github.com/masterhung0112/hk_server/v5@v5.0.0-20220302090640-ec71aef15e1c/api4/command_test.go (about)

     1  // Copyright (c) 2015-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  	"strings"
    11  	"testing"
    12  
    13  	"github.com/stretchr/testify/assert"
    14  	"github.com/stretchr/testify/require"
    15  
    16  	"github.com/masterhung0112/hk_server/v5/model"
    17  )
    18  
    19  func TestCreateCommand(t *testing.T) {
    20  	th := Setup(t).InitBasic()
    21  	defer th.TearDown()
    22  	Client := th.Client
    23  	LocalClient := th.LocalClient
    24  
    25  	enableCommands := *th.App.Config().ServiceSettings.EnableCommands
    26  	defer func() {
    27  		th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableCommands = &enableCommands })
    28  	}()
    29  	th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableCommands = true })
    30  
    31  	newCmd := &model.Command{
    32  		CreatorId: th.BasicUser.Id,
    33  		TeamId:    th.BasicTeam.Id,
    34  		URL:       "http://nowhere.com",
    35  		Method:    model.COMMAND_METHOD_POST,
    36  		Trigger:   "trigger"}
    37  
    38  	_, resp := Client.CreateCommand(newCmd)
    39  	CheckForbiddenStatus(t, resp)
    40  
    41  	createdCmd, resp := th.SystemAdminClient.CreateCommand(newCmd)
    42  	CheckNoError(t, resp)
    43  	CheckCreatedStatus(t, resp)
    44  	require.Equal(t, th.SystemAdminUser.Id, createdCmd.CreatorId, "user ids didn't match")
    45  	require.Equal(t, th.BasicTeam.Id, createdCmd.TeamId, "team ids didn't match")
    46  
    47  	_, resp = th.SystemAdminClient.CreateCommand(newCmd)
    48  	CheckBadRequestStatus(t, resp)
    49  	CheckErrorMessage(t, resp, "api.command.duplicate_trigger.app_error")
    50  
    51  	newCmd.Trigger = "Local"
    52  	localCreatedCmd, resp := LocalClient.CreateCommand(newCmd)
    53  	CheckNoError(t, resp)
    54  	CheckCreatedStatus(t, resp)
    55  	require.Equal(t, th.BasicUser.Id, localCreatedCmd.CreatorId, "local client: user ids didn't match")
    56  	require.Equal(t, th.BasicTeam.Id, localCreatedCmd.TeamId, "local client: team ids didn't match")
    57  
    58  	newCmd.Method = "Wrong"
    59  	newCmd.Trigger = "testcommand"
    60  	_, resp = th.SystemAdminClient.CreateCommand(newCmd)
    61  	CheckBadRequestStatus(t, resp)
    62  	CheckErrorMessage(t, resp, "model.command.is_valid.method.app_error")
    63  
    64  	th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableCommands = false })
    65  	newCmd.Method = "P"
    66  	newCmd.Trigger = "testcommand"
    67  	_, resp = th.SystemAdminClient.CreateCommand(newCmd)
    68  	CheckNotImplementedStatus(t, resp)
    69  	CheckErrorMessage(t, resp, "api.command.disabled.app_error")
    70  
    71  	// Confirm that local clients can't override disable command setting
    72  	newCmd.Trigger = "LocalOverride"
    73  	_, resp = LocalClient.CreateCommand(newCmd)
    74  	CheckErrorMessage(t, resp, "api.command.disabled.app_error")
    75  }
    76  
    77  func TestUpdateCommand(t *testing.T) {
    78  	th := Setup(t).InitBasic()
    79  	defer th.TearDown()
    80  	user := th.SystemAdminUser
    81  	team := th.BasicTeam
    82  
    83  	enableCommands := *th.App.Config().ServiceSettings.EnableCommands
    84  	defer func() {
    85  		th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableCommands = &enableCommands })
    86  	}()
    87  	th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableCommands = true })
    88  
    89  	cmd1 := &model.Command{
    90  		CreatorId: user.Id,
    91  		TeamId:    team.Id,
    92  		URL:       "http://nowhere.com",
    93  		Method:    model.COMMAND_METHOD_POST,
    94  		Trigger:   "trigger1",
    95  	}
    96  
    97  	cmd1, _ = th.App.CreateCommand(cmd1)
    98  
    99  	cmd2 := &model.Command{
   100  		CreatorId: GenerateTestId(),
   101  		TeamId:    team.Id,
   102  		URL:       "http://nowhere.com/change",
   103  		Method:    model.COMMAND_METHOD_GET,
   104  		Trigger:   "trigger2",
   105  		Id:        cmd1.Id,
   106  		Token:     "tokenchange",
   107  	}
   108  
   109  	th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
   110  		rcmd, resp := client.UpdateCommand(cmd2)
   111  		CheckNoError(t, resp)
   112  
   113  		require.Equal(t, cmd2.Trigger, rcmd.Trigger, "Trigger should have updated")
   114  
   115  		require.Equal(t, cmd2.Method, rcmd.Method, "Method should have updated")
   116  
   117  		require.Equal(t, cmd2.URL, rcmd.URL, "URL should have updated")
   118  
   119  		require.Equal(t, cmd1.CreatorId, rcmd.CreatorId, "CreatorId should have not updated")
   120  
   121  		require.Equal(t, cmd1.Token, rcmd.Token, "Token should have not updated")
   122  
   123  		cmd2.Id = GenerateTestId()
   124  
   125  		rcmd, resp = client.UpdateCommand(cmd2)
   126  		CheckNotFoundStatus(t, resp)
   127  
   128  		require.Nil(t, rcmd, "should be empty")
   129  
   130  		cmd2.Id = "junk"
   131  
   132  		_, resp = client.UpdateCommand(cmd2)
   133  		CheckBadRequestStatus(t, resp)
   134  
   135  		cmd2.Id = cmd1.Id
   136  		cmd2.TeamId = GenerateTestId()
   137  
   138  		_, resp = client.UpdateCommand(cmd2)
   139  		CheckBadRequestStatus(t, resp)
   140  
   141  		cmd2.TeamId = team.Id
   142  
   143  		_, resp = th.Client.UpdateCommand(cmd2)
   144  		CheckNotFoundStatus(t, resp)
   145  	})
   146  	th.SystemAdminClient.Logout()
   147  	_, resp := th.SystemAdminClient.UpdateCommand(cmd2)
   148  	CheckUnauthorizedStatus(t, resp)
   149  }
   150  
   151  func TestMoveCommand(t *testing.T) {
   152  	th := Setup(t).InitBasic()
   153  	defer th.TearDown()
   154  	user := th.SystemAdminUser
   155  	team := th.BasicTeam
   156  	newTeam := th.CreateTeam()
   157  
   158  	enableCommands := *th.App.Config().ServiceSettings.EnableCommands
   159  	defer func() {
   160  		th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableCommands = &enableCommands })
   161  	}()
   162  	th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableCommands = true })
   163  
   164  	cmd1 := &model.Command{
   165  		CreatorId: user.Id,
   166  		TeamId:    team.Id,
   167  		URL:       "http://nowhere.com",
   168  		Method:    model.COMMAND_METHOD_POST,
   169  		Trigger:   "trigger1",
   170  	}
   171  
   172  	rcmd1, _ := th.App.CreateCommand(cmd1)
   173  	th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
   174  
   175  		ok, resp := client.MoveCommand(newTeam.Id, rcmd1.Id)
   176  		CheckNoError(t, resp)
   177  		require.True(t, ok)
   178  
   179  		rcmd1, _ = th.App.GetCommand(rcmd1.Id)
   180  		require.NotNil(t, rcmd1)
   181  		require.Equal(t, newTeam.Id, rcmd1.TeamId)
   182  
   183  		ok, resp = client.MoveCommand(newTeam.Id, "bogus")
   184  		CheckBadRequestStatus(t, resp)
   185  		require.False(t, ok)
   186  
   187  		ok, resp = client.MoveCommand(GenerateTestId(), rcmd1.Id)
   188  		CheckNotFoundStatus(t, resp)
   189  		require.False(t, ok)
   190  	})
   191  	cmd2 := &model.Command{
   192  		CreatorId: user.Id,
   193  		TeamId:    team.Id,
   194  		URL:       "http://nowhere.com",
   195  		Method:    model.COMMAND_METHOD_POST,
   196  		Trigger:   "trigger2",
   197  	}
   198  
   199  	rcmd2, _ := th.App.CreateCommand(cmd2)
   200  
   201  	_, resp := th.Client.MoveCommand(newTeam.Id, rcmd2.Id)
   202  	CheckNotFoundStatus(t, resp)
   203  
   204  	th.SystemAdminClient.Logout()
   205  	_, resp = th.SystemAdminClient.MoveCommand(newTeam.Id, rcmd2.Id)
   206  	CheckUnauthorizedStatus(t, resp)
   207  }
   208  
   209  func TestDeleteCommand(t *testing.T) {
   210  	th := Setup(t).InitBasic()
   211  	defer th.TearDown()
   212  	user := th.SystemAdminUser
   213  	team := th.BasicTeam
   214  
   215  	enableCommands := *th.App.Config().ServiceSettings.EnableCommands
   216  	defer func() {
   217  		th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableCommands = &enableCommands })
   218  	}()
   219  	th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableCommands = true })
   220  
   221  	cmd1 := &model.Command{
   222  		CreatorId: user.Id,
   223  		TeamId:    team.Id,
   224  		URL:       "http://nowhere.com",
   225  		Method:    model.COMMAND_METHOD_POST,
   226  		Trigger:   "trigger1",
   227  	}
   228  
   229  	th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
   230  		cmd1.Id = ""
   231  		rcmd1, err := th.App.CreateCommand(cmd1)
   232  		require.Nil(t, err)
   233  		ok, resp := client.DeleteCommand(rcmd1.Id)
   234  		CheckNoError(t, resp)
   235  
   236  		require.True(t, ok)
   237  
   238  		rcmd1, _ = th.App.GetCommand(rcmd1.Id)
   239  		require.Nil(t, rcmd1)
   240  
   241  		ok, resp = client.DeleteCommand("junk")
   242  		CheckBadRequestStatus(t, resp)
   243  
   244  		require.False(t, ok)
   245  
   246  		_, resp = client.DeleteCommand(GenerateTestId())
   247  		CheckNotFoundStatus(t, resp)
   248  	})
   249  	cmd2 := &model.Command{
   250  		CreatorId: user.Id,
   251  		TeamId:    team.Id,
   252  		URL:       "http://nowhere.com",
   253  		Method:    model.COMMAND_METHOD_POST,
   254  		Trigger:   "trigger2",
   255  	}
   256  
   257  	rcmd2, _ := th.App.CreateCommand(cmd2)
   258  
   259  	_, resp := th.Client.DeleteCommand(rcmd2.Id)
   260  	CheckNotFoundStatus(t, resp)
   261  
   262  	th.SystemAdminClient.Logout()
   263  	_, resp = th.SystemAdminClient.DeleteCommand(rcmd2.Id)
   264  	CheckUnauthorizedStatus(t, resp)
   265  }
   266  
   267  func TestListCommands(t *testing.T) {
   268  	th := Setup(t).InitBasic()
   269  	defer th.TearDown()
   270  	Client := th.Client
   271  
   272  	enableCommands := *th.App.Config().ServiceSettings.EnableCommands
   273  	defer func() {
   274  		th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableCommands = &enableCommands })
   275  	}()
   276  	th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableCommands = true })
   277  
   278  	newCmd := &model.Command{
   279  		CreatorId: th.BasicUser.Id,
   280  		TeamId:    th.BasicTeam.Id,
   281  		URL:       "http://nowhere.com",
   282  		Method:    model.COMMAND_METHOD_POST,
   283  		Trigger:   "custom_command"}
   284  
   285  	_, resp := th.SystemAdminClient.CreateCommand(newCmd)
   286  	CheckNoError(t, resp)
   287  
   288  	th.TestForSystemAdminAndLocal(t, func(t *testing.T, c *model.Client4) {
   289  		listCommands, resp := c.ListCommands(th.BasicTeam.Id, false)
   290  		CheckNoError(t, resp)
   291  
   292  		foundEcho := false
   293  		foundCustom := false
   294  		for _, command := range listCommands {
   295  			if command.Trigger == "echo" {
   296  				foundEcho = true
   297  			}
   298  			if command.Trigger == "custom_command" {
   299  				foundCustom = true
   300  			}
   301  		}
   302  		require.True(t, foundEcho, "Couldn't find echo command")
   303  		require.True(t, foundCustom, "Should list the custom command")
   304  	}, "ListSystemAndCustomCommands")
   305  
   306  	th.TestForSystemAdminAndLocal(t, func(t *testing.T, c *model.Client4) {
   307  		listCommands, resp := c.ListCommands(th.BasicTeam.Id, true)
   308  		CheckNoError(t, resp)
   309  
   310  		require.Len(t, listCommands, 1, "Should list just one custom command")
   311  		require.Equal(t, listCommands[0].Trigger, "custom_command", "Wrong custom command trigger")
   312  	}, "ListCustomOnlyCommands")
   313  
   314  	t.Run("UserWithNoPermissionForCustomCommands", func(t *testing.T) {
   315  		_, resp := Client.ListCommands(th.BasicTeam.Id, true)
   316  		CheckForbiddenStatus(t, resp)
   317  	})
   318  
   319  	t.Run("RegularUserCanListOnlySystemCommands", func(t *testing.T) {
   320  		listCommands, resp := Client.ListCommands(th.BasicTeam.Id, false)
   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  		require.True(t, foundEcho, "Couldn't find echo command")
   334  		require.False(t, foundCustom, "Should not list the custom command")
   335  	})
   336  
   337  	t.Run("NoMember", func(t *testing.T) {
   338  		Client.Logout()
   339  		user := th.CreateUser()
   340  		th.SystemAdminClient.RemoveTeamMember(th.BasicTeam.Id, user.Id)
   341  		Client.Login(user.Email, user.Password)
   342  		_, resp := Client.ListCommands(th.BasicTeam.Id, false)
   343  		CheckForbiddenStatus(t, resp)
   344  		_, resp = Client.ListCommands(th.BasicTeam.Id, true)
   345  		CheckForbiddenStatus(t, resp)
   346  	})
   347  
   348  	t.Run("NotLoggedIn", func(t *testing.T) {
   349  		Client.Logout()
   350  		_, resp := Client.ListCommands(th.BasicTeam.Id, false)
   351  		CheckUnauthorizedStatus(t, resp)
   352  		_, resp = Client.ListCommands(th.BasicTeam.Id, true)
   353  		CheckUnauthorizedStatus(t, resp)
   354  	})
   355  }
   356  
   357  func TestListAutocompleteCommands(t *testing.T) {
   358  	th := Setup(t).InitBasic()
   359  	defer th.TearDown()
   360  	Client := th.Client
   361  
   362  	newCmd := &model.Command{
   363  		CreatorId: th.BasicUser.Id,
   364  		TeamId:    th.BasicTeam.Id,
   365  		URL:       "http://nowhere.com",
   366  		Method:    model.COMMAND_METHOD_POST,
   367  		Trigger:   "custom_command"}
   368  
   369  	_, resp := th.SystemAdminClient.CreateCommand(newCmd)
   370  	CheckNoError(t, resp)
   371  
   372  	t.Run("ListAutocompleteCommandsOnly", func(t *testing.T) {
   373  		listCommands, resp := th.SystemAdminClient.ListAutocompleteCommands(th.BasicTeam.Id)
   374  		CheckNoError(t, resp)
   375  
   376  		foundEcho := false
   377  		foundCustom := false
   378  		for _, command := range listCommands {
   379  			if command.Trigger == "echo" {
   380  				foundEcho = true
   381  			}
   382  			if command.Trigger == "custom_command" {
   383  				foundCustom = true
   384  			}
   385  		}
   386  		require.True(t, foundEcho, "Couldn't find echo command")
   387  		require.False(t, foundCustom, "Should not list the custom command")
   388  	})
   389  
   390  	t.Run("RegularUserCanListOnlySystemCommands", func(t *testing.T) {
   391  		listCommands, resp := Client.ListAutocompleteCommands(th.BasicTeam.Id)
   392  		CheckNoError(t, resp)
   393  
   394  		foundEcho := false
   395  		foundCustom := false
   396  		for _, command := range listCommands {
   397  			if command.Trigger == "echo" {
   398  				foundEcho = true
   399  			}
   400  			if command.Trigger == "custom_command" {
   401  				foundCustom = true
   402  			}
   403  		}
   404  		require.True(t, foundEcho, "Couldn't find echo command")
   405  		require.False(t, foundCustom, "Should not list the custom command")
   406  	})
   407  
   408  	t.Run("NoMember", func(t *testing.T) {
   409  		Client.Logout()
   410  		user := th.CreateUser()
   411  		th.SystemAdminClient.RemoveTeamMember(th.BasicTeam.Id, user.Id)
   412  		Client.Login(user.Email, user.Password)
   413  		_, resp := Client.ListAutocompleteCommands(th.BasicTeam.Id)
   414  		CheckForbiddenStatus(t, resp)
   415  	})
   416  
   417  	t.Run("NotLoggedIn", func(t *testing.T) {
   418  		Client.Logout()
   419  		_, resp := Client.ListAutocompleteCommands(th.BasicTeam.Id)
   420  		CheckUnauthorizedStatus(t, resp)
   421  	})
   422  }
   423  
   424  func TestListCommandAutocompleteSuggestions(t *testing.T) {
   425  	th := Setup(t).InitBasic()
   426  	defer th.TearDown()
   427  	Client := th.Client
   428  
   429  	newCmd := &model.Command{
   430  		CreatorId: th.BasicUser.Id,
   431  		TeamId:    th.BasicTeam.Id,
   432  		URL:       "http://nowhere.com",
   433  		Method:    model.COMMAND_METHOD_POST,
   434  		Trigger:   "custom_command"}
   435  
   436  	_, resp := th.SystemAdminClient.CreateCommand(newCmd)
   437  	CheckNoError(t, resp)
   438  
   439  	t.Run("ListAutocompleteSuggestionsOnly", func(t *testing.T) {
   440  		suggestions, resp := th.SystemAdminClient.ListCommandAutocompleteSuggestions("/", th.BasicTeam.Id)
   441  		CheckNoError(t, resp)
   442  
   443  		foundEcho := false
   444  		foundShrug := false
   445  		foundCustom := false
   446  		for _, command := range suggestions {
   447  			if command.Suggestion == "echo" {
   448  				foundEcho = true
   449  			}
   450  			if command.Suggestion == "shrug" {
   451  				foundShrug = true
   452  			}
   453  			if command.Suggestion == "custom_command" {
   454  				foundCustom = true
   455  			}
   456  		}
   457  		require.True(t, foundEcho, "Couldn't find echo command")
   458  		require.True(t, foundShrug, "Couldn't find shrug command")
   459  		require.False(t, foundCustom, "Should not list the custom command")
   460  	})
   461  
   462  	t.Run("ListAutocompleteSuggestionsOnlyWithInput", func(t *testing.T) {
   463  		suggestions, resp := th.SystemAdminClient.ListCommandAutocompleteSuggestions("/e", th.BasicTeam.Id)
   464  		CheckNoError(t, resp)
   465  
   466  		foundEcho := false
   467  		foundShrug := false
   468  		for _, command := range suggestions {
   469  			if command.Suggestion == "echo" {
   470  				foundEcho = true
   471  			}
   472  			if command.Suggestion == "shrug" {
   473  				foundShrug = true
   474  			}
   475  		}
   476  		require.True(t, foundEcho, "Couldn't find echo command")
   477  		require.False(t, foundShrug, "Should not list the shrug command")
   478  	})
   479  
   480  	t.Run("RegularUserCanListOnlySystemCommands", func(t *testing.T) {
   481  		suggestions, resp := Client.ListCommandAutocompleteSuggestions("/", th.BasicTeam.Id)
   482  		CheckNoError(t, resp)
   483  
   484  		foundEcho := false
   485  		foundCustom := false
   486  		for _, suggestion := range suggestions {
   487  			if suggestion.Suggestion == "echo" {
   488  				foundEcho = true
   489  			}
   490  			if suggestion.Suggestion == "custom_command" {
   491  				foundCustom = true
   492  			}
   493  		}
   494  		require.True(t, foundEcho, "Couldn't find echo command")
   495  		require.False(t, foundCustom, "Should not list the custom command")
   496  	})
   497  
   498  	t.Run("NoMember", func(t *testing.T) {
   499  		Client.Logout()
   500  		user := th.CreateUser()
   501  		th.SystemAdminClient.RemoveTeamMember(th.BasicTeam.Id, user.Id)
   502  		Client.Login(user.Email, user.Password)
   503  		_, resp := Client.ListCommandAutocompleteSuggestions("/", th.BasicTeam.Id)
   504  		CheckForbiddenStatus(t, resp)
   505  	})
   506  
   507  	t.Run("NotLoggedIn", func(t *testing.T) {
   508  		Client.Logout()
   509  		_, resp := Client.ListCommandAutocompleteSuggestions("/", th.BasicTeam.Id)
   510  		CheckUnauthorizedStatus(t, resp)
   511  	})
   512  }
   513  
   514  func TestGetCommand(t *testing.T) {
   515  	th := Setup(t).InitBasic()
   516  	defer th.TearDown()
   517  
   518  	enableCommands := *th.App.Config().ServiceSettings.EnableCommands
   519  	defer func() {
   520  		th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableCommands = &enableCommands })
   521  	}()
   522  	th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableCommands = true })
   523  
   524  	newCmd := &model.Command{
   525  		CreatorId: th.BasicUser.Id,
   526  		TeamId:    th.BasicTeam.Id,
   527  		URL:       "http://nowhere.com",
   528  		Method:    model.COMMAND_METHOD_POST,
   529  		Trigger:   "roger"}
   530  
   531  	newCmd, resp := th.SystemAdminClient.CreateCommand(newCmd)
   532  	CheckNoError(t, resp)
   533  	th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
   534  
   535  		t.Run("ValidId", func(t *testing.T) {
   536  			cmd, resp := client.GetCommandById(newCmd.Id)
   537  			CheckNoError(t, resp)
   538  
   539  			require.Equal(t, newCmd.Id, cmd.Id)
   540  			require.Equal(t, newCmd.CreatorId, cmd.CreatorId)
   541  			require.Equal(t, newCmd.TeamId, cmd.TeamId)
   542  			require.Equal(t, newCmd.URL, cmd.URL)
   543  			require.Equal(t, newCmd.Method, cmd.Method)
   544  			require.Equal(t, newCmd.Trigger, cmd.Trigger)
   545  		})
   546  
   547  		t.Run("InvalidId", func(t *testing.T) {
   548  			_, resp := client.GetCommandById(strings.Repeat("z", len(newCmd.Id)))
   549  			require.NotNil(t, resp.Error)
   550  		})
   551  	})
   552  	t.Run("UserWithNoPermissionForCustomCommands", func(t *testing.T) {
   553  		_, resp := th.Client.GetCommandById(newCmd.Id)
   554  		CheckNotFoundStatus(t, resp)
   555  	})
   556  
   557  	t.Run("NoMember", func(t *testing.T) {
   558  		th.Client.Logout()
   559  		user := th.CreateUser()
   560  		th.SystemAdminClient.RemoveTeamMember(th.BasicTeam.Id, user.Id)
   561  		th.Client.Login(user.Email, user.Password)
   562  		_, resp := th.Client.GetCommandById(newCmd.Id)
   563  		CheckNotFoundStatus(t, resp)
   564  	})
   565  
   566  	t.Run("NotLoggedIn", func(t *testing.T) {
   567  		th.Client.Logout()
   568  		_, resp := th.Client.GetCommandById(newCmd.Id)
   569  		CheckUnauthorizedStatus(t, resp)
   570  	})
   571  }
   572  
   573  func TestRegenToken(t *testing.T) {
   574  	th := Setup(t).InitBasic()
   575  	defer th.TearDown()
   576  	Client := th.Client
   577  
   578  	enableCommands := *th.App.Config().ServiceSettings.EnableCommands
   579  	defer func() {
   580  		th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableCommands = &enableCommands })
   581  	}()
   582  	th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableCommands = true })
   583  
   584  	newCmd := &model.Command{
   585  		CreatorId: th.BasicUser.Id,
   586  		TeamId:    th.BasicTeam.Id,
   587  		URL:       "http://nowhere.com",
   588  		Method:    model.COMMAND_METHOD_POST,
   589  		Trigger:   "trigger"}
   590  
   591  	createdCmd, resp := th.SystemAdminClient.CreateCommand(newCmd)
   592  	CheckNoError(t, resp)
   593  	CheckCreatedStatus(t, resp)
   594  
   595  	token, resp := th.SystemAdminClient.RegenCommandToken(createdCmd.Id)
   596  	CheckNoError(t, resp)
   597  	require.NotEqual(t, createdCmd.Token, token, "should update the token")
   598  
   599  	token, resp = Client.RegenCommandToken(createdCmd.Id)
   600  	CheckNotFoundStatus(t, resp)
   601  	require.Empty(t, token, "should not return the token")
   602  }
   603  
   604  func TestExecuteInvalidCommand(t *testing.T) {
   605  	th := Setup(t).InitBasic()
   606  	defer th.TearDown()
   607  	Client := th.Client
   608  	channel := th.BasicChannel
   609  
   610  	enableCommands := *th.App.Config().ServiceSettings.EnableCommands
   611  	allowedInternalConnections := *th.App.Config().ServiceSettings.AllowedUntrustedInternalConnections
   612  	defer func() {
   613  		th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableCommands = &enableCommands })
   614  		th.App.UpdateConfig(func(cfg *model.Config) {
   615  			cfg.ServiceSettings.AllowedUntrustedInternalConnections = &allowedInternalConnections
   616  		})
   617  	}()
   618  	th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableCommands = true })
   619  	th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.AllowedUntrustedInternalConnections = "127.0.0.0/8" })
   620  
   621  	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   622  		rc := &model.CommandResponse{}
   623  
   624  		w.Write([]byte(rc.ToJson()))
   625  	}))
   626  	defer ts.Close()
   627  
   628  	getCmd := &model.Command{
   629  		CreatorId: th.BasicUser.Id,
   630  		TeamId:    th.BasicTeam.Id,
   631  		URL:       ts.URL,
   632  		Method:    model.COMMAND_METHOD_GET,
   633  		Trigger:   "getcommand",
   634  	}
   635  
   636  	_, err := th.App.CreateCommand(getCmd)
   637  	require.Nil(t, err, "failed to create get command")
   638  
   639  	_, resp := Client.ExecuteCommand(channel.Id, "")
   640  	CheckBadRequestStatus(t, resp)
   641  
   642  	_, resp = Client.ExecuteCommand(channel.Id, "/")
   643  	CheckBadRequestStatus(t, resp)
   644  
   645  	_, resp = Client.ExecuteCommand(channel.Id, "getcommand")
   646  	CheckBadRequestStatus(t, resp)
   647  
   648  	_, resp = Client.ExecuteCommand(channel.Id, "/junk")
   649  	CheckNotFoundStatus(t, resp)
   650  
   651  	otherUser := th.CreateUser()
   652  	Client.Login(otherUser.Email, otherUser.Password)
   653  
   654  	_, resp = Client.ExecuteCommand(channel.Id, "/getcommand")
   655  	CheckForbiddenStatus(t, resp)
   656  
   657  	Client.Logout()
   658  
   659  	_, resp = Client.ExecuteCommand(channel.Id, "/getcommand")
   660  	CheckUnauthorizedStatus(t, resp)
   661  
   662  	_, resp = th.SystemAdminClient.ExecuteCommand(channel.Id, "/getcommand")
   663  	CheckNoError(t, resp)
   664  }
   665  
   666  func TestExecuteGetCommand(t *testing.T) {
   667  	th := Setup(t).InitBasic()
   668  	defer th.TearDown()
   669  	Client := th.Client
   670  	channel := th.BasicChannel
   671  
   672  	enableCommands := *th.App.Config().ServiceSettings.EnableCommands
   673  	allowedInternalConnections := *th.App.Config().ServiceSettings.AllowedUntrustedInternalConnections
   674  	defer func() {
   675  		th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableCommands = &enableCommands })
   676  		th.App.UpdateConfig(func(cfg *model.Config) {
   677  			cfg.ServiceSettings.AllowedUntrustedInternalConnections = &allowedInternalConnections
   678  		})
   679  	}()
   680  	th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableCommands = true })
   681  	th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.AllowedUntrustedInternalConnections = "127.0.0.0/8" })
   682  
   683  	token := model.NewId()
   684  	expectedCommandResponse := &model.CommandResponse{
   685  		Text:         "test get command response",
   686  		ResponseType: model.COMMAND_RESPONSE_TYPE_IN_CHANNEL,
   687  		Type:         "custom_test",
   688  		Props:        map[string]interface{}{"someprop": "somevalue"},
   689  	}
   690  
   691  	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   692  		require.Equal(t, http.MethodGet, r.Method)
   693  
   694  		values, err := url.ParseQuery(r.URL.RawQuery)
   695  		require.NoError(t, err)
   696  
   697  		require.Equal(t, token, values.Get("token"))
   698  		require.Equal(t, th.BasicTeam.Name, values.Get("team_domain"))
   699  		require.Equal(t, "ourCommand", values.Get("cmd"))
   700  
   701  		w.Header().Set("Content-Type", "application/json")
   702  		w.Write([]byte(expectedCommandResponse.ToJson()))
   703  	}))
   704  	defer ts.Close()
   705  
   706  	getCmd := &model.Command{
   707  		CreatorId: th.BasicUser.Id,
   708  		TeamId:    th.BasicTeam.Id,
   709  		URL:       ts.URL + "/?cmd=ourCommand",
   710  		Method:    model.COMMAND_METHOD_GET,
   711  		Trigger:   "getcommand",
   712  		Token:     token,
   713  	}
   714  
   715  	_, err := th.App.CreateCommand(getCmd)
   716  	require.Nil(t, err, "failed to create get command")
   717  
   718  	commandResponse, resp := Client.ExecuteCommand(channel.Id, "/getcommand")
   719  	CheckNoError(t, resp)
   720  	assert.True(t, len(commandResponse.TriggerId) == 26)
   721  
   722  	expectedCommandResponse.TriggerId = commandResponse.TriggerId
   723  	require.Equal(t, expectedCommandResponse, commandResponse)
   724  }
   725  
   726  func TestExecutePostCommand(t *testing.T) {
   727  	th := Setup(t).InitBasic()
   728  	defer th.TearDown()
   729  	Client := th.Client
   730  	channel := th.BasicChannel
   731  
   732  	enableCommands := *th.App.Config().ServiceSettings.EnableCommands
   733  	allowedInternalConnections := *th.App.Config().ServiceSettings.AllowedUntrustedInternalConnections
   734  	defer func() {
   735  		th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableCommands = &enableCommands })
   736  		th.App.UpdateConfig(func(cfg *model.Config) {
   737  			cfg.ServiceSettings.AllowedUntrustedInternalConnections = &allowedInternalConnections
   738  		})
   739  	}()
   740  	th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableCommands = true })
   741  	th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.AllowedUntrustedInternalConnections = "127.0.0.0/8" })
   742  
   743  	token := model.NewId()
   744  	expectedCommandResponse := &model.CommandResponse{
   745  		Text:         "test post command response",
   746  		ResponseType: model.COMMAND_RESPONSE_TYPE_IN_CHANNEL,
   747  		Type:         "custom_test",
   748  		Props:        map[string]interface{}{"someprop": "somevalue"},
   749  	}
   750  
   751  	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   752  		require.Equal(t, http.MethodPost, r.Method)
   753  
   754  		r.ParseForm()
   755  
   756  		require.Equal(t, token, r.FormValue("token"))
   757  		require.Equal(t, th.BasicTeam.Name, r.FormValue("team_domain"))
   758  
   759  		w.Header().Set("Content-Type", "application/json")
   760  		w.Write([]byte(expectedCommandResponse.ToJson()))
   761  	}))
   762  	defer ts.Close()
   763  
   764  	postCmd := &model.Command{
   765  		CreatorId: th.BasicUser.Id,
   766  		TeamId:    th.BasicTeam.Id,
   767  		URL:       ts.URL,
   768  		Method:    model.COMMAND_METHOD_POST,
   769  		Trigger:   "postcommand",
   770  		Token:     token,
   771  	}
   772  
   773  	_, err := th.App.CreateCommand(postCmd)
   774  	require.Nil(t, err, "failed to create get command")
   775  
   776  	commandResponse, resp := Client.ExecuteCommand(channel.Id, "/postcommand")
   777  	CheckNoError(t, resp)
   778  	assert.True(t, len(commandResponse.TriggerId) == 26)
   779  
   780  	expectedCommandResponse.TriggerId = commandResponse.TriggerId
   781  	require.Equal(t, expectedCommandResponse, commandResponse)
   782  }
   783  
   784  func TestExecuteCommandAgainstChannelOnAnotherTeam(t *testing.T) {
   785  	th := Setup(t).InitBasic()
   786  	defer th.TearDown()
   787  	Client := th.Client
   788  	channel := th.BasicChannel
   789  
   790  	enableCommands := *th.App.Config().ServiceSettings.EnableCommands
   791  	allowedInternalConnections := *th.App.Config().ServiceSettings.AllowedUntrustedInternalConnections
   792  	defer func() {
   793  		th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableCommands = &enableCommands })
   794  		th.App.UpdateConfig(func(cfg *model.Config) {
   795  			cfg.ServiceSettings.AllowedUntrustedInternalConnections = &allowedInternalConnections
   796  		})
   797  	}()
   798  	th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableCommands = true })
   799  	th.App.UpdateConfig(func(cfg *model.Config) {
   800  		*cfg.ServiceSettings.AllowedUntrustedInternalConnections = "localhost,127.0.0.1"
   801  	})
   802  
   803  	expectedCommandResponse := &model.CommandResponse{
   804  		Text:         "test post command response",
   805  		ResponseType: model.COMMAND_RESPONSE_TYPE_IN_CHANNEL,
   806  		Type:         "custom_test",
   807  		Props:        map[string]interface{}{"someprop": "somevalue"},
   808  	}
   809  
   810  	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   811  		w.Header().Set("Content-Type", "application/json")
   812  		w.Write([]byte(expectedCommandResponse.ToJson()))
   813  	}))
   814  	defer ts.Close()
   815  
   816  	// create a slash command on some other team where we have permission to do so
   817  	team2 := th.CreateTeam()
   818  	postCmd := &model.Command{
   819  		CreatorId: th.BasicUser.Id,
   820  		TeamId:    team2.Id,
   821  		URL:       ts.URL,
   822  		Method:    model.COMMAND_METHOD_POST,
   823  		Trigger:   "postcommand",
   824  	}
   825  	_, err := th.App.CreateCommand(postCmd)
   826  	require.Nil(t, err, "failed to create post command")
   827  
   828  	// the execute command endpoint will always search for the command by trigger and team id, inferring team id from the
   829  	// channel id, so there is no way to use that slash command on a channel that belongs to some other team
   830  	_, resp := Client.ExecuteCommand(channel.Id, "/postcommand")
   831  	CheckNotFoundStatus(t, resp)
   832  }
   833  
   834  func TestExecuteCommandAgainstChannelUserIsNotIn(t *testing.T) {
   835  	th := Setup(t).InitBasic()
   836  	defer th.TearDown()
   837  	client := th.Client
   838  
   839  	enableCommands := *th.App.Config().ServiceSettings.EnableCommands
   840  	allowedInternalConnections := *th.App.Config().ServiceSettings.AllowedUntrustedInternalConnections
   841  	defer func() {
   842  		th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableCommands = &enableCommands })
   843  		th.App.UpdateConfig(func(cfg *model.Config) {
   844  			cfg.ServiceSettings.AllowedUntrustedInternalConnections = &allowedInternalConnections
   845  		})
   846  	}()
   847  	th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableCommands = true })
   848  	th.App.UpdateConfig(func(cfg *model.Config) {
   849  		*cfg.ServiceSettings.AllowedUntrustedInternalConnections = "localhost,127.0.0.1"
   850  	})
   851  
   852  	expectedCommandResponse := &model.CommandResponse{
   853  		Text:         "test post command response",
   854  		ResponseType: model.COMMAND_RESPONSE_TYPE_IN_CHANNEL,
   855  		Type:         "custom_test",
   856  		Props:        map[string]interface{}{"someprop": "somevalue"},
   857  	}
   858  
   859  	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   860  		w.Header().Set("Content-Type", "application/json")
   861  		w.Write([]byte(expectedCommandResponse.ToJson()))
   862  	}))
   863  	defer ts.Close()
   864  
   865  	// create a slash command on some other team where we have permission to do so
   866  	team2 := th.CreateTeam()
   867  	postCmd := &model.Command{
   868  		CreatorId: th.BasicUser.Id,
   869  		TeamId:    team2.Id,
   870  		URL:       ts.URL,
   871  		Method:    model.COMMAND_METHOD_POST,
   872  		Trigger:   "postcommand",
   873  	}
   874  	_, err := th.App.CreateCommand(postCmd)
   875  	require.Nil(t, err, "failed to create post command")
   876  
   877  	// make a channel on that team, ensuring that our test user isn't in it
   878  	channel2 := th.CreateChannelWithClientAndTeam(client, model.CHANNEL_OPEN, team2.Id)
   879  	success, _ := client.RemoveUserFromChannel(channel2.Id, th.BasicUser.Id)
   880  	require.True(t, success, "Failed to remove user from channel")
   881  
   882  	// we should not be able to run the slash command in channel2, because we aren't in it
   883  	_, resp := client.ExecuteCommandWithTeam(channel2.Id, team2.Id, "/postcommand")
   884  	CheckForbiddenStatus(t, resp)
   885  }
   886  
   887  func TestExecuteCommandInDirectMessageChannel(t *testing.T) {
   888  	th := Setup(t).InitBasic()
   889  	defer th.TearDown()
   890  	client := th.Client
   891  
   892  	enableCommands := *th.App.Config().ServiceSettings.EnableCommands
   893  	allowedInternalConnections := *th.App.Config().ServiceSettings.AllowedUntrustedInternalConnections
   894  	defer func() {
   895  		th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableCommands = &enableCommands })
   896  		th.App.UpdateConfig(func(cfg *model.Config) {
   897  			cfg.ServiceSettings.AllowedUntrustedInternalConnections = &allowedInternalConnections
   898  		})
   899  	}()
   900  	th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableCommands = true })
   901  	th.App.UpdateConfig(func(cfg *model.Config) {
   902  		*cfg.ServiceSettings.AllowedUntrustedInternalConnections = "localhost,127.0.0.1"
   903  	})
   904  
   905  	// create a team that the user isn't a part of
   906  	team2 := th.CreateTeam()
   907  
   908  	expectedCommandResponse := &model.CommandResponse{
   909  		Text:         "test post command response",
   910  		ResponseType: model.COMMAND_RESPONSE_TYPE_IN_CHANNEL,
   911  		Type:         "custom_test",
   912  		Props:        map[string]interface{}{"someprop": "somevalue"},
   913  	}
   914  
   915  	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   916  		require.Equal(t, http.MethodPost, r.Method)
   917  		w.Header().Set("Content-Type", "application/json")
   918  		w.Write([]byte(expectedCommandResponse.ToJson()))
   919  	}))
   920  	defer ts.Close()
   921  
   922  	// create a slash command on some other team where we have permission to do so
   923  	postCmd := &model.Command{
   924  		CreatorId: th.BasicUser.Id,
   925  		TeamId:    team2.Id,
   926  		URL:       ts.URL,
   927  		Method:    model.COMMAND_METHOD_POST,
   928  		Trigger:   "postcommand",
   929  	}
   930  	_, err := th.App.CreateCommand(postCmd)
   931  	require.Nil(t, err, "failed to create post command")
   932  
   933  	// make a direct message channel
   934  	dmChannel, response := client.CreateDirectChannel(th.BasicUser.Id, th.BasicUser2.Id)
   935  	CheckCreatedStatus(t, response)
   936  
   937  	// we should be able to run the slash command in the DM channel
   938  	_, resp := client.ExecuteCommandWithTeam(dmChannel.Id, team2.Id, "/postcommand")
   939  	CheckOKStatus(t, resp)
   940  
   941  	// but we can't run the slash command in the DM channel if we sub in some other team's id
   942  	_, resp = client.ExecuteCommandWithTeam(dmChannel.Id, th.BasicTeam.Id, "/postcommand")
   943  	CheckNotFoundStatus(t, resp)
   944  }
   945  
   946  func TestExecuteCommandInTeamUserIsNotOn(t *testing.T) {
   947  	th := Setup(t).InitBasic()
   948  	defer th.TearDown()
   949  	client := th.Client
   950  
   951  	enableCommands := *th.App.Config().ServiceSettings.EnableCommands
   952  	allowedInternalConnections := *th.App.Config().ServiceSettings.AllowedUntrustedInternalConnections
   953  	defer func() {
   954  		th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableCommands = &enableCommands })
   955  		th.App.UpdateConfig(func(cfg *model.Config) {
   956  			cfg.ServiceSettings.AllowedUntrustedInternalConnections = &allowedInternalConnections
   957  		})
   958  	}()
   959  	th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableCommands = true })
   960  	th.App.UpdateConfig(func(cfg *model.Config) {
   961  		*cfg.ServiceSettings.AllowedUntrustedInternalConnections = "localhost,127.0.0.1"
   962  	})
   963  
   964  	// create a team that the user isn't a part of
   965  	team2 := th.CreateTeam()
   966  
   967  	expectedCommandResponse := &model.CommandResponse{
   968  		Text:         "test post command response",
   969  		ResponseType: model.COMMAND_RESPONSE_TYPE_IN_CHANNEL,
   970  		Type:         "custom_test",
   971  		Props:        map[string]interface{}{"someprop": "somevalue"},
   972  	}
   973  
   974  	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   975  		require.Equal(t, http.MethodPost, r.Method)
   976  		r.ParseForm()
   977  		require.Equal(t, team2.Name, r.FormValue("team_domain"))
   978  
   979  		w.Header().Set("Content-Type", "application/json")
   980  		w.Write([]byte(expectedCommandResponse.ToJson()))
   981  	}))
   982  	defer ts.Close()
   983  
   984  	// create a slash command on that team
   985  	postCmd := &model.Command{
   986  		CreatorId: th.BasicUser.Id,
   987  		TeamId:    team2.Id,
   988  		URL:       ts.URL,
   989  		Method:    model.COMMAND_METHOD_POST,
   990  		Trigger:   "postcommand",
   991  	}
   992  	_, err := th.App.CreateCommand(postCmd)
   993  	require.Nil(t, err, "failed to create post command")
   994  
   995  	// make a direct message channel
   996  	dmChannel, response := client.CreateDirectChannel(th.BasicUser.Id, th.BasicUser2.Id)
   997  	CheckCreatedStatus(t, response)
   998  
   999  	// we should be able to run the slash command in the DM channel
  1000  	_, resp := client.ExecuteCommandWithTeam(dmChannel.Id, team2.Id, "/postcommand")
  1001  	CheckOKStatus(t, resp)
  1002  
  1003  	// if the user is removed from the team, they should NOT be able to run the slash command in the DM channel
  1004  	success, _ := client.RemoveTeamMember(team2.Id, th.BasicUser.Id)
  1005  	require.True(t, success, "Failed to remove user from team")
  1006  
  1007  	_, resp = client.ExecuteCommandWithTeam(dmChannel.Id, team2.Id, "/postcommand")
  1008  	CheckForbiddenStatus(t, resp)
  1009  
  1010  	// if we omit the team id from the request, the slash command will fail because this is a DM channel, and the
  1011  	// team id can't be inherited from the channel
  1012  	_, resp = client.ExecuteCommand(dmChannel.Id, "/postcommand")
  1013  	CheckForbiddenStatus(t, resp)
  1014  }