github.com/qichengzx/mattermost-server@v4.5.1-0.20180604164826-2c75247c97d0+incompatible/api4/command_test.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  	"fmt"
     8  	"net/http"
     9  	"net/http/httptest"
    10  	"net/url"
    11  	"testing"
    12  
    13  	"github.com/stretchr/testify/require"
    14  
    15  	"github.com/mattermost/mattermost-server/model"
    16  )
    17  
    18  func TestCreateCommand(t *testing.T) {
    19  	th := Setup().InitBasic().InitSystemAdmin()
    20  	defer th.TearDown()
    21  	Client := th.Client
    22  
    23  	enableCommands := *th.App.Config().ServiceSettings.EnableCommands
    24  	defer func() {
    25  		th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableCommands = &enableCommands })
    26  	}()
    27  	th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableCommands = true })
    28  
    29  	newCmd := &model.Command{
    30  		CreatorId: th.BasicUser.Id,
    31  		TeamId:    th.BasicTeam.Id,
    32  		URL:       "http://nowhere.com",
    33  		Method:    model.COMMAND_METHOD_POST,
    34  		Trigger:   "trigger"}
    35  
    36  	_, resp := Client.CreateCommand(newCmd)
    37  	CheckForbiddenStatus(t, resp)
    38  
    39  	createdCmd, resp := th.SystemAdminClient.CreateCommand(newCmd)
    40  	CheckNoError(t, resp)
    41  	CheckCreatedStatus(t, resp)
    42  	if createdCmd.CreatorId != th.SystemAdminUser.Id {
    43  		t.Fatal("user ids didn't match")
    44  	}
    45  	if createdCmd.TeamId != th.BasicTeam.Id {
    46  		t.Fatal("team ids didn't match")
    47  	}
    48  
    49  	_, resp = th.SystemAdminClient.CreateCommand(newCmd)
    50  	CheckBadRequestStatus(t, resp)
    51  	CheckErrorMessage(t, resp, "api.command.duplicate_trigger.app_error")
    52  
    53  	newCmd.Method = "Wrong"
    54  	newCmd.Trigger = "testcommand"
    55  	_, resp = th.SystemAdminClient.CreateCommand(newCmd)
    56  	CheckBadRequestStatus(t, resp)
    57  	CheckErrorMessage(t, resp, "model.command.is_valid.method.app_error")
    58  
    59  	th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableCommands = false })
    60  	newCmd.Method = "P"
    61  	newCmd.Trigger = "testcommand"
    62  	_, resp = th.SystemAdminClient.CreateCommand(newCmd)
    63  	CheckNotImplementedStatus(t, resp)
    64  	CheckErrorMessage(t, resp, "api.command.disabled.app_error")
    65  }
    66  
    67  func TestUpdateCommand(t *testing.T) {
    68  	th := Setup().InitBasic().InitSystemAdmin()
    69  	defer th.TearDown()
    70  	Client := th.SystemAdminClient
    71  	user := th.SystemAdminUser
    72  	team := th.BasicTeam
    73  
    74  	enableCommands := *th.App.Config().ServiceSettings.EnableCommands
    75  	defer func() {
    76  		th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableCommands = &enableCommands })
    77  	}()
    78  	th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableCommands = true })
    79  
    80  	cmd1 := &model.Command{
    81  		CreatorId: user.Id,
    82  		TeamId:    team.Id,
    83  		URL:       "http://nowhere.com",
    84  		Method:    model.COMMAND_METHOD_POST,
    85  		Trigger:   "trigger1",
    86  	}
    87  
    88  	cmd1, _ = th.App.CreateCommand(cmd1)
    89  
    90  	cmd2 := &model.Command{
    91  		CreatorId: GenerateTestId(),
    92  		TeamId:    team.Id,
    93  		URL:       "http://nowhere.com/change",
    94  		Method:    model.COMMAND_METHOD_GET,
    95  		Trigger:   "trigger2",
    96  		Id:        cmd1.Id,
    97  		Token:     "tokenchange",
    98  	}
    99  
   100  	rcmd, resp := Client.UpdateCommand(cmd2)
   101  	CheckNoError(t, resp)
   102  
   103  	if rcmd.Trigger != cmd2.Trigger {
   104  		t.Fatal("Trigger should have updated")
   105  	}
   106  
   107  	if rcmd.Method != cmd2.Method {
   108  		t.Fatal("Method should have updated")
   109  	}
   110  
   111  	if rcmd.URL != cmd2.URL {
   112  		t.Fatal("URL should have updated")
   113  	}
   114  
   115  	if rcmd.CreatorId != cmd1.CreatorId {
   116  		t.Fatal("CreatorId should have not updated")
   117  	}
   118  
   119  	if rcmd.Token != cmd1.Token {
   120  		t.Fatal("Token should have not updated")
   121  	}
   122  
   123  	cmd2.Id = GenerateTestId()
   124  
   125  	rcmd, resp = Client.UpdateCommand(cmd2)
   126  	CheckNotFoundStatus(t, resp)
   127  
   128  	if rcmd != nil {
   129  		t.Fatal("should be empty")
   130  	}
   131  
   132  	cmd2.Id = "junk"
   133  
   134  	_, resp = Client.UpdateCommand(cmd2)
   135  	CheckBadRequestStatus(t, resp)
   136  
   137  	cmd2.Id = cmd1.Id
   138  	cmd2.TeamId = GenerateTestId()
   139  
   140  	_, resp = Client.UpdateCommand(cmd2)
   141  	CheckBadRequestStatus(t, resp)
   142  
   143  	cmd2.TeamId = team.Id
   144  
   145  	_, resp = th.Client.UpdateCommand(cmd2)
   146  	CheckForbiddenStatus(t, resp)
   147  
   148  	Client.Logout()
   149  	_, resp = Client.UpdateCommand(cmd2)
   150  	CheckUnauthorizedStatus(t, resp)
   151  }
   152  
   153  func TestDeleteCommand(t *testing.T) {
   154  	th := Setup().InitBasic().InitSystemAdmin()
   155  	defer th.TearDown()
   156  	Client := th.SystemAdminClient
   157  	user := th.SystemAdminUser
   158  	team := th.BasicTeam
   159  
   160  	enableCommands := *th.App.Config().ServiceSettings.EnableCommands
   161  	defer func() {
   162  		th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableCommands = &enableCommands })
   163  	}()
   164  	th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableCommands = true })
   165  
   166  	cmd1 := &model.Command{
   167  		CreatorId: user.Id,
   168  		TeamId:    team.Id,
   169  		URL:       "http://nowhere.com",
   170  		Method:    model.COMMAND_METHOD_POST,
   171  		Trigger:   "trigger1",
   172  	}
   173  
   174  	rcmd1, _ := th.App.CreateCommand(cmd1)
   175  
   176  	ok, resp := Client.DeleteCommand(rcmd1.Id)
   177  	CheckNoError(t, resp)
   178  
   179  	if !ok {
   180  		t.Fatal("should have returned true")
   181  	}
   182  
   183  	rcmd1, _ = th.App.GetCommand(rcmd1.Id)
   184  	if rcmd1 != nil {
   185  		t.Fatal("should be nil")
   186  	}
   187  
   188  	ok, resp = Client.DeleteCommand("junk")
   189  	CheckBadRequestStatus(t, resp)
   190  
   191  	if ok {
   192  		t.Fatal("should have returned false")
   193  	}
   194  
   195  	_, resp = Client.DeleteCommand(GenerateTestId())
   196  	CheckNotFoundStatus(t, resp)
   197  
   198  	cmd2 := &model.Command{
   199  		CreatorId: user.Id,
   200  		TeamId:    team.Id,
   201  		URL:       "http://nowhere.com",
   202  		Method:    model.COMMAND_METHOD_POST,
   203  		Trigger:   "trigger2",
   204  	}
   205  
   206  	rcmd2, _ := th.App.CreateCommand(cmd2)
   207  
   208  	_, resp = th.Client.DeleteCommand(rcmd2.Id)
   209  	CheckForbiddenStatus(t, resp)
   210  
   211  	Client.Logout()
   212  	_, resp = Client.DeleteCommand(rcmd2.Id)
   213  	CheckUnauthorizedStatus(t, resp)
   214  }
   215  
   216  func TestListCommands(t *testing.T) {
   217  	th := Setup().InitBasic().InitSystemAdmin()
   218  	defer th.TearDown()
   219  	Client := th.Client
   220  
   221  	enableCommands := *th.App.Config().ServiceSettings.EnableCommands
   222  	enableOnlyAdminIntegrations := *th.App.Config().ServiceSettings.EnableOnlyAdminIntegrations
   223  	defer func() {
   224  		th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableCommands = &enableCommands })
   225  		th.App.UpdateConfig(func(cfg *model.Config) {
   226  			cfg.ServiceSettings.EnableOnlyAdminIntegrations = &enableOnlyAdminIntegrations
   227  		})
   228  	}()
   229  	th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableCommands = true })
   230  	th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableOnlyAdminIntegrations = true })
   231  
   232  	newCmd := &model.Command{
   233  		CreatorId: th.BasicUser.Id,
   234  		TeamId:    th.BasicTeam.Id,
   235  		URL:       "http://nowhere.com",
   236  		Method:    model.COMMAND_METHOD_POST,
   237  		Trigger:   "custom_command"}
   238  
   239  	_, resp := th.SystemAdminClient.CreateCommand(newCmd)
   240  	CheckNoError(t, resp)
   241  
   242  	t.Run("ListSystemAndCustomCommands", func(t *testing.T) {
   243  		listCommands, resp := th.SystemAdminClient.ListCommands(th.BasicTeam.Id, false)
   244  		CheckNoError(t, resp)
   245  
   246  		foundEcho := false
   247  		foundCustom := false
   248  		for _, command := range listCommands {
   249  			if command.Trigger == "echo" {
   250  				foundEcho = true
   251  			}
   252  			if command.Trigger == "custom_command" {
   253  				foundCustom = true
   254  			}
   255  		}
   256  		if !foundEcho {
   257  			t.Fatal("Couldn't find echo command")
   258  		}
   259  		if !foundCustom {
   260  			t.Fatal("Should list the custom command")
   261  		}
   262  	})
   263  
   264  	t.Run("ListCustomOnlyCommands", func(t *testing.T) {
   265  		listCommands, resp := th.SystemAdminClient.ListCommands(th.BasicTeam.Id, true)
   266  		CheckNoError(t, resp)
   267  
   268  		if len(listCommands) > 1 {
   269  			t.Fatal("Should list just one custom command")
   270  		}
   271  		if listCommands[0].Trigger != "custom_command" {
   272  			t.Fatal("Wrong custom command trigger")
   273  		}
   274  	})
   275  
   276  	t.Run("UserWithNoPermissionForCustomCommands", func(t *testing.T) {
   277  		_, resp := Client.ListCommands(th.BasicTeam.Id, true)
   278  		CheckForbiddenStatus(t, resp)
   279  	})
   280  
   281  	t.Run("RegularUserCanListOnlySystemCommands", func(t *testing.T) {
   282  		listCommands, resp := Client.ListCommands(th.BasicTeam.Id, false)
   283  		CheckNoError(t, resp)
   284  
   285  		foundEcho := false
   286  		foundCustom := false
   287  		for _, command := range listCommands {
   288  			if command.Trigger == "echo" {
   289  				foundEcho = true
   290  			}
   291  			if command.Trigger == "custom_command" {
   292  				foundCustom = true
   293  			}
   294  		}
   295  		if !foundEcho {
   296  			t.Fatal("Couldn't find echo command")
   297  		}
   298  		if foundCustom {
   299  			t.Fatal("Should not list the custom command")
   300  		}
   301  	})
   302  }
   303  
   304  func TestListAutocompleteCommands(t *testing.T) {
   305  	th := Setup().InitBasic().InitSystemAdmin()
   306  	defer th.TearDown()
   307  	Client := th.Client
   308  
   309  	newCmd := &model.Command{
   310  		CreatorId: th.BasicUser.Id,
   311  		TeamId:    th.BasicTeam.Id,
   312  		URL:       "http://nowhere.com",
   313  		Method:    model.COMMAND_METHOD_POST,
   314  		Trigger:   "custom_command"}
   315  
   316  	_, resp := th.SystemAdminClient.CreateCommand(newCmd)
   317  	CheckNoError(t, resp)
   318  
   319  	t.Run("ListAutocompleteCommandsOnly", func(t *testing.T) {
   320  		listCommands, resp := th.SystemAdminClient.ListAutocompleteCommands(th.BasicTeam.Id)
   321  		CheckNoError(t, resp)
   322  
   323  		foundEcho := false
   324  		foundCustom := false
   325  		for _, command := range listCommands {
   326  			if command.Trigger == "echo" {
   327  				foundEcho = true
   328  			}
   329  			if command.Trigger == "custom_command" {
   330  				foundCustom = true
   331  			}
   332  		}
   333  		if !foundEcho {
   334  			t.Fatal("Couldn't find echo command")
   335  		}
   336  		if foundCustom {
   337  			t.Fatal("Should not list the custom command")
   338  		}
   339  	})
   340  
   341  	t.Run("RegularUserCanListOnlySystemCommands", func(t *testing.T) {
   342  		listCommands, resp := Client.ListAutocompleteCommands(th.BasicTeam.Id)
   343  		CheckNoError(t, resp)
   344  
   345  		foundEcho := false
   346  		foundCustom := false
   347  		for _, command := range listCommands {
   348  			if command.Trigger == "echo" {
   349  				foundEcho = true
   350  			}
   351  			if command.Trigger == "custom_command" {
   352  				foundCustom = true
   353  			}
   354  		}
   355  		if !foundEcho {
   356  			t.Fatal("Couldn't find echo command")
   357  		}
   358  		if foundCustom {
   359  			t.Fatal("Should not list the custom command")
   360  		}
   361  	})
   362  }
   363  
   364  func TestRegenToken(t *testing.T) {
   365  	th := Setup().InitBasic().InitSystemAdmin()
   366  	defer th.TearDown()
   367  	Client := th.Client
   368  
   369  	enableCommands := *th.App.Config().ServiceSettings.EnableCommands
   370  	defer func() {
   371  		th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableCommands = &enableCommands })
   372  	}()
   373  	th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableCommands = true })
   374  
   375  	newCmd := &model.Command{
   376  		CreatorId: th.BasicUser.Id,
   377  		TeamId:    th.BasicTeam.Id,
   378  		URL:       "http://nowhere.com",
   379  		Method:    model.COMMAND_METHOD_POST,
   380  		Trigger:   "trigger"}
   381  
   382  	createdCmd, resp := th.SystemAdminClient.CreateCommand(newCmd)
   383  	CheckNoError(t, resp)
   384  	CheckCreatedStatus(t, resp)
   385  
   386  	token, resp := th.SystemAdminClient.RegenCommandToken(createdCmd.Id)
   387  	CheckNoError(t, resp)
   388  	if token == createdCmd.Token {
   389  		t.Fatal("should update the token")
   390  	}
   391  
   392  	token, resp = Client.RegenCommandToken(createdCmd.Id)
   393  	CheckForbiddenStatus(t, resp)
   394  	if token != "" {
   395  		t.Fatal("should not return the token")
   396  	}
   397  }
   398  
   399  func TestExecuteInvalidCommand(t *testing.T) {
   400  	th := Setup().InitBasic().InitSystemAdmin()
   401  	defer th.TearDown()
   402  	Client := th.Client
   403  	channel := th.BasicChannel
   404  
   405  	enableCommands := *th.App.Config().ServiceSettings.EnableCommands
   406  	allowedInternalConnections := *th.App.Config().ServiceSettings.AllowedUntrustedInternalConnections
   407  	defer func() {
   408  		th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableCommands = &enableCommands })
   409  		th.App.UpdateConfig(func(cfg *model.Config) {
   410  			cfg.ServiceSettings.AllowedUntrustedInternalConnections = &allowedInternalConnections
   411  		})
   412  	}()
   413  	th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableCommands = true })
   414  	th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.AllowedUntrustedInternalConnections = "127.0.0.0/8" })
   415  
   416  	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   417  		rc := &model.CommandResponse{}
   418  
   419  		w.Write([]byte(rc.ToJson()))
   420  	}))
   421  	defer ts.Close()
   422  
   423  	getCmd := &model.Command{
   424  		CreatorId: th.BasicUser.Id,
   425  		TeamId:    th.BasicTeam.Id,
   426  		URL:       fmt.Sprintf("%s/%s/teams/command_test", ts.URL, model.API_URL_SUFFIX_V4),
   427  		Method:    model.COMMAND_METHOD_GET,
   428  		Trigger:   "getcommand",
   429  	}
   430  
   431  	if _, err := th.App.CreateCommand(getCmd); err != nil {
   432  		t.Fatal("failed to create get command")
   433  	}
   434  
   435  	_, resp := Client.ExecuteCommand(channel.Id, "")
   436  	CheckBadRequestStatus(t, resp)
   437  
   438  	_, resp = Client.ExecuteCommand(channel.Id, "/")
   439  	CheckBadRequestStatus(t, resp)
   440  
   441  	_, resp = Client.ExecuteCommand(channel.Id, "getcommand")
   442  	CheckBadRequestStatus(t, resp)
   443  
   444  	_, resp = Client.ExecuteCommand(channel.Id, "/junk")
   445  	CheckNotFoundStatus(t, resp)
   446  
   447  	otherUser := th.CreateUser()
   448  	Client.Login(otherUser.Email, otherUser.Password)
   449  
   450  	_, resp = Client.ExecuteCommand(channel.Id, "/getcommand")
   451  	CheckForbiddenStatus(t, resp)
   452  
   453  	Client.Logout()
   454  
   455  	_, resp = Client.ExecuteCommand(channel.Id, "/getcommand")
   456  	CheckUnauthorizedStatus(t, resp)
   457  
   458  	_, resp = th.SystemAdminClient.ExecuteCommand(channel.Id, "/getcommand")
   459  	CheckNoError(t, resp)
   460  }
   461  
   462  func TestExecuteGetCommand(t *testing.T) {
   463  	th := Setup().InitBasic().InitSystemAdmin()
   464  	defer th.TearDown()
   465  	Client := th.Client
   466  	channel := th.BasicChannel
   467  
   468  	enableCommands := *th.App.Config().ServiceSettings.EnableCommands
   469  	allowedInternalConnections := *th.App.Config().ServiceSettings.AllowedUntrustedInternalConnections
   470  	defer func() {
   471  		th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableCommands = &enableCommands })
   472  		th.App.UpdateConfig(func(cfg *model.Config) {
   473  			cfg.ServiceSettings.AllowedUntrustedInternalConnections = &allowedInternalConnections
   474  		})
   475  	}()
   476  	th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableCommands = true })
   477  	th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.AllowedUntrustedInternalConnections = "127.0.0.0/8" })
   478  
   479  	token := model.NewId()
   480  	expectedCommandResponse := &model.CommandResponse{
   481  		Text:         "test get command response",
   482  		ResponseType: model.COMMAND_RESPONSE_TYPE_IN_CHANNEL,
   483  		Type:         "custom_test",
   484  		Props:        map[string]interface{}{"someprop": "somevalue"},
   485  	}
   486  
   487  	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   488  		require.Equal(t, http.MethodGet, r.Method)
   489  
   490  		values, err := url.ParseQuery(r.URL.RawQuery)
   491  		require.NoError(t, err)
   492  
   493  		require.Equal(t, token, values.Get("token"))
   494  		require.Equal(t, th.BasicTeam.Name, values.Get("team_domain"))
   495  
   496  		w.Header().Set("Content-Type", "application/json")
   497  		w.Write([]byte(expectedCommandResponse.ToJson()))
   498  	}))
   499  	defer ts.Close()
   500  
   501  	getCmd := &model.Command{
   502  		CreatorId: th.BasicUser.Id,
   503  		TeamId:    th.BasicTeam.Id,
   504  		URL:       fmt.Sprintf("%s/%s/teams/command_test", ts.URL, model.API_URL_SUFFIX_V4),
   505  		Method:    model.COMMAND_METHOD_GET,
   506  		Trigger:   "getcommand",
   507  		Token:     token,
   508  	}
   509  
   510  	if _, err := th.App.CreateCommand(getCmd); err != nil {
   511  		t.Fatal("failed to create get command")
   512  	}
   513  
   514  	commandResponse, resp := Client.ExecuteCommand(channel.Id, "/getcommand")
   515  	CheckNoError(t, resp)
   516  
   517  	expectedCommandResponse.Props["from_webhook"] = "true"
   518  	require.Equal(t, expectedCommandResponse, commandResponse)
   519  }
   520  
   521  func TestExecutePostCommand(t *testing.T) {
   522  	th := Setup().InitBasic().InitSystemAdmin()
   523  	defer th.TearDown()
   524  	Client := th.Client
   525  	channel := th.BasicChannel
   526  
   527  	enableCommands := *th.App.Config().ServiceSettings.EnableCommands
   528  	allowedInternalConnections := *th.App.Config().ServiceSettings.AllowedUntrustedInternalConnections
   529  	defer func() {
   530  		th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableCommands = &enableCommands })
   531  		th.App.UpdateConfig(func(cfg *model.Config) {
   532  			cfg.ServiceSettings.AllowedUntrustedInternalConnections = &allowedInternalConnections
   533  		})
   534  	}()
   535  	th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableCommands = true })
   536  	th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.AllowedUntrustedInternalConnections = "127.0.0.0/8" })
   537  
   538  	token := model.NewId()
   539  	expectedCommandResponse := &model.CommandResponse{
   540  		Text:         "test post command response",
   541  		ResponseType: model.COMMAND_RESPONSE_TYPE_IN_CHANNEL,
   542  		Type:         "custom_test",
   543  		Props:        map[string]interface{}{"someprop": "somevalue"},
   544  	}
   545  
   546  	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   547  		require.Equal(t, http.MethodPost, r.Method)
   548  
   549  		r.ParseForm()
   550  
   551  		require.Equal(t, token, r.FormValue("token"))
   552  		require.Equal(t, th.BasicTeam.Name, r.FormValue("team_domain"))
   553  
   554  		w.Header().Set("Content-Type", "application/json")
   555  		w.Write([]byte(expectedCommandResponse.ToJson()))
   556  	}))
   557  	defer ts.Close()
   558  
   559  	getCmd := &model.Command{
   560  		CreatorId: th.BasicUser.Id,
   561  		TeamId:    th.BasicTeam.Id,
   562  		URL:       fmt.Sprintf("%s/%s/teams/command_test", ts.URL, model.API_URL_SUFFIX_V4),
   563  		Method:    model.COMMAND_METHOD_POST,
   564  		Trigger:   "postcommand",
   565  		Token:     token,
   566  	}
   567  
   568  	if _, err := th.App.CreateCommand(getCmd); err != nil {
   569  		t.Fatal("failed to create get command")
   570  	}
   571  
   572  	commandResponse, resp := Client.ExecuteCommand(channel.Id, "/postcommand")
   573  	CheckNoError(t, resp)
   574  
   575  	expectedCommandResponse.Props["from_webhook"] = "true"
   576  	require.Equal(t, expectedCommandResponse, commandResponse)
   577  
   578  }
   579  
   580  func TestExecuteCommandAgainstChannelOnAnotherTeam(t *testing.T) {
   581  	th := Setup().InitBasic()
   582  	defer th.TearDown()
   583  	Client := th.Client
   584  	channel := th.BasicChannel
   585  
   586  	enableCommands := *th.App.Config().ServiceSettings.EnableCommands
   587  	allowedInternalConnections := *th.App.Config().ServiceSettings.AllowedUntrustedInternalConnections
   588  	defer func() {
   589  		th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableCommands = &enableCommands })
   590  		th.App.UpdateConfig(func(cfg *model.Config) {
   591  			cfg.ServiceSettings.AllowedUntrustedInternalConnections = &allowedInternalConnections
   592  		})
   593  	}()
   594  	th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableCommands = true })
   595  	th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.AllowedUntrustedInternalConnections = "localhost" })
   596  
   597  	// create a slash command on some other team where we have permission to do so
   598  	team2 := th.CreateTeam()
   599  	postCmd := &model.Command{
   600  		CreatorId: th.BasicUser.Id,
   601  		TeamId:    team2.Id,
   602  		URL:       fmt.Sprintf("http://localhost:%v", th.App.Srv.ListenAddr.Port) + model.API_URL_SUFFIX_V4 + "/teams/command_test",
   603  		Method:    model.COMMAND_METHOD_POST,
   604  		Trigger:   "postcommand",
   605  	}
   606  	if _, err := th.App.CreateCommand(postCmd); err != nil {
   607  		t.Fatal("failed to create post command")
   608  	}
   609  
   610  	// the execute command endpoint will always search for the command by trigger and team id, inferring team id from the
   611  	// channel id, so there is no way to use that slash command on a channel that belongs to some other team
   612  	_, resp := Client.ExecuteCommand(channel.Id, "/postcommand")
   613  	CheckNotFoundStatus(t, resp)
   614  }
   615  
   616  func TestExecuteCommandAgainstChannelUserIsNotIn(t *testing.T) {
   617  	th := Setup().InitBasic()
   618  	defer th.TearDown()
   619  	client := th.Client
   620  
   621  	enableCommands := *th.App.Config().ServiceSettings.EnableCommands
   622  	allowedInternalConnections := *th.App.Config().ServiceSettings.AllowedUntrustedInternalConnections
   623  	defer func() {
   624  		th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableCommands = &enableCommands })
   625  		th.App.UpdateConfig(func(cfg *model.Config) {
   626  			cfg.ServiceSettings.AllowedUntrustedInternalConnections = &allowedInternalConnections
   627  		})
   628  	}()
   629  	th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableCommands = true })
   630  	th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.AllowedUntrustedInternalConnections = "localhost" })
   631  
   632  	// create a slash command on some other team where we have permission to do so
   633  	team2 := th.CreateTeam()
   634  	postCmd := &model.Command{
   635  		CreatorId: th.BasicUser.Id,
   636  		TeamId:    team2.Id,
   637  		URL:       fmt.Sprintf("http://localhost:%v", th.App.Srv.ListenAddr.Port) + model.API_URL_SUFFIX_V4 + "/teams/command_test",
   638  		Method:    model.COMMAND_METHOD_POST,
   639  		Trigger:   "postcommand",
   640  	}
   641  	if _, err := th.App.CreateCommand(postCmd); err != nil {
   642  		t.Fatal("failed to create post command")
   643  	}
   644  
   645  	// make a channel on that team, ensuring that our test user isn't in it
   646  	channel2 := th.CreateChannelWithClientAndTeam(client, model.CHANNEL_OPEN, team2.Id)
   647  	if success, _ := client.RemoveUserFromChannel(channel2.Id, th.BasicUser.Id); !success {
   648  		t.Fatal("Failed to remove user from channel")
   649  	}
   650  
   651  	// we should not be able to run the slash command in channel2, because we aren't in it
   652  	_, resp := client.ExecuteCommandWithTeam(channel2.Id, team2.Id, "/postcommand")
   653  	CheckForbiddenStatus(t, resp)
   654  }
   655  
   656  func TestExecuteCommandInDirectMessageChannel(t *testing.T) {
   657  	th := Setup().InitBasic()
   658  	defer th.TearDown()
   659  	client := th.Client
   660  
   661  	enableCommands := *th.App.Config().ServiceSettings.EnableCommands
   662  	allowedInternalConnections := *th.App.Config().ServiceSettings.AllowedUntrustedInternalConnections
   663  	defer func() {
   664  		th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableCommands = &enableCommands })
   665  		th.App.UpdateConfig(func(cfg *model.Config) {
   666  			cfg.ServiceSettings.AllowedUntrustedInternalConnections = &allowedInternalConnections
   667  		})
   668  	}()
   669  	th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableCommands = true })
   670  	th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.AllowedUntrustedInternalConnections = "localhost" })
   671  
   672  	// create a slash command on some other team where we have permission to do so
   673  	team2 := th.CreateTeam()
   674  	postCmd := &model.Command{
   675  		CreatorId: th.BasicUser.Id,
   676  		TeamId:    team2.Id,
   677  		URL:       fmt.Sprintf("http://localhost:%v", th.App.Srv.ListenAddr.Port) + model.API_URL_SUFFIX_V4 + "/teams/command_test",
   678  		Method:    model.COMMAND_METHOD_POST,
   679  		Trigger:   "postcommand",
   680  	}
   681  	if _, err := th.App.CreateCommand(postCmd); err != nil {
   682  		t.Fatal("failed to create post command")
   683  	}
   684  
   685  	// make a direct message channel
   686  	dmChannel, response := client.CreateDirectChannel(th.BasicUser.Id, th.BasicUser2.Id)
   687  	CheckCreatedStatus(t, response)
   688  
   689  	// we should be able to run the slash command in the DM channel
   690  	_, resp := client.ExecuteCommandWithTeam(dmChannel.Id, team2.Id, "/postcommand")
   691  	CheckOKStatus(t, resp)
   692  
   693  	// but we can't run the slash command in the DM channel if we sub in some other team's id
   694  	_, resp = client.ExecuteCommandWithTeam(dmChannel.Id, th.BasicTeam.Id, "/postcommand")
   695  	CheckNotFoundStatus(t, resp)
   696  }
   697  
   698  func TestExecuteCommandInTeamUserIsNotOn(t *testing.T) {
   699  	th := Setup().InitBasic()
   700  	defer th.TearDown()
   701  	client := th.Client
   702  
   703  	enableCommands := *th.App.Config().ServiceSettings.EnableCommands
   704  	allowedInternalConnections := *th.App.Config().ServiceSettings.AllowedUntrustedInternalConnections
   705  	defer func() {
   706  		th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableCommands = &enableCommands })
   707  		th.App.UpdateConfig(func(cfg *model.Config) {
   708  			cfg.ServiceSettings.AllowedUntrustedInternalConnections = &allowedInternalConnections
   709  		})
   710  	}()
   711  	th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableCommands = true })
   712  	th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.AllowedUntrustedInternalConnections = "localhost" })
   713  
   714  	// create a team that the user isn't a part of
   715  	team2 := th.CreateTeam()
   716  
   717  	// create a slash command on that team
   718  	postCmd := &model.Command{
   719  		CreatorId: th.BasicUser.Id,
   720  		TeamId:    team2.Id,
   721  		URL:       fmt.Sprintf("http://localhost:%v", th.App.Srv.ListenAddr.Port) + model.API_URL_SUFFIX_V4 + "/teams/command_test",
   722  		Method:    model.COMMAND_METHOD_POST,
   723  		Trigger:   "postcommand",
   724  	}
   725  	if _, err := th.App.CreateCommand(postCmd); err != nil {
   726  		t.Fatal("failed to create post command")
   727  	}
   728  
   729  	// make a direct message channel
   730  	dmChannel, response := client.CreateDirectChannel(th.BasicUser.Id, th.BasicUser2.Id)
   731  	CheckCreatedStatus(t, response)
   732  
   733  	// we should be able to run the slash command in the DM channel
   734  	_, resp := client.ExecuteCommandWithTeam(dmChannel.Id, team2.Id, "/postcommand")
   735  	CheckOKStatus(t, resp)
   736  
   737  	// if the user is removed from the team, they should NOT be able to run the slash command in the DM channel
   738  	if success, _ := client.RemoveTeamMember(team2.Id, th.BasicUser.Id); !success {
   739  		t.Fatal("Failed to remove user from team")
   740  	}
   741  	_, resp = client.ExecuteCommandWithTeam(dmChannel.Id, team2.Id, "/postcommand")
   742  	CheckForbiddenStatus(t, resp)
   743  
   744  	// if we omit the team id from the request, the slash command will fail because this is a DM channel, and the
   745  	// team id can't be inherited from the channel
   746  	_, resp = client.ExecuteCommand(dmChannel.Id, "/postcommand")
   747  	CheckForbiddenStatus(t, resp)
   748  }