diff --git a/web/webhook.go b/web/webhook.go index 1e33b367d3..cf000160a2 100644 --- a/web/webhook.go +++ b/web/webhook.go @@ -5,6 +5,7 @@ package web import ( "io" + "mime" "net/http" "strings" @@ -28,7 +29,11 @@ func incomingWebhook(c *Context, w http.ResponseWriter, r *http.Request) { var err *model.AppError incomingWebhookPayload := &model.IncomingWebhookRequest{} - contentType := r.Header.Get("Content-Type") + mediaType, _, mimeErr := mime.ParseMediaType(r.Header.Get("Content-Type")) + if mimeErr != nil && mimeErr != mime.ErrInvalidMediaParameter { + c.Err = model.NewAppError("incomingWebhook", "api.webhook.incoming.error", nil, mimeErr.Error(), http.StatusBadRequest) + return + } defer func() { if *c.App.Config().LogSettings.EnableWebhookDebugging { @@ -38,7 +43,7 @@ func incomingWebhook(c *Context, w http.ResponseWriter, r *http.Request) { } }() - if strings.Split(contentType, "; ")[0] == "application/x-www-form-urlencoded" { + if mediaType == "application/x-www-form-urlencoded" { payload := strings.NewReader(r.FormValue("payload")) incomingWebhookPayload, err = decodePayload(payload) @@ -46,7 +51,7 @@ func incomingWebhook(c *Context, w http.ResponseWriter, r *http.Request) { c.Err = err return } - } else if strings.HasPrefix(contentType, "multipart/form-data") { + } else if mediaType == "multipart/form-data" { r.ParseMultipartForm(0) decoder := schema.NewDecoder() diff --git a/web/webhook_test.go b/web/webhook_test.go index 47a7e88d16..1e918cf24b 100644 --- a/web/webhook_test.go +++ b/web/webhook_test.go @@ -87,14 +87,42 @@ func TestIncomingWebhook(t *testing.T) { assert.Nil(t, err) assert.True(t, resp.StatusCode == http.StatusOK) + resp, err = http.Post(url, "AppLicaTion/x-www-Form-urlencoded", strings.NewReader("payload={\"text\":\""+text+"\"}")) + assert.Nil(t, err) + assert.True(t, resp.StatusCode == http.StatusOK) + + resp, err = http.Post(url, "application/x-www-form-urlencoded;charset=utf-8", strings.NewReader("payload={\"text\":\""+text+"\"}")) + assert.Nil(t, err) + assert.True(t, resp.StatusCode == http.StatusOK) + + resp, err = http.Post(url, "application/x-www-form-urlencoded; charset=utf-8", strings.NewReader("payload={\"text\":\""+text+"\"}")) + assert.Nil(t, err) + assert.True(t, resp.StatusCode == http.StatusOK) + + resp, err = http.Post(url, "application/x-www-form-urlencoded wrongtext", strings.NewReader("payload={\"text\":\""+text+"\"}")) + assert.Nil(t, err) + assert.True(t, resp.StatusCode == http.StatusBadRequest) + resp, err = http.Post(url, "application/json", strings.NewReader("{\"text\":\""+tooLongText+"\"}")) require.Nil(t, err) assert.True(t, resp.StatusCode == http.StatusOK) + resp, err = http.Post(url, "application/x-www-form-urlencoded", strings.NewReader("{\"text\":\""+tooLongText+"\"}")) + assert.Nil(t, err) + assert.True(t, resp.StatusCode == http.StatusBadRequest) + + resp, err = http.Post(url, "application/json", strings.NewReader("payload={\"text\":\""+text+"\"}")) + assert.Nil(t, err) + assert.True(t, resp.StatusCode == http.StatusBadRequest) + payloadMultiPart := "------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: form-data; name=\"username\"\r\n\r\nwebhook-bot\r\n------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: form-data; name=\"text\"\r\n\r\nthis is a test :tada:\r\n------WebKitFormBoundary7MA4YWxkTrZu0gW--" resp, err = http.Post(ApiClient.Url+"/hooks/"+hook.Id, "multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW", strings.NewReader(payloadMultiPart)) require.Nil(t, err) assert.True(t, resp.StatusCode == http.StatusOK) + + resp, err = http.Post(url, "mimetype/wrong", strings.NewReader("payload={\"text\":\""+text+"\"}")) + assert.Nil(t, err) + assert.True(t, resp.StatusCode == http.StatusBadRequest) }) t.Run("WebhookExperimentalReadOnly", func(t *testing.T) {