github.com/crspeller/mattermost-server@v0.0.0-20190328001957-a200beb3d111/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/assert" 13 "github.com/stretchr/testify/require" 14 15 "github.com/crspeller/mattermost-server/model" 16 ) 17 18 func TestCreateCommand(t *testing.T) { 19 th := Setup().InitBasic() 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() 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() 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() 218 defer th.TearDown() 219 Client := th.Client 220 221 enableCommands := *th.App.Config().ServiceSettings.EnableCommands 222 defer func() { 223 th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableCommands = &enableCommands }) 224 }() 225 th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableCommands = true }) 226 227 newCmd := &model.Command{ 228 CreatorId: th.BasicUser.Id, 229 TeamId: th.BasicTeam.Id, 230 URL: "http://nowhere.com", 231 Method: model.COMMAND_METHOD_POST, 232 Trigger: "custom_command"} 233 234 _, resp := th.SystemAdminClient.CreateCommand(newCmd) 235 CheckNoError(t, resp) 236 237 t.Run("ListSystemAndCustomCommands", func(t *testing.T) { 238 listCommands, resp := th.SystemAdminClient.ListCommands(th.BasicTeam.Id, false) 239 CheckNoError(t, resp) 240 241 foundEcho := false 242 foundCustom := false 243 for _, command := range listCommands { 244 if command.Trigger == "echo" { 245 foundEcho = true 246 } 247 if command.Trigger == "custom_command" { 248 foundCustom = true 249 } 250 } 251 if !foundEcho { 252 t.Fatal("Couldn't find echo command") 253 } 254 if !foundCustom { 255 t.Fatal("Should list the custom command") 256 } 257 }) 258 259 t.Run("ListCustomOnlyCommands", func(t *testing.T) { 260 listCommands, resp := th.SystemAdminClient.ListCommands(th.BasicTeam.Id, true) 261 CheckNoError(t, resp) 262 263 if len(listCommands) > 1 { 264 t.Fatal("Should list just one custom command") 265 } 266 if listCommands[0].Trigger != "custom_command" { 267 t.Fatal("Wrong custom command trigger") 268 } 269 }) 270 271 t.Run("UserWithNoPermissionForCustomCommands", func(t *testing.T) { 272 _, resp := Client.ListCommands(th.BasicTeam.Id, true) 273 CheckForbiddenStatus(t, resp) 274 }) 275 276 t.Run("RegularUserCanListOnlySystemCommands", func(t *testing.T) { 277 listCommands, resp := Client.ListCommands(th.BasicTeam.Id, false) 278 CheckNoError(t, resp) 279 280 foundEcho := false 281 foundCustom := false 282 for _, command := range listCommands { 283 if command.Trigger == "echo" { 284 foundEcho = true 285 } 286 if command.Trigger == "custom_command" { 287 foundCustom = true 288 } 289 } 290 if !foundEcho { 291 t.Fatal("Couldn't find echo command") 292 } 293 if foundCustom { 294 t.Fatal("Should not list the custom command") 295 } 296 }) 297 } 298 299 func TestListAutocompleteCommands(t *testing.T) { 300 th := Setup().InitBasic() 301 defer th.TearDown() 302 Client := th.Client 303 304 newCmd := &model.Command{ 305 CreatorId: th.BasicUser.Id, 306 TeamId: th.BasicTeam.Id, 307 URL: "http://nowhere.com", 308 Method: model.COMMAND_METHOD_POST, 309 Trigger: "custom_command"} 310 311 _, resp := th.SystemAdminClient.CreateCommand(newCmd) 312 CheckNoError(t, resp) 313 314 t.Run("ListAutocompleteCommandsOnly", func(t *testing.T) { 315 listCommands, resp := th.SystemAdminClient.ListAutocompleteCommands(th.BasicTeam.Id) 316 CheckNoError(t, resp) 317 318 foundEcho := false 319 foundCustom := false 320 for _, command := range listCommands { 321 if command.Trigger == "echo" { 322 foundEcho = true 323 } 324 if command.Trigger == "custom_command" { 325 foundCustom = true 326 } 327 } 328 if !foundEcho { 329 t.Fatal("Couldn't find echo command") 330 } 331 if foundCustom { 332 t.Fatal("Should not list the custom command") 333 } 334 }) 335 336 t.Run("RegularUserCanListOnlySystemCommands", func(t *testing.T) { 337 listCommands, resp := Client.ListAutocompleteCommands(th.BasicTeam.Id) 338 CheckNoError(t, resp) 339 340 foundEcho := false 341 foundCustom := false 342 for _, command := range listCommands { 343 if command.Trigger == "echo" { 344 foundEcho = true 345 } 346 if command.Trigger == "custom_command" { 347 foundCustom = true 348 } 349 } 350 if !foundEcho { 351 t.Fatal("Couldn't find echo command") 352 } 353 if foundCustom { 354 t.Fatal("Should not list the custom command") 355 } 356 }) 357 } 358 359 func TestRegenToken(t *testing.T) { 360 th := Setup().InitBasic() 361 defer th.TearDown() 362 Client := th.Client 363 364 enableCommands := *th.App.Config().ServiceSettings.EnableCommands 365 defer func() { 366 th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableCommands = &enableCommands }) 367 }() 368 th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableCommands = true }) 369 370 newCmd := &model.Command{ 371 CreatorId: th.BasicUser.Id, 372 TeamId: th.BasicTeam.Id, 373 URL: "http://nowhere.com", 374 Method: model.COMMAND_METHOD_POST, 375 Trigger: "trigger"} 376 377 createdCmd, resp := th.SystemAdminClient.CreateCommand(newCmd) 378 CheckNoError(t, resp) 379 CheckCreatedStatus(t, resp) 380 381 token, resp := th.SystemAdminClient.RegenCommandToken(createdCmd.Id) 382 CheckNoError(t, resp) 383 if token == createdCmd.Token { 384 t.Fatal("should update the token") 385 } 386 387 token, resp = Client.RegenCommandToken(createdCmd.Id) 388 CheckForbiddenStatus(t, resp) 389 if token != "" { 390 t.Fatal("should not return the token") 391 } 392 } 393 394 func TestExecuteInvalidCommand(t *testing.T) { 395 th := Setup().InitBasic() 396 defer th.TearDown() 397 Client := th.Client 398 channel := th.BasicChannel 399 400 enableCommands := *th.App.Config().ServiceSettings.EnableCommands 401 allowedInternalConnections := *th.App.Config().ServiceSettings.AllowedUntrustedInternalConnections 402 defer func() { 403 th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableCommands = &enableCommands }) 404 th.App.UpdateConfig(func(cfg *model.Config) { 405 cfg.ServiceSettings.AllowedUntrustedInternalConnections = &allowedInternalConnections 406 }) 407 }() 408 th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableCommands = true }) 409 th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.AllowedUntrustedInternalConnections = "127.0.0.0/8" }) 410 411 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 412 rc := &model.CommandResponse{} 413 414 w.Write([]byte(rc.ToJson())) 415 })) 416 defer ts.Close() 417 418 getCmd := &model.Command{ 419 CreatorId: th.BasicUser.Id, 420 TeamId: th.BasicTeam.Id, 421 URL: ts.URL, 422 Method: model.COMMAND_METHOD_GET, 423 Trigger: "getcommand", 424 } 425 426 if _, err := th.App.CreateCommand(getCmd); err != nil { 427 t.Fatal("failed to create get command") 428 } 429 430 _, resp := Client.ExecuteCommand(channel.Id, "") 431 CheckBadRequestStatus(t, resp) 432 433 _, resp = Client.ExecuteCommand(channel.Id, "/") 434 CheckBadRequestStatus(t, resp) 435 436 _, resp = Client.ExecuteCommand(channel.Id, "getcommand") 437 CheckBadRequestStatus(t, resp) 438 439 _, resp = Client.ExecuteCommand(channel.Id, "/junk") 440 CheckNotFoundStatus(t, resp) 441 442 otherUser := th.CreateUser() 443 Client.Login(otherUser.Email, otherUser.Password) 444 445 _, resp = Client.ExecuteCommand(channel.Id, "/getcommand") 446 CheckForbiddenStatus(t, resp) 447 448 Client.Logout() 449 450 _, resp = Client.ExecuteCommand(channel.Id, "/getcommand") 451 CheckUnauthorizedStatus(t, resp) 452 453 _, resp = th.SystemAdminClient.ExecuteCommand(channel.Id, "/getcommand") 454 CheckNoError(t, resp) 455 } 456 457 func TestExecuteGetCommand(t *testing.T) { 458 th := Setup().InitBasic() 459 defer th.TearDown() 460 Client := th.Client 461 channel := th.BasicChannel 462 463 enableCommands := *th.App.Config().ServiceSettings.EnableCommands 464 allowedInternalConnections := *th.App.Config().ServiceSettings.AllowedUntrustedInternalConnections 465 defer func() { 466 th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableCommands = &enableCommands }) 467 th.App.UpdateConfig(func(cfg *model.Config) { 468 cfg.ServiceSettings.AllowedUntrustedInternalConnections = &allowedInternalConnections 469 }) 470 }() 471 th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableCommands = true }) 472 th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.AllowedUntrustedInternalConnections = "127.0.0.0/8" }) 473 474 token := model.NewId() 475 expectedCommandResponse := &model.CommandResponse{ 476 Text: "test get command response", 477 ResponseType: model.COMMAND_RESPONSE_TYPE_IN_CHANNEL, 478 Type: "custom_test", 479 Props: map[string]interface{}{"someprop": "somevalue"}, 480 } 481 482 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 483 require.Equal(t, http.MethodGet, r.Method) 484 485 values, err := url.ParseQuery(r.URL.RawQuery) 486 require.NoError(t, err) 487 488 require.Equal(t, token, values.Get("token")) 489 require.Equal(t, th.BasicTeam.Name, values.Get("team_domain")) 490 require.Equal(t, "ourCommand", values.Get("cmd")) 491 492 w.Header().Set("Content-Type", "application/json") 493 w.Write([]byte(expectedCommandResponse.ToJson())) 494 })) 495 defer ts.Close() 496 497 getCmd := &model.Command{ 498 CreatorId: th.BasicUser.Id, 499 TeamId: th.BasicTeam.Id, 500 URL: ts.URL + "/?cmd=ourCommand", 501 Method: model.COMMAND_METHOD_GET, 502 Trigger: "getcommand", 503 Token: token, 504 } 505 506 if _, err := th.App.CreateCommand(getCmd); err != nil { 507 t.Fatal("failed to create get command") 508 } 509 510 commandResponse, resp := Client.ExecuteCommand(channel.Id, "/getcommand") 511 CheckNoError(t, resp) 512 assert.True(t, len(commandResponse.TriggerId) == 26) 513 514 expectedCommandResponse.TriggerId = commandResponse.TriggerId 515 expectedCommandResponse.Props["from_webhook"] = "true" 516 require.Equal(t, expectedCommandResponse, commandResponse) 517 } 518 519 func TestExecutePostCommand(t *testing.T) { 520 th := Setup().InitBasic() 521 defer th.TearDown() 522 Client := th.Client 523 channel := th.BasicChannel 524 525 enableCommands := *th.App.Config().ServiceSettings.EnableCommands 526 allowedInternalConnections := *th.App.Config().ServiceSettings.AllowedUntrustedInternalConnections 527 defer func() { 528 th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableCommands = &enableCommands }) 529 th.App.UpdateConfig(func(cfg *model.Config) { 530 cfg.ServiceSettings.AllowedUntrustedInternalConnections = &allowedInternalConnections 531 }) 532 }() 533 th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableCommands = true }) 534 th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.AllowedUntrustedInternalConnections = "127.0.0.0/8" }) 535 536 token := model.NewId() 537 expectedCommandResponse := &model.CommandResponse{ 538 Text: "test post command response", 539 ResponseType: model.COMMAND_RESPONSE_TYPE_IN_CHANNEL, 540 Type: "custom_test", 541 Props: map[string]interface{}{"someprop": "somevalue"}, 542 } 543 544 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 545 require.Equal(t, http.MethodPost, r.Method) 546 547 r.ParseForm() 548 549 require.Equal(t, token, r.FormValue("token")) 550 require.Equal(t, th.BasicTeam.Name, r.FormValue("team_domain")) 551 552 w.Header().Set("Content-Type", "application/json") 553 w.Write([]byte(expectedCommandResponse.ToJson())) 554 })) 555 defer ts.Close() 556 557 postCmd := &model.Command{ 558 CreatorId: th.BasicUser.Id, 559 TeamId: th.BasicTeam.Id, 560 URL: ts.URL, 561 Method: model.COMMAND_METHOD_POST, 562 Trigger: "postcommand", 563 Token: token, 564 } 565 566 if _, err := th.App.CreateCommand(postCmd); err != nil { 567 t.Fatal("failed to create get command") 568 } 569 570 commandResponse, resp := Client.ExecuteCommand(channel.Id, "/postcommand") 571 CheckNoError(t, resp) 572 assert.True(t, len(commandResponse.TriggerId) == 26) 573 574 expectedCommandResponse.TriggerId = commandResponse.TriggerId 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 }