integration_action_test.go 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
  2. // See LICENSE.txt for license information.
  3. package api4
  4. import (
  5. "bytes"
  6. "encoding/json"
  7. "io/ioutil"
  8. "net/http"
  9. "net/http/httptest"
  10. "testing"
  11. "github.com/stretchr/testify/assert"
  12. "github.com/mattermost/mattermost-server/v5/model"
  13. "github.com/stretchr/testify/require"
  14. )
  15. type testHandler struct {
  16. t *testing.T
  17. }
  18. func (th *testHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  19. bb, err := ioutil.ReadAll(r.Body)
  20. assert.Nil(th.t, err)
  21. assert.NotEmpty(th.t, string(bb))
  22. poir := model.PostActionIntegrationRequestFromJson(bytes.NewReader(bb))
  23. assert.NotEmpty(th.t, poir.UserId)
  24. assert.NotEmpty(th.t, poir.UserName)
  25. assert.NotEmpty(th.t, poir.ChannelId)
  26. assert.NotEmpty(th.t, poir.ChannelName)
  27. assert.NotEmpty(th.t, poir.TeamId)
  28. assert.NotEmpty(th.t, poir.TeamName)
  29. assert.NotEmpty(th.t, poir.PostId)
  30. assert.NotEmpty(th.t, poir.TriggerId)
  31. assert.Equal(th.t, "button", poir.Type)
  32. assert.Equal(th.t, "test-value", poir.Context["test-key"])
  33. w.Write([]byte("{}"))
  34. w.WriteHeader(200)
  35. }
  36. func TestPostActionCookies(t *testing.T) {
  37. th := Setup(t).InitBasic()
  38. defer th.TearDown()
  39. Client := th.Client
  40. th.App.UpdateConfig(func(cfg *model.Config) {
  41. *cfg.ServiceSettings.AllowedUntrustedInternalConnections = "localhost,127.0.0.1"
  42. })
  43. handler := &testHandler{t}
  44. server := httptest.NewServer(handler)
  45. for name, test := range map[string]struct {
  46. Action model.PostAction
  47. ExpectedSucess bool
  48. ExpectedStatusCode int
  49. }{
  50. "32 character ID": {
  51. Action: model.PostAction{
  52. Id: model.NewId(),
  53. Name: "Test-action",
  54. Type: model.POST_ACTION_TYPE_BUTTON,
  55. Integration: &model.PostActionIntegration{
  56. URL: server.URL,
  57. Context: map[string]interface{}{
  58. "test-key": "test-value",
  59. },
  60. },
  61. },
  62. ExpectedSucess: true,
  63. ExpectedStatusCode: http.StatusOK,
  64. },
  65. "6 character ID": {
  66. Action: model.PostAction{
  67. Id: "someID",
  68. Name: "Test-action",
  69. Type: model.POST_ACTION_TYPE_BUTTON,
  70. Integration: &model.PostActionIntegration{
  71. URL: server.URL,
  72. Context: map[string]interface{}{
  73. "test-key": "test-value",
  74. },
  75. },
  76. },
  77. ExpectedSucess: true,
  78. ExpectedStatusCode: http.StatusOK,
  79. },
  80. "Empty ID": {
  81. Action: model.PostAction{
  82. Id: "",
  83. Name: "Test-action",
  84. Type: model.POST_ACTION_TYPE_BUTTON,
  85. Integration: &model.PostActionIntegration{
  86. URL: server.URL,
  87. Context: map[string]interface{}{
  88. "test-key": "test-value",
  89. },
  90. },
  91. },
  92. ExpectedSucess: false,
  93. ExpectedStatusCode: http.StatusNotFound,
  94. },
  95. } {
  96. t.Run(name, func(t *testing.T) {
  97. post := &model.Post{
  98. Id: model.NewId(),
  99. Type: model.POST_EPHEMERAL,
  100. UserId: th.BasicUser.Id,
  101. ChannelId: th.BasicChannel.Id,
  102. CreateAt: model.GetMillis(),
  103. UpdateAt: model.GetMillis(),
  104. Props: map[string]interface{}{
  105. "attachments": []*model.SlackAttachment{
  106. {
  107. Title: "some-title",
  108. TitleLink: "https://some-url.com",
  109. Text: "some-text",
  110. ImageURL: "https://some-other-url.com",
  111. Actions: []*model.PostAction{&test.Action},
  112. },
  113. },
  114. },
  115. }
  116. assert.Equal(t, 32, len(th.App.PostActionCookieSecret()))
  117. post = model.AddPostActionCookies(post, th.App.PostActionCookieSecret())
  118. ok, resp := Client.DoPostActionWithCookie(post.Id, test.Action.Id, "", test.Action.Cookie)
  119. require.NotNil(t, resp)
  120. if test.ExpectedSucess {
  121. assert.True(t, ok)
  122. assert.Nil(t, resp.Error)
  123. } else {
  124. assert.False(t, ok)
  125. assert.NotNil(t, resp.Error)
  126. }
  127. assert.Equal(t, test.ExpectedStatusCode, resp.StatusCode)
  128. assert.NotNil(t, resp.RequestId)
  129. assert.NotNil(t, resp.ServerVersion)
  130. })
  131. }
  132. }
  133. func TestOpenDialog(t *testing.T) {
  134. th := Setup(t).InitBasic()
  135. defer th.TearDown()
  136. Client := th.Client
  137. th.App.UpdateConfig(func(cfg *model.Config) {
  138. *cfg.ServiceSettings.AllowedUntrustedInternalConnections = "localhost,127.0.0.1"
  139. })
  140. _, triggerId, err := model.GenerateTriggerId(th.BasicUser.Id, th.App.AsymmetricSigningKey())
  141. require.Nil(t, err)
  142. request := model.OpenDialogRequest{
  143. TriggerId: triggerId,
  144. URL: "http://localhost:8065",
  145. Dialog: model.Dialog{
  146. CallbackId: "callbackid",
  147. Title: "Some Title",
  148. Elements: []model.DialogElement{
  149. {
  150. DisplayName: "Element Name",
  151. Name: "element_name",
  152. Type: "text",
  153. Placeholder: "Enter a value",
  154. },
  155. },
  156. SubmitLabel: "Submit",
  157. NotifyOnCancel: false,
  158. State: "somestate",
  159. },
  160. }
  161. pass, resp := Client.OpenInteractiveDialog(request)
  162. CheckNoError(t, resp)
  163. assert.True(t, pass)
  164. // Should fail on bad trigger ID
  165. request.TriggerId = "junk"
  166. pass, resp = Client.OpenInteractiveDialog(request)
  167. CheckBadRequestStatus(t, resp)
  168. assert.False(t, pass)
  169. // URL is required
  170. request.TriggerId = triggerId
  171. request.URL = ""
  172. pass, resp = Client.OpenInteractiveDialog(request)
  173. CheckBadRequestStatus(t, resp)
  174. assert.False(t, pass)
  175. // Should pass with markdown formatted introduction text
  176. request.URL = "http://localhost:8065"
  177. request.Dialog.IntroductionText = "**Some** _introduction text"
  178. pass, resp = Client.OpenInteractiveDialog(request)
  179. CheckNoError(t, resp)
  180. assert.True(t, pass)
  181. // Should pass with empty introduction text
  182. request.Dialog.IntroductionText = ""
  183. pass, resp = Client.OpenInteractiveDialog(request)
  184. CheckNoError(t, resp)
  185. assert.True(t, pass)
  186. // Should pass with no elements
  187. request.Dialog.Elements = nil
  188. pass, resp = Client.OpenInteractiveDialog(request)
  189. CheckNoError(t, resp)
  190. assert.True(t, pass)
  191. request.Dialog.Elements = []model.DialogElement{}
  192. pass, resp = Client.OpenInteractiveDialog(request)
  193. CheckNoError(t, resp)
  194. assert.True(t, pass)
  195. }
  196. func TestSubmitDialog(t *testing.T) {
  197. th := Setup(t).InitBasic()
  198. defer th.TearDown()
  199. Client := th.Client
  200. th.App.UpdateConfig(func(cfg *model.Config) {
  201. *cfg.ServiceSettings.AllowedUntrustedInternalConnections = "localhost,127.0.0.1"
  202. })
  203. submit := model.SubmitDialogRequest{
  204. CallbackId: "callbackid",
  205. State: "somestate",
  206. UserId: th.BasicUser.Id,
  207. ChannelId: th.BasicChannel.Id,
  208. TeamId: th.BasicTeam.Id,
  209. Submission: map[string]interface{}{"somename": "somevalue"},
  210. }
  211. ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  212. var request model.SubmitDialogRequest
  213. err := json.NewDecoder(r.Body).Decode(&request)
  214. require.Nil(t, err)
  215. assert.NotNil(t, request)
  216. assert.Equal(t, request.URL, "")
  217. assert.Equal(t, request.UserId, submit.UserId)
  218. assert.Equal(t, request.ChannelId, submit.ChannelId)
  219. assert.Equal(t, request.TeamId, submit.TeamId)
  220. assert.Equal(t, request.CallbackId, submit.CallbackId)
  221. assert.Equal(t, request.State, submit.State)
  222. val, ok := request.Submission["somename"].(string)
  223. require.True(t, ok)
  224. assert.Equal(t, "somevalue", val)
  225. }))
  226. defer ts.Close()
  227. submit.URL = ts.URL
  228. submitResp, resp := Client.SubmitInteractiveDialog(submit)
  229. CheckNoError(t, resp)
  230. assert.NotNil(t, submitResp)
  231. submit.URL = ""
  232. submitResp, resp = Client.SubmitInteractiveDialog(submit)
  233. CheckBadRequestStatus(t, resp)
  234. assert.Nil(t, submitResp)
  235. submit.URL = ts.URL
  236. submit.ChannelId = model.NewId()
  237. submitResp, resp = Client.SubmitInteractiveDialog(submit)
  238. CheckForbiddenStatus(t, resp)
  239. assert.Nil(t, submitResp)
  240. submit.URL = ts.URL
  241. submit.ChannelId = th.BasicChannel.Id
  242. submit.TeamId = model.NewId()
  243. submitResp, resp = Client.SubmitInteractiveDialog(submit)
  244. CheckForbiddenStatus(t, resp)
  245. assert.Nil(t, submitResp)
  246. }