github.com/bensooraj/mattermost-server@v5.11.1+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  		// Bots are exempt
   129  		if user.IsBot {
   130  			return
   131  		}
   132  
   133  		if !user.MfaActive {
   134  			c.Err = model.NewAppError("", "api.context.mfa_required.app_error", nil, "MfaRequired", http.StatusForbidden)
   135  			return
   136  		}
   137  	}
   138  }
   139  
   140  func (c *Context) RemoveSessionCookie(w http.ResponseWriter, r *http.Request) {
   141  	cookie := &http.Cookie{
   142  		Name:     model.SESSION_COOKIE_TOKEN,
   143  		Value:    "",
   144  		Path:     "/",
   145  		MaxAge:   -1,
   146  		HttpOnly: true,
   147  	}
   148  
   149  	http.SetCookie(w, cookie)
   150  }
   151  
   152  func (c *Context) SetInvalidParam(parameter string) {
   153  	c.Err = NewInvalidParamError(parameter)
   154  }
   155  
   156  func (c *Context) SetInvalidUrlParam(parameter string) {
   157  	c.Err = NewInvalidUrlParamError(parameter)
   158  }
   159  
   160  func (c *Context) HandleEtag(etag string, routeName string, w http.ResponseWriter, r *http.Request) bool {
   161  	metrics := c.App.Metrics
   162  	if et := r.Header.Get(model.HEADER_ETAG_CLIENT); len(etag) > 0 {
   163  		if et == etag {
   164  			w.Header().Set(model.HEADER_ETAG_SERVER, etag)
   165  			w.WriteHeader(http.StatusNotModified)
   166  			if metrics != nil {
   167  				metrics.IncrementEtagHitCounter(routeName)
   168  			}
   169  			return true
   170  		}
   171  	}
   172  
   173  	if metrics != nil {
   174  		metrics.IncrementEtagMissCounter(routeName)
   175  	}
   176  
   177  	return false
   178  }
   179  
   180  func NewInvalidParamError(parameter string) *model.AppError {
   181  	err := model.NewAppError("Context", "api.context.invalid_body_param.app_error", map[string]interface{}{"Name": parameter}, "", http.StatusBadRequest)
   182  	return err
   183  }
   184  func NewInvalidUrlParamError(parameter string) *model.AppError {
   185  	err := model.NewAppError("Context", "api.context.invalid_url_param.app_error", map[string]interface{}{"Name": parameter}, "", http.StatusBadRequest)
   186  	return err
   187  }
   188  
   189  func (c *Context) SetPermissionError(permission *model.Permission) {
   190  	c.Err = c.App.MakePermissionError(permission)
   191  }
   192  
   193  func (c *Context) SetSiteURLHeader(url string) {
   194  	c.siteURLHeader = strings.TrimRight(url, "/")
   195  }
   196  
   197  func (c *Context) GetSiteURLHeader() string {
   198  	return c.siteURLHeader
   199  }
   200  
   201  func (c *Context) RequireUserId() *Context {
   202  	if c.Err != nil {
   203  		return c
   204  	}
   205  
   206  	if c.Params.UserId == model.ME {
   207  		c.Params.UserId = c.App.Session.UserId
   208  	}
   209  
   210  	if len(c.Params.UserId) != 26 {
   211  		c.SetInvalidUrlParam("user_id")
   212  	}
   213  	return c
   214  }
   215  
   216  func (c *Context) RequireTeamId() *Context {
   217  	if c.Err != nil {
   218  		return c
   219  	}
   220  
   221  	if len(c.Params.TeamId) != 26 {
   222  		c.SetInvalidUrlParam("team_id")
   223  	}
   224  	return c
   225  }
   226  
   227  func (c *Context) RequireInviteId() *Context {
   228  	if c.Err != nil {
   229  		return c
   230  	}
   231  
   232  	if len(c.Params.InviteId) == 0 {
   233  		c.SetInvalidUrlParam("invite_id")
   234  	}
   235  	return c
   236  }
   237  
   238  func (c *Context) RequireTokenId() *Context {
   239  	if c.Err != nil {
   240  		return c
   241  	}
   242  
   243  	if len(c.Params.TokenId) != 26 {
   244  		c.SetInvalidUrlParam("token_id")
   245  	}
   246  	return c
   247  }
   248  
   249  func (c *Context) RequireChannelId() *Context {
   250  	if c.Err != nil {
   251  		return c
   252  	}
   253  
   254  	if len(c.Params.ChannelId) != 26 {
   255  		c.SetInvalidUrlParam("channel_id")
   256  	}
   257  	return c
   258  }
   259  
   260  func (c *Context) RequireUsername() *Context {
   261  	if c.Err != nil {
   262  		return c
   263  	}
   264  
   265  	if !model.IsValidUsername(c.Params.Username) {
   266  		c.SetInvalidParam("username")
   267  	}
   268  
   269  	return c
   270  }
   271  
   272  func (c *Context) RequirePostId() *Context {
   273  	if c.Err != nil {
   274  		return c
   275  	}
   276  
   277  	if len(c.Params.PostId) != 26 {
   278  		c.SetInvalidUrlParam("post_id")
   279  	}
   280  	return c
   281  }
   282  
   283  func (c *Context) RequireAppId() *Context {
   284  	if c.Err != nil {
   285  		return c
   286  	}
   287  
   288  	if len(c.Params.AppId) != 26 {
   289  		c.SetInvalidUrlParam("app_id")
   290  	}
   291  	return c
   292  }
   293  
   294  func (c *Context) RequireFileId() *Context {
   295  	if c.Err != nil {
   296  		return c
   297  	}
   298  
   299  	if len(c.Params.FileId) != 26 {
   300  		c.SetInvalidUrlParam("file_id")
   301  	}
   302  
   303  	return c
   304  }
   305  
   306  func (c *Context) RequireFilename() *Context {
   307  	if c.Err != nil {
   308  		return c
   309  	}
   310  
   311  	if len(c.Params.Filename) == 0 {
   312  		c.SetInvalidUrlParam("filename")
   313  	}
   314  
   315  	return c
   316  }
   317  
   318  func (c *Context) RequirePluginId() *Context {
   319  	if c.Err != nil {
   320  		return c
   321  	}
   322  
   323  	if len(c.Params.PluginId) == 0 {
   324  		c.SetInvalidUrlParam("plugin_id")
   325  	}
   326  
   327  	return c
   328  }
   329  
   330  func (c *Context) RequireReportId() *Context {
   331  	if c.Err != nil {
   332  		return c
   333  	}
   334  
   335  	if len(c.Params.ReportId) != 26 {
   336  		c.SetInvalidUrlParam("report_id")
   337  	}
   338  	return c
   339  }
   340  
   341  func (c *Context) RequireEmojiId() *Context {
   342  	if c.Err != nil {
   343  		return c
   344  	}
   345  
   346  	if len(c.Params.EmojiId) != 26 {
   347  		c.SetInvalidUrlParam("emoji_id")
   348  	}
   349  	return c
   350  }
   351  
   352  func (c *Context) RequireTeamName() *Context {
   353  	if c.Err != nil {
   354  		return c
   355  	}
   356  
   357  	if !model.IsValidTeamName(c.Params.TeamName) {
   358  		c.SetInvalidUrlParam("team_name")
   359  	}
   360  
   361  	return c
   362  }
   363  
   364  func (c *Context) RequireChannelName() *Context {
   365  	if c.Err != nil {
   366  		return c
   367  	}
   368  
   369  	if !model.IsValidChannelIdentifier(c.Params.ChannelName) {
   370  		c.SetInvalidUrlParam("channel_name")
   371  	}
   372  
   373  	return c
   374  }
   375  
   376  func (c *Context) RequireEmail() *Context {
   377  	if c.Err != nil {
   378  		return c
   379  	}
   380  
   381  	if !model.IsValidEmail(c.Params.Email) {
   382  		c.SetInvalidUrlParam("email")
   383  	}
   384  
   385  	return c
   386  }
   387  
   388  func (c *Context) RequireCategory() *Context {
   389  	if c.Err != nil {
   390  		return c
   391  	}
   392  
   393  	if !model.IsValidAlphaNumHyphenUnderscore(c.Params.Category, true) {
   394  		c.SetInvalidUrlParam("category")
   395  	}
   396  
   397  	return c
   398  }
   399  
   400  func (c *Context) RequireService() *Context {
   401  	if c.Err != nil {
   402  		return c
   403  	}
   404  
   405  	if len(c.Params.Service) == 0 {
   406  		c.SetInvalidUrlParam("service")
   407  	}
   408  
   409  	return c
   410  }
   411  
   412  func (c *Context) RequirePreferenceName() *Context {
   413  	if c.Err != nil {
   414  		return c
   415  	}
   416  
   417  	if !model.IsValidAlphaNumHyphenUnderscore(c.Params.PreferenceName, true) {
   418  		c.SetInvalidUrlParam("preference_name")
   419  	}
   420  
   421  	return c
   422  }
   423  
   424  func (c *Context) RequireEmojiName() *Context {
   425  	if c.Err != nil {
   426  		return c
   427  	}
   428  
   429  	validName := regexp.MustCompile(`^[a-zA-Z0-9\-\+_]+$`)
   430  
   431  	if len(c.Params.EmojiName) == 0 || len(c.Params.EmojiName) > model.EMOJI_NAME_MAX_LENGTH || !validName.MatchString(c.Params.EmojiName) {
   432  		c.SetInvalidUrlParam("emoji_name")
   433  	}
   434  
   435  	return c
   436  }
   437  
   438  func (c *Context) RequireHookId() *Context {
   439  	if c.Err != nil {
   440  		return c
   441  	}
   442  
   443  	if len(c.Params.HookId) != 26 {
   444  		c.SetInvalidUrlParam("hook_id")
   445  	}
   446  
   447  	return c
   448  }
   449  
   450  func (c *Context) RequireCommandId() *Context {
   451  	if c.Err != nil {
   452  		return c
   453  	}
   454  
   455  	if len(c.Params.CommandId) != 26 {
   456  		c.SetInvalidUrlParam("command_id")
   457  	}
   458  	return c
   459  }
   460  
   461  func (c *Context) RequireJobId() *Context {
   462  	if c.Err != nil {
   463  		return c
   464  	}
   465  
   466  	if len(c.Params.JobId) != 26 {
   467  		c.SetInvalidUrlParam("job_id")
   468  	}
   469  	return c
   470  }
   471  
   472  func (c *Context) RequireJobType() *Context {
   473  	if c.Err != nil {
   474  		return c
   475  	}
   476  
   477  	if len(c.Params.JobType) == 0 || len(c.Params.JobType) > 32 {
   478  		c.SetInvalidUrlParam("job_type")
   479  	}
   480  	return c
   481  }
   482  
   483  func (c *Context) RequireActionId() *Context {
   484  	if c.Err != nil {
   485  		return c
   486  	}
   487  
   488  	if len(c.Params.ActionId) != 26 {
   489  		c.SetInvalidUrlParam("action_id")
   490  	}
   491  	return c
   492  }
   493  
   494  func (c *Context) RequireRoleId() *Context {
   495  	if c.Err != nil {
   496  		return c
   497  	}
   498  
   499  	if len(c.Params.RoleId) != 26 {
   500  		c.SetInvalidUrlParam("role_id")
   501  	}
   502  	return c
   503  }
   504  
   505  func (c *Context) RequireSchemeId() *Context {
   506  	if c.Err != nil {
   507  		return c
   508  	}
   509  
   510  	if len(c.Params.SchemeId) != 26 {
   511  		c.SetInvalidUrlParam("scheme_id")
   512  	}
   513  	return c
   514  }
   515  
   516  func (c *Context) RequireRoleName() *Context {
   517  	if c.Err != nil {
   518  		return c
   519  	}
   520  
   521  	if !model.IsValidRoleName(c.Params.RoleName) {
   522  		c.SetInvalidUrlParam("role_name")
   523  	}
   524  
   525  	return c
   526  }
   527  
   528  func (c *Context) RequireGroupId() *Context {
   529  	if c.Err != nil {
   530  		return c
   531  	}
   532  
   533  	if len(c.Params.GroupId) != 26 {
   534  		c.SetInvalidUrlParam("group_id")
   535  	}
   536  	return c
   537  }
   538  
   539  func (c *Context) RequireRemoteId() *Context {
   540  	if c.Err != nil {
   541  		return c
   542  	}
   543  
   544  	if len(c.Params.RemoteId) == 0 {
   545  		c.SetInvalidUrlParam("remote_id")
   546  	}
   547  	return c
   548  }
   549  
   550  func (c *Context) RequireSyncableId() *Context {
   551  	if c.Err != nil {
   552  		return c
   553  	}
   554  
   555  	if len(c.Params.SyncableId) != 26 {
   556  		c.SetInvalidUrlParam("syncable_id")
   557  	}
   558  	return c
   559  }
   560  
   561  func (c *Context) RequireSyncableType() *Context {
   562  	if c.Err != nil {
   563  		return c
   564  	}
   565  
   566  	if c.Params.SyncableType != model.GroupSyncableTypeTeam && c.Params.SyncableType != model.GroupSyncableTypeChannel {
   567  		c.SetInvalidUrlParam("syncable_type")
   568  	}
   569  	return c
   570  }
   571  
   572  func (c *Context) RequireBotUserId() *Context {
   573  	if c.Err != nil {
   574  		return c
   575  	}
   576  
   577  	if len(c.Params.BotUserId) != 26 {
   578  		c.SetInvalidUrlParam("bot_user_id")
   579  	}
   580  	return c
   581  }