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