github.com/psyb0t/mattermost-server@v4.6.1-0.20180125161845-5503a1351abf+incompatible/api/webhook_test.go (about) 1 // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. 2 // See License.txt for license information. 3 4 package api 5 6 import ( 7 "fmt" 8 "net/http" 9 "testing" 10 11 "github.com/mattermost/mattermost-server/model" 12 "github.com/mattermost/mattermost-server/utils" 13 ) 14 15 func TestCreateIncomingHook(t *testing.T) { 16 th := Setup().InitSystemAdmin() 17 defer th.TearDown() 18 19 Client := th.SystemAdminClient 20 user := th.SystemAdminUser 21 team := th.SystemAdminTeam 22 channel1 := th.CreateChannel(Client, team) 23 channel2 := th.CreatePrivateChannel(Client, team) 24 channel3 := th.CreateChannel(Client, team) 25 user2 := th.CreateUser(Client) 26 th.LinkUserToTeam(user2, team) 27 28 th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableIncomingWebhooks = true }) 29 th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableOnlyAdminIntegrations = true }) 30 31 hook := &model.IncomingWebhook{ChannelId: channel1.Id} 32 33 var rhook *model.IncomingWebhook 34 if result, err := Client.CreateIncomingWebhook(hook); err != nil { 35 t.Fatal(err) 36 } else { 37 rhook = result.Data.(*model.IncomingWebhook) 38 } 39 40 if hook.ChannelId != rhook.ChannelId { 41 t.Fatal("channel ids didn't match") 42 } 43 44 if rhook.UserId != user.Id { 45 t.Fatal("user ids didn't match") 46 } 47 48 if rhook.TeamId != team.Id { 49 t.Fatal("team ids didn't match") 50 } 51 52 hook = &model.IncomingWebhook{ChannelId: "junk"} 53 if _, err := Client.CreateIncomingWebhook(hook); err == nil { 54 t.Fatal("should have failed - bad channel id") 55 } 56 57 hook = &model.IncomingWebhook{ChannelId: channel2.Id, UserId: "123", TeamId: "456"} 58 if result, err := Client.CreateIncomingWebhook(hook); err != nil { 59 t.Fatal(err) 60 } else { 61 if result.Data.(*model.IncomingWebhook).UserId != user.Id { 62 t.Fatal("bad user id wasn't overwritten") 63 } 64 if result.Data.(*model.IncomingWebhook).TeamId != team.Id { 65 t.Fatal("bad team id wasn't overwritten") 66 } 67 } 68 69 Client.Must(Client.LeaveChannel(channel3.Id)) 70 71 hook = &model.IncomingWebhook{ChannelId: channel3.Id, UserId: user.Id, TeamId: team.Id} 72 if _, err := Client.CreateIncomingWebhook(hook); err != nil { 73 t.Fatal(err) 74 } 75 76 Client.Logout() 77 Client.Must(Client.LoginById(user2.Id, user2.Password)) 78 Client.SetTeamId(team.Id) 79 80 hook = &model.IncomingWebhook{ChannelId: channel1.Id} 81 82 if _, err := Client.CreateIncomingWebhook(hook); err == nil { 83 t.Fatal("should have failed - not system/team admin") 84 } 85 86 Client.Logout() 87 th.UpdateUserToTeamAdmin(user2, team) 88 Client.Must(Client.LoginById(user2.Id, user2.Password)) 89 Client.SetTeamId(team.Id) 90 91 if _, err := Client.CreateIncomingWebhook(hook); err != nil { 92 t.Fatal(err) 93 } 94 95 th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableOnlyAdminIntegrations = false }) 96 th.App.SetDefaultRolesBasedOnConfig() 97 98 if _, err := Client.CreateIncomingWebhook(hook); err != nil { 99 t.Fatal(err) 100 } 101 102 hook = &model.IncomingWebhook{ChannelId: channel2.Id} 103 104 if _, err := Client.CreateIncomingWebhook(hook); err == nil { 105 t.Fatal("should have failed - channel is private and not a member") 106 } 107 108 th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableIncomingWebhooks = false }) 109 110 if _, err := Client.CreateIncomingWebhook(hook); err == nil { 111 t.Fatal("should have errored - webhooks turned off") 112 } 113 } 114 115 func TestUpdateIncomingHook(t *testing.T) { 116 th := Setup().InitSystemAdmin() 117 defer th.TearDown() 118 119 Client := th.SystemAdminClient 120 team := th.SystemAdminTeam 121 122 channel1 := th.CreateChannel(Client, team) 123 channel2 := th.CreatePrivateChannel(Client, team) 124 channel3 := th.CreateChannel(Client, team) 125 126 user2 := th.CreateUser(Client) 127 th.LinkUserToTeam(user2, team) 128 129 team2 := th.CreateTeam(Client) 130 user3 := th.CreateUser(Client) 131 th.LinkUserToTeam(user3, team2) 132 th.UpdateUserToTeamAdmin(user3, team2) 133 134 th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableIncomingWebhooks = true }) 135 th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableOnlyAdminIntegrations = true }) 136 th.App.SetDefaultRolesBasedOnConfig() 137 138 hook := createIncomingWebhook(channel1.Id, Client, t) 139 140 t.Run("UpdateIncomingHook", func(t *testing.T) { 141 hook.DisplayName = "hook2" 142 hook.Description = "description" 143 hook.ChannelId = channel3.Id 144 145 if result, err := Client.UpdateIncomingWebhook(hook); err != nil { 146 t.Fatal("Update hook should not fail") 147 } else { 148 updatedHook := result.Data.(*model.IncomingWebhook) 149 150 if updatedHook.DisplayName != "hook2" { 151 t.Fatal("Hook name is not updated") 152 } 153 154 if updatedHook.Description != "description" { 155 t.Fatal("Hook description is not updated") 156 } 157 158 if updatedHook.ChannelId != channel3.Id { 159 t.Fatal("Hook channel is not updated") 160 } 161 } 162 }) 163 164 t.Run("RetainCreateAt", func(t *testing.T) { 165 hook2 := &model.IncomingWebhook{ChannelId: channel1.Id, CreateAt: 100} 166 167 if result, err := Client.CreateIncomingWebhook(hook2); err != nil { 168 t.Fatal("hook creation failed") 169 } else { 170 createdHook := result.Data.(*model.IncomingWebhook) 171 createdHook.DisplayName = "Name2" 172 173 if result, err := Client.UpdateIncomingWebhook(createdHook); err != nil { 174 t.Fatal("Update hook should not fail") 175 } else { 176 updatedHook := result.Data.(*model.IncomingWebhook) 177 178 if updatedHook.CreateAt != createdHook.CreateAt { 179 t.Fatal("failed - hook create at should not be changed") 180 } 181 } 182 } 183 }) 184 185 t.Run("ModifyUpdateAt", func(t *testing.T) { 186 hook.DisplayName = "Name3" 187 188 if result, err := Client.UpdateIncomingWebhook(hook); err != nil { 189 t.Fatal("Update hook should not fail") 190 } else { 191 updatedHook := result.Data.(*model.IncomingWebhook) 192 193 if updatedHook.UpdateAt == hook.UpdateAt { 194 t.Fatal("failed - hook updateAt is not updated") 195 } 196 } 197 }) 198 199 t.Run("UpdateNonExistentHook", func(t *testing.T) { 200 nonExistentHook := &model.IncomingWebhook{ChannelId: channel1.Id} 201 202 if _, err := Client.UpdateIncomingWebhook(nonExistentHook); err == nil { 203 t.Fatal("should have failed - update a non-existent hook") 204 } 205 }) 206 207 Client.Logout() 208 Client.Must(Client.LoginById(user2.Id, user2.Password)) 209 Client.SetTeamId(team.Id) 210 t.Run("UserIsNotAdminOfTeam", func(t *testing.T) { 211 if _, err := Client.UpdateIncomingWebhook(hook); err == nil { 212 t.Fatal("should have failed - user is not admin of team") 213 } 214 }) 215 216 th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableIncomingWebhooks = true }) 217 218 t.Run("OnlyAdminIntegrationsDisabled", func(t *testing.T) { 219 th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableOnlyAdminIntegrations = false }) 220 th.App.SetDefaultRolesBasedOnConfig() 221 222 t.Run("UpdateHookOfSameUser", func(t *testing.T) { 223 sameUserHook := &model.IncomingWebhook{ChannelId: channel1.Id, UserId: user2.Id} 224 if result, err := Client.CreateIncomingWebhook(sameUserHook); err != nil { 225 t.Fatal("Hook creation failed") 226 } else { 227 sameUserHook = result.Data.(*model.IncomingWebhook) 228 } 229 230 if _, err := Client.UpdateIncomingWebhook(sameUserHook); err != nil { 231 t.Fatal("should not fail - only admin integrations are disabled & hook of same user") 232 } 233 }) 234 235 t.Run("UpdateHookOfDifferentUser", func(t *testing.T) { 236 if _, err := Client.UpdateIncomingWebhook(hook); err == nil { 237 t.Fatal("should have failed - user does not have permissions to update other user's hooks") 238 } 239 }) 240 }) 241 242 th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableOnlyAdminIntegrations = true }) 243 th.App.SetDefaultRolesBasedOnConfig() 244 245 Client.Logout() 246 th.UpdateUserToTeamAdmin(user2, team) 247 Client.Must(Client.LoginById(user2.Id, user2.Password)) 248 Client.SetTeamId(team.Id) 249 t.Run("UpdateByDifferentUser", func(t *testing.T) { 250 if result, err := Client.UpdateIncomingWebhook(hook); err != nil { 251 t.Fatal("Update hook should not fail") 252 } else { 253 updatedHook := result.Data.(*model.IncomingWebhook) 254 255 if updatedHook.UserId == user2.Id { 256 t.Fatal("Hook's creator userId is not retained") 257 } 258 } 259 }) 260 261 t.Run("IncomingHooksDisabled", func(t *testing.T) { 262 th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableIncomingWebhooks = false }) 263 if _, err := Client.UpdateIncomingWebhook(hook); err == nil { 264 t.Fatal("should have failed - incoming hooks are disabled") 265 } 266 }) 267 268 t.Run("PrivateChannel", func(t *testing.T) { 269 hook.ChannelId = channel2.Id 270 271 if _, err := Client.UpdateIncomingWebhook(hook); err == nil { 272 t.Fatal("should have failed - updating to a private channel where the user is not a member") 273 } 274 }) 275 276 t.Run("UpdateToNonExistentChannel", func(t *testing.T) { 277 hook.ChannelId = "junk" 278 if _, err := Client.UpdateIncomingWebhook(hook); err == nil { 279 t.Fatal("should have failed - bad channel id") 280 } 281 }) 282 283 Client.Logout() 284 Client.Must(Client.LoginById(user3.Id, user3.Password)) 285 Client.SetTeamId(team2.Id) 286 t.Run("UpdateToADifferentTeam", func(t *testing.T) { 287 if _, err := Client.UpdateIncomingWebhook(hook); err == nil { 288 t.Fatal("should have failed - update to a different team is not allowed") 289 } 290 }) 291 } 292 293 func createIncomingWebhook(channelID string, Client *model.Client, t *testing.T) *model.IncomingWebhook { 294 hook := &model.IncomingWebhook{ChannelId: channelID} 295 if result, err := Client.CreateIncomingWebhook(hook); err != nil { 296 t.Fatal("Hook creation failed") 297 } else { 298 hook = result.Data.(*model.IncomingWebhook) 299 } 300 301 return hook 302 } 303 304 func createOutgoingWebhook(channelID string, callbackURLs []string, triggerWords []string, Client *model.Client, t *testing.T) *model.OutgoingWebhook { 305 hook := &model.OutgoingWebhook{ChannelId: channelID, CallbackURLs: callbackURLs, TriggerWords: triggerWords} 306 if result, err := Client.CreateOutgoingWebhook(hook); err != nil { 307 t.Fatal("Hook creation failed") 308 } else { 309 hook = result.Data.(*model.OutgoingWebhook) 310 } 311 312 return hook 313 } 314 315 func TestListIncomingHooks(t *testing.T) { 316 th := Setup().InitSystemAdmin() 317 defer th.TearDown() 318 319 Client := th.SystemAdminClient 320 team := th.SystemAdminTeam 321 channel1 := th.CreateChannel(Client, team) 322 user2 := th.CreateUser(Client) 323 th.LinkUserToTeam(user2, team) 324 325 th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableIncomingWebhooks = true }) 326 th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableOnlyAdminIntegrations = true }) 327 th.App.SetDefaultRolesBasedOnConfig() 328 329 hook1 := &model.IncomingWebhook{ChannelId: channel1.Id} 330 hook1 = Client.Must(Client.CreateIncomingWebhook(hook1)).Data.(*model.IncomingWebhook) 331 332 hook2 := &model.IncomingWebhook{ChannelId: channel1.Id} 333 hook2 = Client.Must(Client.CreateIncomingWebhook(hook2)).Data.(*model.IncomingWebhook) 334 335 if result, err := Client.ListIncomingWebhooks(); err != nil { 336 t.Fatal(err) 337 } else { 338 hooks := result.Data.([]*model.IncomingWebhook) 339 340 if len(hooks) != 2 { 341 t.Fatal("incorrect number of hooks") 342 } 343 } 344 345 Client.Logout() 346 Client.Must(Client.LoginById(user2.Id, user2.Password)) 347 Client.SetTeamId(team.Id) 348 349 if _, err := Client.ListIncomingWebhooks(); err == nil { 350 t.Fatal("should have errored - not system/team admin") 351 } 352 353 th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableOnlyAdminIntegrations = false }) 354 th.App.SetDefaultRolesBasedOnConfig() 355 356 if _, err := Client.ListIncomingWebhooks(); err != nil { 357 t.Fatal(err) 358 } 359 360 th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableIncomingWebhooks = false }) 361 362 if _, err := Client.ListIncomingWebhooks(); err == nil { 363 t.Fatal("should have errored - webhooks turned off") 364 } 365 } 366 367 func TestDeleteIncomingHook(t *testing.T) { 368 th := Setup().InitSystemAdmin() 369 defer th.TearDown() 370 371 Client := th.SystemAdminClient 372 team := th.SystemAdminTeam 373 channel1 := th.CreateChannel(Client, team) 374 user2 := th.CreateUser(Client) 375 th.LinkUserToTeam(user2, team) 376 377 th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableIncomingWebhooks = true }) 378 th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableOnlyAdminIntegrations = true }) 379 th.App.SetDefaultRolesBasedOnConfig() 380 381 hook := &model.IncomingWebhook{ChannelId: channel1.Id} 382 hook = Client.Must(Client.CreateIncomingWebhook(hook)).Data.(*model.IncomingWebhook) 383 384 if _, err := Client.DeleteIncomingWebhook(hook.Id); err != nil { 385 t.Fatal(err) 386 } 387 388 if _, err := Client.DeleteIncomingWebhook("junk"); err == nil { 389 t.Fatal("should have failed - bad id") 390 } 391 392 if _, err := Client.DeleteIncomingWebhook(""); err == nil { 393 t.Fatal("should have failed - empty id") 394 } 395 396 hooks := Client.Must(Client.ListIncomingWebhooks()).Data.([]*model.IncomingWebhook) 397 if len(hooks) != 0 { 398 t.Fatal("delete didn't work properly") 399 } 400 401 hook = &model.IncomingWebhook{ChannelId: channel1.Id} 402 hook = Client.Must(Client.CreateIncomingWebhook(hook)).Data.(*model.IncomingWebhook) 403 404 Client.Logout() 405 Client.Must(Client.LoginById(user2.Id, user2.Password)) 406 Client.SetTeamId(team.Id) 407 408 if _, err := Client.DeleteIncomingWebhook(hook.Id); err == nil { 409 t.Fatal("should have failed - not system/team admin") 410 } 411 412 th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableOnlyAdminIntegrations = false }) 413 th.App.SetDefaultRolesBasedOnConfig() 414 415 if _, err := Client.DeleteIncomingWebhook(hook.Id); err == nil { 416 t.Fatal("should have failed - not creator or team admin") 417 } 418 419 hook = &model.IncomingWebhook{ChannelId: channel1.Id} 420 hook = Client.Must(Client.CreateIncomingWebhook(hook)).Data.(*model.IncomingWebhook) 421 422 if _, err := Client.DeleteIncomingWebhook(hook.Id); err != nil { 423 t.Fatal(err) 424 } 425 426 th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableIncomingWebhooks = false }) 427 428 if _, err := Client.DeleteIncomingWebhook(hook.Id); err == nil { 429 t.Fatal("should have errored - webhooks turned off") 430 } 431 } 432 433 func TestCreateOutgoingHook(t *testing.T) { 434 th := Setup().InitSystemAdmin() 435 defer th.TearDown() 436 437 Client := th.SystemAdminClient 438 user := th.SystemAdminUser 439 team := th.SystemAdminTeam 440 team2 := th.CreateTeam(Client) 441 channel1 := th.CreateChannel(Client, team) 442 channel2 := th.CreatePrivateChannel(Client, team) 443 user2 := th.CreateUser(Client) 444 th.LinkUserToTeam(user2, team) 445 user3 := th.CreateUser(Client) 446 th.LinkUserToTeam(user3, team2) 447 448 th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOutgoingWebhooks = true }) 449 th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableOnlyAdminIntegrations = true }) 450 th.App.SetDefaultRolesBasedOnConfig() 451 452 hook := &model.OutgoingWebhook{ChannelId: channel1.Id, CallbackURLs: []string{"http://nowhere.com"}} 453 454 var rhook *model.OutgoingWebhook 455 if result, err := Client.CreateOutgoingWebhook(hook); err != nil { 456 t.Fatal(err) 457 } else { 458 rhook = result.Data.(*model.OutgoingWebhook) 459 } 460 461 if hook.ChannelId != rhook.ChannelId { 462 t.Fatal("channel ids didn't match") 463 } 464 465 if rhook.CreatorId != user.Id { 466 t.Fatal("user ids didn't match") 467 } 468 469 if rhook.TeamId != team.Id { 470 t.Fatal("team ids didn't match") 471 } 472 473 hook = &model.OutgoingWebhook{ChannelId: channel1.Id, TriggerWords: []string{"cats", "dogs"}, CallbackURLs: []string{"http://nowhere.com", "http://cats.com"}} 474 hook1 := &model.OutgoingWebhook{ChannelId: channel1.Id, TriggerWords: []string{"cats"}, CallbackURLs: []string{"http://nowhere.com"}} 475 476 if _, err := Client.CreateOutgoingWebhook(hook); err != nil { 477 t.Fatal("multiple trigger words and urls failed") 478 } 479 480 if _, err := Client.CreateOutgoingWebhook(hook1); err == nil { 481 t.Fatal("should have failed - duplicate trigger words and urls") 482 } 483 484 hook = &model.OutgoingWebhook{ChannelId: "junk", CallbackURLs: []string{"http://nowhere.com"}} 485 if _, err := Client.CreateOutgoingWebhook(hook); err == nil { 486 t.Fatal("should have failed - bad channel id") 487 } 488 489 hook = &model.OutgoingWebhook{ChannelId: channel1.Id, CreatorId: "123", TeamId: "456", CallbackURLs: []string{"http://nowhere.com"}} 490 if result, err := Client.CreateOutgoingWebhook(hook); err != nil { 491 t.Fatal(err) 492 } else { 493 if result.Data.(*model.OutgoingWebhook).CreatorId != user.Id { 494 t.Fatal("bad user id wasn't overwritten") 495 } 496 if result.Data.(*model.OutgoingWebhook).TeamId != team.Id { 497 t.Fatal("bad team id wasn't overwritten") 498 } 499 } 500 501 hook = &model.OutgoingWebhook{ChannelId: channel2.Id, CallbackURLs: []string{"http://nowhere.com"}} 502 if _, err := Client.CreateOutgoingWebhook(hook); err == nil { 503 t.Fatal("should have failed - private channel") 504 } 505 506 hook = &model.OutgoingWebhook{CallbackURLs: []string{"http://nowhere.com"}} 507 if _, err := Client.CreateOutgoingWebhook(hook); err == nil { 508 t.Fatal("should have failed - blank channel and trigger words") 509 } 510 511 Client.Logout() 512 Client.Must(Client.LoginById(user2.Id, user2.Password)) 513 Client.SetTeamId(team.Id) 514 515 hook = &model.OutgoingWebhook{ChannelId: channel1.Id, CallbackURLs: []string{"http://nowhere.com"}} 516 if _, err := Client.CreateOutgoingWebhook(hook); err == nil { 517 t.Fatal("should have failed - not system/team admin") 518 } 519 520 th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableOnlyAdminIntegrations = false }) 521 th.App.SetDefaultRolesBasedOnConfig() 522 523 if _, err := Client.CreateOutgoingWebhook(hook); err != nil { 524 t.Fatal(err) 525 } 526 527 Client.Logout() 528 Client.Must(Client.LoginById(user3.Id, user3.Password)) 529 Client.SetTeamId(team2.Id) 530 531 if _, err := Client.CreateOutgoingWebhook(hook); err == nil { 532 t.Fatal("should have failed - wrong team") 533 } 534 535 th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOutgoingWebhooks = false }) 536 537 if _, err := Client.CreateOutgoingWebhook(hook); err == nil { 538 t.Fatal("should have errored - webhooks turned off") 539 } 540 } 541 542 func TestListOutgoingHooks(t *testing.T) { 543 th := Setup().InitSystemAdmin() 544 defer th.TearDown() 545 546 Client := th.SystemAdminClient 547 team := th.SystemAdminTeam 548 channel1 := th.CreateChannel(Client, team) 549 user2 := th.CreateUser(Client) 550 th.LinkUserToTeam(user2, team) 551 552 th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOutgoingWebhooks = true }) 553 th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableOnlyAdminIntegrations = true }) 554 th.App.SetDefaultRolesBasedOnConfig() 555 556 hook1 := &model.OutgoingWebhook{ChannelId: channel1.Id, CallbackURLs: []string{"http://nowhere.com"}} 557 hook1 = Client.Must(Client.CreateOutgoingWebhook(hook1)).Data.(*model.OutgoingWebhook) 558 559 hook2 := &model.OutgoingWebhook{TriggerWords: []string{"trigger"}, CallbackURLs: []string{"http://nowhere.com"}} 560 hook2 = Client.Must(Client.CreateOutgoingWebhook(hook2)).Data.(*model.OutgoingWebhook) 561 562 if result, err := Client.ListOutgoingWebhooks(); err != nil { 563 t.Fatal(err) 564 } else { 565 hooks := result.Data.([]*model.OutgoingWebhook) 566 567 if len(hooks) != 2 { 568 t.Fatal("incorrect number of hooks") 569 } 570 } 571 572 Client.Logout() 573 Client.Must(Client.LoginById(user2.Id, user2.Password)) 574 Client.SetTeamId(team.Id) 575 576 if _, err := Client.ListOutgoingWebhooks(); err == nil { 577 t.Fatal("should have failed - not system/team admin") 578 } 579 580 th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableOnlyAdminIntegrations = false }) 581 th.App.SetDefaultRolesBasedOnConfig() 582 583 if _, err := Client.ListOutgoingWebhooks(); err != nil { 584 t.Fatal(err) 585 } 586 587 th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOutgoingWebhooks = false }) 588 589 if _, err := Client.ListOutgoingWebhooks(); err == nil { 590 t.Fatal("should have errored - webhooks turned off") 591 } 592 } 593 594 func TestUpdateOutgoingHook(t *testing.T) { 595 th := Setup().InitSystemAdmin() 596 defer th.TearDown() 597 598 Client := th.SystemAdminClient 599 user := th.SystemAdminUser 600 team := th.SystemAdminTeam 601 team2 := th.CreateTeam(Client) 602 channel1 := th.CreateChannel(Client, team) 603 channel2 := th.CreatePrivateChannel(Client, team) 604 channel3 := th.CreateChannel(Client, team) 605 user2 := th.CreateUser(Client) 606 th.LinkUserToTeam(user2, team) 607 user3 := th.CreateUser(Client) 608 th.LinkUserToTeam(user3, team2) 609 610 th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOutgoingWebhooks = true }) 611 th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableOnlyAdminIntegrations = true }) 612 th.App.SetDefaultRolesBasedOnConfig() 613 614 hook := createOutgoingWebhook(channel1.Id, []string{"http://nowhere.com"}, []string{"cats"}, Client, t) 615 createOutgoingWebhook(channel1.Id, []string{"http://nowhere.com"}, []string{"dogs"}, Client, t) 616 617 hook.DisplayName = "Cats" 618 hook.Description = "Get me some cats" 619 t.Run("OutgoingHooksDisabled", func(t *testing.T) { 620 th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOutgoingWebhooks = false }) 621 if _, err := Client.UpdateOutgoingWebhook(hook); err == nil { 622 t.Fatal("should have failed - outgoing webhooks disabled") 623 } 624 }) 625 626 th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOutgoingWebhooks = true }) 627 t.Run("UpdateOutgoingWebhook", func(t *testing.T) { 628 if result, err := Client.UpdateOutgoingWebhook(hook); err != nil { 629 t.Fatal("failed to update outgoing web hook") 630 } else { 631 updatedHook := result.Data.(*model.OutgoingWebhook) 632 633 if updatedHook.DisplayName != hook.DisplayName { 634 t.Fatal("Hook display name did not get updated") 635 } 636 637 if updatedHook.Description != hook.Description { 638 t.Fatal("Hook description did not get updated") 639 } 640 } 641 }) 642 643 t.Run("RetainCreateAt", func(t *testing.T) { 644 hook2 := &model.OutgoingWebhook{ChannelId: channel1.Id, CallbackURLs: []string{"http://nowhere.com"}, TriggerWords: []string{"rats"}} 645 646 if result, err := Client.CreateOutgoingWebhook(hook2); err != nil { 647 t.Fatal("hook creation failed") 648 } else { 649 createdHook := result.Data.(*model.OutgoingWebhook) 650 createdHook.DisplayName = "Name2" 651 652 if result, err := Client.UpdateOutgoingWebhook(createdHook); err != nil { 653 t.Fatal("Update hook should not fail") 654 } else { 655 updatedHook := result.Data.(*model.OutgoingWebhook) 656 657 if updatedHook.CreateAt != createdHook.CreateAt { 658 t.Fatal("failed - hook create at should not be changed") 659 } 660 } 661 } 662 }) 663 664 t.Run("ModifyUpdateAt", func(t *testing.T) { 665 hook.DisplayName = "Name3" 666 667 if result, err := Client.UpdateOutgoingWebhook(hook); err != nil { 668 t.Fatal("Update hook should not fail") 669 } else { 670 updatedHook := result.Data.(*model.OutgoingWebhook) 671 672 if updatedHook.UpdateAt == hook.UpdateAt { 673 t.Fatal("failed - hook updateAt is not updated") 674 } 675 } 676 }) 677 678 Client.Logout() 679 Client.Must(Client.LoginById(user2.Id, user2.Password)) 680 Client.SetTeamId(team.Id) 681 if _, err := Client.UpdateOutgoingWebhook(hook); err == nil { 682 t.Fatal("should have failed - user does not have permissions to manage webhooks") 683 } 684 685 th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableOnlyAdminIntegrations = false }) 686 th.App.SetDefaultRolesBasedOnConfig() 687 hook2 := createOutgoingWebhook(channel1.Id, []string{"http://nowhereelse.com"}, []string{"dogs"}, Client, t) 688 689 if _, err := Client.UpdateOutgoingWebhook(hook2); err != nil { 690 t.Fatal("update webhook failed when admin only integrations is turned off") 691 } 692 693 th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableOnlyAdminIntegrations = true }) 694 th.App.SetDefaultRolesBasedOnConfig() 695 696 Client.Logout() 697 th.LinkUserToTeam(user3, team) 698 th.UpdateUserToTeamAdmin(user3, team) 699 Client.Must(Client.LoginById(user3.Id, user3.Password)) 700 Client.SetTeamId(team.Id) 701 t.Run("RetainHookCreator", func(t *testing.T) { 702 if result, err := Client.UpdateOutgoingWebhook(hook); err != nil { 703 t.Fatal("failed to update outgoing web hook") 704 } else { 705 updatedHook := result.Data.(*model.OutgoingWebhook) 706 707 if updatedHook.CreatorId != user.Id { 708 t.Fatal("hook creator should not be changed") 709 } 710 } 711 }) 712 713 Client.Logout() 714 Client.Must(Client.LoginById(user.Id, user.Password)) 715 Client.SetTeamId(team.Id) 716 t.Run("UpdateToExistingTriggerWordAndCallback", func(t *testing.T) { 717 t.Run("OnSameChannel", func(t *testing.T) { 718 hook.TriggerWords = []string{"dogs"} 719 720 if _, err := Client.UpdateOutgoingWebhook(hook); err == nil { 721 t.Fatal("should have failed - duplicate trigger words & channel urls") 722 } 723 }) 724 725 t.Run("OnDifferentChannel", func(t *testing.T) { 726 hook.TriggerWords = []string{"dogs"} 727 hook.ChannelId = channel3.Id 728 729 if _, err := Client.UpdateOutgoingWebhook(hook); err != nil { 730 t.Fatal("update of hook failed with duplicate trigger word but different channel") 731 } 732 }) 733 }) 734 735 t.Run("UpdateToNonExistentChannel", func(t *testing.T) { 736 hook.ChannelId = "junk" 737 738 if _, err := Client.UpdateOutgoingWebhook(hook); err == nil { 739 t.Fatal("should have failed - non existent channel") 740 } 741 }) 742 743 t.Run("UpdateToPrivateChannel", func(t *testing.T) { 744 hook.ChannelId = channel2.Id 745 746 if _, err := Client.UpdateOutgoingWebhook(hook); err == nil { 747 t.Fatal("should have failed - update to a private channel") 748 } 749 }) 750 751 t.Run("UpdateToBlankTriggerWordAndChannel", func(t *testing.T) { 752 hook.ChannelId = "" 753 hook.TriggerWords = nil 754 755 if _, err := Client.UpdateOutgoingWebhook(hook); err == nil { 756 t.Fatal("should have failed - update to blank trigger words & channel") 757 } 758 }) 759 760 Client.Logout() 761 Client.Must(Client.LoginById(user3.Id, user3.Password)) 762 Client.SetTeamId(team2.Id) 763 t.Run("UpdateToADifferentTeam", func(t *testing.T) { 764 if _, err := Client.UpdateOutgoingWebhook(hook); err == nil { 765 t.Fatal("should have failed - update to a different team is not allowed") 766 } 767 }) 768 } 769 770 func TestDeleteOutgoingHook(t *testing.T) { 771 th := Setup().InitSystemAdmin() 772 defer th.TearDown() 773 774 Client := th.SystemAdminClient 775 team := th.SystemAdminTeam 776 channel1 := th.CreateChannel(Client, team) 777 user2 := th.CreateUser(Client) 778 th.LinkUserToTeam(user2, team) 779 780 th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOutgoingWebhooks = true }) 781 th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableOnlyAdminIntegrations = true }) 782 th.App.SetDefaultRolesBasedOnConfig() 783 784 hook := &model.OutgoingWebhook{ChannelId: channel1.Id, CallbackURLs: []string{"http://nowhere.com"}} 785 hook = Client.Must(Client.CreateOutgoingWebhook(hook)).Data.(*model.OutgoingWebhook) 786 787 if _, err := Client.DeleteOutgoingWebhook("junk"); err == nil { 788 t.Fatal("should have failed - bad hook id") 789 } 790 791 if _, err := Client.DeleteOutgoingWebhook(""); err == nil { 792 t.Fatal("should have failed - empty hook id") 793 } 794 795 if _, err := Client.DeleteOutgoingWebhook(hook.Id); err != nil { 796 t.Fatal(err) 797 } 798 799 hooks := Client.Must(Client.ListOutgoingWebhooks()).Data.([]*model.OutgoingWebhook) 800 if len(hooks) != 0 { 801 t.Fatal("delete didn't work properly") 802 } 803 804 hook = &model.OutgoingWebhook{ChannelId: channel1.Id, CallbackURLs: []string{"http://nowhere.com"}} 805 hook = Client.Must(Client.CreateOutgoingWebhook(hook)).Data.(*model.OutgoingWebhook) 806 807 Client.Logout() 808 Client.Must(Client.LoginById(user2.Id, user2.Password)) 809 Client.SetTeamId(team.Id) 810 811 if _, err := Client.DeleteOutgoingWebhook(hook.Id); err == nil { 812 t.Fatal("should have failed - not system/team admin") 813 } 814 815 th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableOnlyAdminIntegrations = false }) 816 th.App.SetDefaultRolesBasedOnConfig() 817 818 if _, err := Client.DeleteOutgoingWebhook(hook.Id); err == nil { 819 t.Fatal("should have failed - not creator or team admin") 820 } 821 822 hook = &model.OutgoingWebhook{ChannelId: channel1.Id, CallbackURLs: []string{"http://nowhere.com"}} 823 hook = Client.Must(Client.CreateOutgoingWebhook(hook)).Data.(*model.OutgoingWebhook) 824 825 if _, err := Client.DeleteOutgoingWebhook(hook.Id); err != nil { 826 t.Fatal(err) 827 } 828 829 th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOutgoingWebhooks = false }) 830 831 if _, err := Client.DeleteOutgoingWebhook(hook.Id); err == nil { 832 t.Fatal("should have errored - webhooks turned off") 833 } 834 } 835 836 func TestRegenOutgoingHookToken(t *testing.T) { 837 th := Setup().InitSystemAdmin() 838 defer th.TearDown() 839 840 Client := th.SystemAdminClient 841 team := th.SystemAdminTeam 842 team2 := th.CreateTeam(Client) 843 channel1 := th.CreateChannel(Client, team) 844 user2 := th.CreateUser(Client) 845 th.LinkUserToTeam(user2, team) 846 user3 := th.CreateUser(Client) 847 th.LinkUserToTeam(user3, team2) 848 849 th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOutgoingWebhooks = true }) 850 th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableOnlyAdminIntegrations = true }) 851 th.App.SetDefaultRolesBasedOnConfig() 852 853 hook := &model.OutgoingWebhook{ChannelId: channel1.Id, CallbackURLs: []string{"http://nowhere.com"}} 854 hook = Client.Must(Client.CreateOutgoingWebhook(hook)).Data.(*model.OutgoingWebhook) 855 856 if _, err := Client.RegenOutgoingWebhookToken("junk"); err == nil { 857 t.Fatal("should have failed - bad id") 858 } 859 860 if _, err := Client.RegenOutgoingWebhookToken(""); err == nil { 861 t.Fatal("should have failed - empty id") 862 } 863 864 if result, err := Client.RegenOutgoingWebhookToken(hook.Id); err != nil { 865 t.Fatal(err) 866 } else { 867 if result.Data.(*model.OutgoingWebhook).Token == hook.Token { 868 t.Fatal("regen didn't work properly") 869 } 870 } 871 872 Client.SetTeamId(model.NewId()) 873 if _, err := Client.RegenOutgoingWebhookToken(hook.Id); err == nil { 874 t.Fatal("should have failed - wrong team id") 875 } 876 877 Client.Logout() 878 Client.Must(Client.LoginById(user2.Id, user2.Password)) 879 Client.SetTeamId(team.Id) 880 881 if _, err := Client.RegenOutgoingWebhookToken(hook.Id); err == nil { 882 t.Fatal("should have failed - not system/team admin") 883 } 884 885 th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableOnlyAdminIntegrations = false }) 886 th.App.SetDefaultRolesBasedOnConfig() 887 888 hook = &model.OutgoingWebhook{ChannelId: channel1.Id, CallbackURLs: []string{"http://nowhere.com"}} 889 hook = Client.Must(Client.CreateOutgoingWebhook(hook)).Data.(*model.OutgoingWebhook) 890 891 if _, err := Client.RegenOutgoingWebhookToken(hook.Id); err != nil { 892 t.Fatal(err) 893 } 894 895 Client.Logout() 896 Client.Must(Client.LoginById(user3.Id, user3.Password)) 897 Client.SetTeamId(team2.Id) 898 899 if _, err := Client.RegenOutgoingWebhookToken(hook.Id); err == nil { 900 t.Fatal("should have failed - wrong team") 901 } 902 903 th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOutgoingWebhooks = false }) 904 905 if _, err := Client.RegenOutgoingWebhookToken(hook.Id); err == nil { 906 t.Fatal("should have errored - webhooks turned off") 907 } 908 } 909 910 func TestIncomingWebhooks(t *testing.T) { 911 th := Setup().InitBasic().InitSystemAdmin() 912 defer th.TearDown() 913 914 Client := th.SystemAdminClient 915 team := th.SystemAdminTeam 916 channel1 := th.CreateChannel(Client, team) 917 user2 := th.CreateUser(Client) 918 th.LinkUserToTeam(user2, team) 919 920 enableIncomingHooks := th.App.Config().ServiceSettings.EnableIncomingWebhooks 921 defer func() { 922 th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableIncomingWebhooks = enableIncomingHooks }) 923 }() 924 th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableIncomingWebhooks = true }) 925 926 hook := &model.IncomingWebhook{ChannelId: channel1.Id} 927 hook = Client.Must(Client.CreateIncomingWebhook(hook)).Data.(*model.IncomingWebhook) 928 929 url := "/hooks/" + hook.Id 930 text := `this is a \"test\" 931 that contains a newline and a tab` 932 933 if _, err := Client.DoPost(url, "{\"text\":\"this is a test\"}", "application/json"); err != nil { 934 t.Fatal(err) 935 } 936 937 if _, err := Client.DoPost(url, "{\"text\":\""+text+"\"}", "application/json"); err != nil { 938 t.Fatal(err) 939 } 940 941 if _, err := Client.DoPost(url, fmt.Sprintf("{\"text\":\"this is a test\", \"channel\":\"%s\"}", channel1.Name), "application/json"); err != nil { 942 t.Fatal(err) 943 } 944 945 if _, err := Client.DoPost(url, fmt.Sprintf("{\"text\":\"this is a test\", \"channel\":\"#%s\"}", channel1.Name), "application/json"); err != nil { 946 t.Fatal(err) 947 } 948 949 if _, err := Client.DoPost(url, fmt.Sprintf("{\"text\":\"this is a test\", \"channel\":\"@%s\"}", user2.Username), "application/json"); err != nil { 950 t.Fatal(err) 951 } 952 953 if _, err := Client.DoPost(url, "payload={\"text\":\"this is a test\"}", "application/x-www-form-urlencoded"); err != nil { 954 t.Fatal(err) 955 } 956 957 if _, err := Client.DoPost(url, "payload={\"text\":\""+text+"\"}", "application/x-www-form-urlencoded"); err != nil { 958 t.Fatal(err) 959 } 960 961 if _, err := th.BasicClient.DoPost(url, fmt.Sprintf("{\"text\":\"this is a test\", \"channel\":\"%s\"}", model.DEFAULT_CHANNEL), "application/json"); err != nil { 962 t.Fatal("should not have failed -- ExperimentalTownSquareIsReadOnly is false and it's not a read only channel") 963 } 964 965 isLicensed := utils.IsLicensed() 966 license := utils.License() 967 disableTownSquareReadOnly := th.App.Config().TeamSettings.ExperimentalTownSquareIsReadOnly 968 defer func() { 969 th.App.UpdateConfig(func(cfg *model.Config) { cfg.TeamSettings.ExperimentalTownSquareIsReadOnly = disableTownSquareReadOnly }) 970 utils.SetIsLicensed(isLicensed) 971 utils.SetLicense(license) 972 th.App.SetDefaultRolesBasedOnConfig() 973 }() 974 th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.ExperimentalTownSquareIsReadOnly = true }) 975 th.App.SetDefaultRolesBasedOnConfig() 976 utils.SetIsLicensed(true) 977 utils.SetLicense(&model.License{Features: &model.Features{}}) 978 utils.License().Features.SetDefaults() 979 980 if _, err := th.BasicClient.DoPost(url, fmt.Sprintf("{\"text\":\"this is a test\", \"channel\":\"%s\"}", model.DEFAULT_CHANNEL), "application/json"); err == nil { 981 t.Fatal("should have failed -- ExperimentalTownSquareIsReadOnly is true and it's a read only channel") 982 } 983 984 attachmentPayload := `{ 985 "text": "this is a test", 986 "attachments": [ 987 { 988 "fallback": "Required plain-text summary of the attachment.", 989 990 "color": "#36a64f", 991 992 "pretext": "Optional text that appears above the attachment block", 993 994 "author_name": "Bobby Tables", 995 "author_link": "http://flickr.com/bobby/", 996 "author_icon": "http://flickr.com/icons/bobby.jpg", 997 998 "title": "Slack API Documentation", 999 "title_link": "https://api.slack.com/", 1000 1001 "text": "Optional text that appears within the attachment", 1002 1003 "fields": [ 1004 { 1005 "title": "Priority", 1006 "value": "High", 1007 "short": false 1008 } 1009 ], 1010 1011 "image_url": "http://my-website.com/path/to/image.jpg", 1012 "thumb_url": "http://example.com/path/to/thumb.png" 1013 } 1014 ] 1015 }` 1016 1017 if _, err := Client.DoPost(url, attachmentPayload, "application/json"); err != nil { 1018 t.Fatal(err) 1019 } 1020 1021 if _, err := Client.DoPost(url, "{\"text\":\"\"}", "application/json"); err == nil || err.StatusCode != http.StatusBadRequest { 1022 t.Fatal("should have failed - no text") 1023 } 1024 1025 tooLongText := "" 1026 for i := 0; i < 8200; i++ { 1027 tooLongText += "a" 1028 } 1029 1030 if _, err := Client.DoPost(url, "{\"text\":\""+tooLongText+"\"}", "application/json"); err != nil { 1031 t.Fatal(err) 1032 } 1033 1034 attachmentPayload = `{ 1035 "text": "this is a test", 1036 "attachments": [ 1037 { 1038 "fallback": "Required plain-text summary of the attachment.", 1039 1040 "color": "#36a64f", 1041 1042 "pretext": "Optional text that appears above the attachment block", 1043 1044 "author_name": "Bobby Tables", 1045 "author_link": "http://flickr.com/bobby/", 1046 "author_icon": "http://flickr.com/icons/bobby.jpg", 1047 1048 "title": "Slack API Documentation", 1049 "title_link": "https://api.slack.com/", 1050 1051 "text": "` + tooLongText + `", 1052 1053 "fields": [ 1054 { 1055 "title": "Priority", 1056 "value": "High", 1057 "short": false 1058 } 1059 ], 1060 1061 "image_url": "http://my-website.com/path/to/image.jpg", 1062 "thumb_url": "http://example.com/path/to/thumb.png" 1063 } 1064 ] 1065 }` 1066 1067 if _, err := Client.DoPost(url, attachmentPayload, "application/json"); err != nil { 1068 t.Fatal(err) 1069 } 1070 1071 th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableIncomingWebhooks = false }) 1072 1073 if _, err := Client.DoPost(url, "{\"text\":\"this is a test\"}", "application/json"); err == nil { 1074 t.Fatal("should have failed - webhooks turned off") 1075 } 1076 }