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 }