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