github.com/qichengzx/mattermost-server@v4.5.1-0.20180604164826-2c75247c97d0+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  	"regexp"
     9  	"strings"
    10  
    11  	goi18n "github.com/nicksnyder/go-i18n/i18n"
    12  
    13  	"github.com/mattermost/mattermost-server/app"
    14  	"github.com/mattermost/mattermost-server/mlog"
    15  	"github.com/mattermost/mattermost-server/model"
    16  	"github.com/mattermost/mattermost-server/utils"
    17  )
    18  
    19  type Context struct {
    20  	App           *app.App
    21  	Log           *mlog.Logger
    22  	Session       model.Session
    23  	Params        *Params
    24  	Err           *model.AppError
    25  	T             goi18n.TranslateFunc
    26  	RequestId     string
    27  	IpAddress     string
    28  	Path          string
    29  	siteURLHeader string
    30  }
    31  
    32  func (c *Context) LogAudit(extraInfo string) {
    33  	audit := &model.Audit{UserId: c.Session.UserId, IpAddress: c.IpAddress, Action: c.Path, ExtraInfo: extraInfo, SessionId: c.Session.Id}
    34  	if r := <-c.App.Srv.Store.Audit().Save(audit); r.Err != nil {
    35  		c.LogError(r.Err)
    36  	}
    37  }
    38  
    39  func (c *Context) LogAuditWithUserId(userId, extraInfo string) {
    40  
    41  	if len(c.Session.UserId) > 0 {
    42  		extraInfo = strings.TrimSpace(extraInfo + " session_user=" + c.Session.UserId)
    43  	}
    44  
    45  	audit := &model.Audit{UserId: userId, IpAddress: c.IpAddress, Action: c.Path, ExtraInfo: extraInfo, SessionId: c.Session.Id}
    46  	if r := <-c.App.Srv.Store.Audit().Save(audit); r.Err != nil {
    47  		c.LogError(r.Err)
    48  	}
    49  }
    50  
    51  func (c *Context) LogError(err *model.AppError) {
    52  	// Filter out 404s, endless reconnects and browser compatibility errors
    53  	if err.StatusCode == http.StatusNotFound ||
    54  		(c.Path == "/api/v3/users/websocket" && err.StatusCode == http.StatusUnauthorized) ||
    55  		err.Id == "web.check_browser_compatibility.app_error" {
    56  		c.LogDebug(err)
    57  	} else {
    58  		c.Log.Error(
    59  			err.SystemMessage(utils.TDefault),
    60  			mlog.String("err_where", err.Where),
    61  			mlog.Int("http_code", err.StatusCode),
    62  			mlog.String("err_details", err.DetailedError),
    63  		)
    64  	}
    65  }
    66  
    67  func (c *Context) LogInfo(err *model.AppError) {
    68  	// Filter out 401s
    69  	if err.StatusCode == http.StatusUnauthorized {
    70  		c.LogDebug(err)
    71  	} else {
    72  		c.Log.Info(
    73  			err.SystemMessage(utils.TDefault),
    74  			mlog.String("err_where", err.Where),
    75  			mlog.Int("http_code", err.StatusCode),
    76  			mlog.String("err_details", err.DetailedError),
    77  		)
    78  	}
    79  }
    80  
    81  func (c *Context) LogDebug(err *model.AppError) {
    82  	c.Log.Debug(
    83  		err.SystemMessage(utils.TDefault),
    84  		mlog.String("err_where", err.Where),
    85  		mlog.Int("http_code", err.StatusCode),
    86  		mlog.String("err_details", err.DetailedError),
    87  	)
    88  }
    89  
    90  func (c *Context) IsSystemAdmin() bool {
    91  	return c.App.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_SYSTEM)
    92  }
    93  
    94  func (c *Context) SessionRequired() {
    95  	if !*c.App.Config().ServiceSettings.EnableUserAccessTokens && c.Session.Props[model.SESSION_PROP_TYPE] == model.SESSION_TYPE_USER_ACCESS_TOKEN {
    96  		c.Err = model.NewAppError("", "api.context.session_expired.app_error", nil, "UserAccessToken", http.StatusUnauthorized)
    97  		return
    98  	}
    99  
   100  	if len(c.Session.UserId) == 0 {
   101  		c.Err = model.NewAppError("", "api.context.session_expired.app_error", nil, "UserRequired", http.StatusUnauthorized)
   102  		return
   103  	}
   104  }
   105  
   106  func (c *Context) MfaRequired() {
   107  	// Must be licensed for MFA and have it configured for enforcement
   108  	if license := c.App.License(); license == nil || !*license.Features.MFA || !*c.App.Config().ServiceSettings.EnableMultifactorAuthentication || !*c.App.Config().ServiceSettings.EnforceMultifactorAuthentication {
   109  		return
   110  	}
   111  
   112  	// OAuth integrations are excepted
   113  	if c.Session.IsOAuth {
   114  		return
   115  	}
   116  
   117  	if user, err := c.App.GetUser(c.Session.UserId); err != nil {
   118  		c.Err = model.NewAppError("", "api.context.session_expired.app_error", nil, "MfaRequired", http.StatusUnauthorized)
   119  		return
   120  	} else {
   121  		// Only required for email and ldap accounts
   122  		if user.AuthService != "" &&
   123  			user.AuthService != model.USER_AUTH_SERVICE_EMAIL &&
   124  			user.AuthService != model.USER_AUTH_SERVICE_LDAP {
   125  			return
   126  		}
   127  
   128  		// Special case to let user get themself
   129  		if c.Path == "/api/v4/users/me" {
   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 = model.NewAppError("Permissions", "api.context.permissions.app_error", nil, "userId="+c.Session.UserId+", "+"permission="+permission.Id, http.StatusForbidden)
   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.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  }