github.com/mad-app/mattermost-server@v5.11.1+incompatible/api4/command.go (about)

     1  // Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
     2  // See License.txt for license information.
     3  
     4  package api4
     5  
     6  import (
     7  	"net/http"
     8  	"strconv"
     9  	"strings"
    10  
    11  	"github.com/mattermost/mattermost-server/model"
    12  )
    13  
    14  func (api *API) InitCommand() {
    15  	api.BaseRoutes.Commands.Handle("", api.ApiSessionRequired(createCommand)).Methods("POST")
    16  	api.BaseRoutes.Commands.Handle("", api.ApiSessionRequired(listCommands)).Methods("GET")
    17  	api.BaseRoutes.Commands.Handle("/execute", api.ApiSessionRequired(executeCommand)).Methods("POST")
    18  
    19  	api.BaseRoutes.Command.Handle("", api.ApiSessionRequired(updateCommand)).Methods("PUT")
    20  	api.BaseRoutes.Command.Handle("", api.ApiSessionRequired(deleteCommand)).Methods("DELETE")
    21  
    22  	api.BaseRoutes.Team.Handle("/commands/autocomplete", api.ApiSessionRequired(listAutocompleteCommands)).Methods("GET")
    23  	api.BaseRoutes.Command.Handle("/regen_token", api.ApiSessionRequired(regenCommandToken)).Methods("PUT")
    24  }
    25  
    26  func createCommand(c *Context, w http.ResponseWriter, r *http.Request) {
    27  	cmd := model.CommandFromJson(r.Body)
    28  	if cmd == nil {
    29  		c.SetInvalidParam("command")
    30  		return
    31  	}
    32  
    33  	c.LogAudit("attempt")
    34  
    35  	if !c.App.SessionHasPermissionToTeam(c.App.Session, cmd.TeamId, model.PERMISSION_MANAGE_SLASH_COMMANDS) {
    36  		c.SetPermissionError(model.PERMISSION_MANAGE_SLASH_COMMANDS)
    37  		return
    38  	}
    39  
    40  	cmd.CreatorId = c.App.Session.UserId
    41  
    42  	rcmd, err := c.App.CreateCommand(cmd)
    43  	if err != nil {
    44  		c.Err = err
    45  		return
    46  	}
    47  
    48  	c.LogAudit("success")
    49  	w.WriteHeader(http.StatusCreated)
    50  	w.Write([]byte(rcmd.ToJson()))
    51  }
    52  
    53  func updateCommand(c *Context, w http.ResponseWriter, r *http.Request) {
    54  	c.RequireCommandId()
    55  	if c.Err != nil {
    56  		return
    57  	}
    58  
    59  	cmd := model.CommandFromJson(r.Body)
    60  	if cmd == nil || cmd.Id != c.Params.CommandId {
    61  		c.SetInvalidParam("command")
    62  		return
    63  	}
    64  
    65  	c.LogAudit("attempt")
    66  
    67  	oldCmd, err := c.App.GetCommand(c.Params.CommandId)
    68  	if err != nil {
    69  		c.Err = err
    70  		return
    71  	}
    72  
    73  	if cmd.TeamId != oldCmd.TeamId {
    74  		c.Err = model.NewAppError("updateCommand", "api.command.team_mismatch.app_error", nil, "user_id="+c.App.Session.UserId, http.StatusBadRequest)
    75  		return
    76  	}
    77  
    78  	if !c.App.SessionHasPermissionToTeam(c.App.Session, oldCmd.TeamId, model.PERMISSION_MANAGE_SLASH_COMMANDS) {
    79  		c.LogAudit("fail - inappropriate permissions")
    80  		c.SetPermissionError(model.PERMISSION_MANAGE_SLASH_COMMANDS)
    81  		return
    82  	}
    83  
    84  	if c.App.Session.UserId != oldCmd.CreatorId && !c.App.SessionHasPermissionToTeam(c.App.Session, oldCmd.TeamId, model.PERMISSION_MANAGE_OTHERS_SLASH_COMMANDS) {
    85  		c.LogAudit("fail - inappropriate permissions")
    86  		c.SetPermissionError(model.PERMISSION_MANAGE_OTHERS_SLASH_COMMANDS)
    87  		return
    88  	}
    89  
    90  	rcmd, err := c.App.UpdateCommand(oldCmd, cmd)
    91  	if err != nil {
    92  		c.Err = err
    93  		return
    94  	}
    95  
    96  	c.LogAudit("success")
    97  
    98  	w.Write([]byte(rcmd.ToJson()))
    99  }
   100  
   101  func deleteCommand(c *Context, w http.ResponseWriter, r *http.Request) {
   102  	c.RequireCommandId()
   103  	if c.Err != nil {
   104  		return
   105  	}
   106  
   107  	c.LogAudit("attempt")
   108  
   109  	cmd, err := c.App.GetCommand(c.Params.CommandId)
   110  	if err != nil {
   111  		c.Err = err
   112  		return
   113  	}
   114  
   115  	if !c.App.SessionHasPermissionToTeam(c.App.Session, cmd.TeamId, model.PERMISSION_MANAGE_SLASH_COMMANDS) {
   116  		c.LogAudit("fail - inappropriate permissions")
   117  		c.SetPermissionError(model.PERMISSION_MANAGE_SLASH_COMMANDS)
   118  		return
   119  	}
   120  
   121  	if c.App.Session.UserId != cmd.CreatorId && !c.App.SessionHasPermissionToTeam(c.App.Session, cmd.TeamId, model.PERMISSION_MANAGE_OTHERS_SLASH_COMMANDS) {
   122  		c.LogAudit("fail - inappropriate permissions")
   123  		c.SetPermissionError(model.PERMISSION_MANAGE_OTHERS_SLASH_COMMANDS)
   124  		return
   125  	}
   126  
   127  	err = c.App.DeleteCommand(cmd.Id)
   128  	if err != nil {
   129  		c.Err = err
   130  		return
   131  	}
   132  
   133  	c.LogAudit("success")
   134  
   135  	ReturnStatusOK(w)
   136  }
   137  
   138  func listCommands(c *Context, w http.ResponseWriter, r *http.Request) {
   139  	customOnly, failConv := strconv.ParseBool(r.URL.Query().Get("custom_only"))
   140  	if failConv != nil {
   141  		customOnly = false
   142  	}
   143  
   144  	teamId := r.URL.Query().Get("team_id")
   145  
   146  	if len(teamId) == 0 {
   147  		c.SetInvalidParam("team_id")
   148  		return
   149  	}
   150  
   151  	var commands []*model.Command
   152  	var err *model.AppError
   153  	if customOnly {
   154  		if !c.App.SessionHasPermissionToTeam(c.App.Session, teamId, model.PERMISSION_MANAGE_SLASH_COMMANDS) {
   155  			c.SetPermissionError(model.PERMISSION_MANAGE_SLASH_COMMANDS)
   156  			return
   157  		}
   158  		commands, err = c.App.ListTeamCommands(teamId)
   159  		if err != nil {
   160  			c.Err = err
   161  			return
   162  		}
   163  	} else {
   164  		//User with no permission should see only system commands
   165  		if !c.App.SessionHasPermissionToTeam(c.App.Session, teamId, model.PERMISSION_MANAGE_SLASH_COMMANDS) {
   166  			commands, err = c.App.ListAutocompleteCommands(teamId, c.App.T)
   167  			if err != nil {
   168  				c.Err = err
   169  				return
   170  			}
   171  		} else {
   172  			commands, err = c.App.ListAllCommands(teamId, c.App.T)
   173  			if err != nil {
   174  				c.Err = err
   175  				return
   176  			}
   177  		}
   178  	}
   179  
   180  	w.Write([]byte(model.CommandListToJson(commands)))
   181  }
   182  
   183  func executeCommand(c *Context, w http.ResponseWriter, r *http.Request) {
   184  	commandArgs := model.CommandArgsFromJson(r.Body)
   185  	if commandArgs == nil {
   186  		c.SetInvalidParam("command_args")
   187  		return
   188  	}
   189  
   190  	if len(commandArgs.Command) <= 1 || strings.Index(commandArgs.Command, "/") != 0 || len(commandArgs.ChannelId) != 26 {
   191  		c.Err = model.NewAppError("executeCommand", "api.command.execute_command.start.app_error", nil, "", http.StatusBadRequest)
   192  		return
   193  	}
   194  
   195  	// checks that user is a member of the specified channel, and that they have permission to use slash commands in it
   196  	if !c.App.SessionHasPermissionToChannel(c.App.Session, commandArgs.ChannelId, model.PERMISSION_USE_SLASH_COMMANDS) {
   197  		c.SetPermissionError(model.PERMISSION_USE_SLASH_COMMANDS)
   198  		return
   199  	}
   200  
   201  	channel, err := c.App.GetChannel(commandArgs.ChannelId)
   202  	if err != nil {
   203  		c.Err = err
   204  		return
   205  	}
   206  
   207  	if channel.Type != model.CHANNEL_DIRECT && channel.Type != model.CHANNEL_GROUP {
   208  		// if this isn't a DM or GM, the team id is implicitly taken from the channel so that slash commands created on
   209  		// some other team can't be run against this one
   210  		commandArgs.TeamId = channel.TeamId
   211  	} else {
   212  		// if the slash command was used in a DM or GM, ensure that the user is a member of the specified team, so that
   213  		// they can't just execute slash commands against arbitrary teams
   214  		if c.App.Session.GetTeamByTeamId(commandArgs.TeamId) == nil {
   215  			if !c.App.SessionHasPermissionTo(c.App.Session, model.PERMISSION_USE_SLASH_COMMANDS) {
   216  				c.SetPermissionError(model.PERMISSION_USE_SLASH_COMMANDS)
   217  				return
   218  			}
   219  		}
   220  	}
   221  
   222  	commandArgs.UserId = c.App.Session.UserId
   223  	commandArgs.T = c.App.T
   224  	commandArgs.Session = c.App.Session
   225  	commandArgs.SiteURL = c.GetSiteURLHeader()
   226  
   227  	response, err := c.App.ExecuteCommand(commandArgs)
   228  	if err != nil {
   229  		c.Err = err
   230  		return
   231  	}
   232  
   233  	w.Write([]byte(response.ToJson()))
   234  }
   235  
   236  func listAutocompleteCommands(c *Context, w http.ResponseWriter, r *http.Request) {
   237  	c.RequireTeamId()
   238  	if c.Err != nil {
   239  		return
   240  	}
   241  
   242  	if !c.App.SessionHasPermissionToTeam(c.App.Session, c.Params.TeamId, model.PERMISSION_VIEW_TEAM) {
   243  		c.SetPermissionError(model.PERMISSION_VIEW_TEAM)
   244  		return
   245  	}
   246  
   247  	commands, err := c.App.ListAutocompleteCommands(c.Params.TeamId, c.App.T)
   248  	if err != nil {
   249  		c.Err = err
   250  		return
   251  	}
   252  
   253  	w.Write([]byte(model.CommandListToJson(commands)))
   254  }
   255  
   256  func regenCommandToken(c *Context, w http.ResponseWriter, r *http.Request) {
   257  	c.RequireCommandId()
   258  	if c.Err != nil {
   259  		return
   260  	}
   261  
   262  	c.LogAudit("attempt")
   263  	cmd, err := c.App.GetCommand(c.Params.CommandId)
   264  	if err != nil {
   265  		c.Err = err
   266  		return
   267  	}
   268  
   269  	if !c.App.SessionHasPermissionToTeam(c.App.Session, cmd.TeamId, model.PERMISSION_MANAGE_SLASH_COMMANDS) {
   270  		c.LogAudit("fail - inappropriate permissions")
   271  		c.SetPermissionError(model.PERMISSION_MANAGE_SLASH_COMMANDS)
   272  		return
   273  	}
   274  
   275  	if c.App.Session.UserId != cmd.CreatorId && !c.App.SessionHasPermissionToTeam(c.App.Session, cmd.TeamId, model.PERMISSION_MANAGE_OTHERS_SLASH_COMMANDS) {
   276  		c.LogAudit("fail - inappropriate permissions")
   277  		c.SetPermissionError(model.PERMISSION_MANAGE_OTHERS_SLASH_COMMANDS)
   278  		return
   279  	}
   280  
   281  	rcmd, err := c.App.RegenCommandToken(cmd)
   282  	if err != nil {
   283  		c.Err = err
   284  		return
   285  	}
   286  
   287  	resp := make(map[string]string)
   288  	resp["token"] = rcmd.Token
   289  
   290  	w.Write([]byte(model.MapToJson(resp)))
   291  }