webhooks/jira: Decode stream name on our end.

Recently, one of our users reported that a JIRA webhook was not
able to send messages to a stream with a space character in its
name. Turns out that JIRA does something weird with webhook URLs,
such that escaped space characters (%20) are escaped again, so
that when the request gets to Zulip, the double escaped %20 is
evaluated as the literal characters `%20`, and not as a space.

We fix this by unescaping the stream name on our end before
sending the message forward!
This commit is contained in:
Eeshan Garg 2018-11-06 12:37:04 -03:30 committed by Tim Abbott
parent 6ef64fc752
commit 006e47198c
3 changed files with 34 additions and 2 deletions

View File

@ -1,3 +1,5 @@
from urllib.parse import unquote
from django.conf import settings
from django.http import HttpRequest
from django.utils.translation import ugettext as _
@ -51,7 +53,8 @@ class MissingHTTPEventHeader(JsonableError):
def check_send_webhook_message(
request: HttpRequest, user_profile: UserProfile,
topic: str, body: str, stream: Optional[str]=REQ(default=None),
user_specified_topic: Optional[str]=REQ("topic", default=None)
user_specified_topic: Optional[str]=REQ("topic", default=None),
unquote_stream: Optional[bool]=False
) -> None:
if stream is None:
@ -59,6 +62,13 @@ def check_send_webhook_message(
check_send_private_message(user_profile, request.client,
user_profile.bot_owner, body)
else:
# Some third-party websites (such as Atlassian's JIRA), tend to
# double escape their URLs in a manner that escaped space characters
# (%20) are never properly decoded. We work around that by making sure
# that the stream name is decoded on our end.
if unquote_stream:
stream = unquote(stream)
if user_specified_topic is not None:
topic = user_specified_topic

View File

@ -1,5 +1,7 @@
# -*- coding: utf-8 -*-
from urllib.parse import quote, unquote
from zerver.lib.test_classes import WebhookTestCase
from zerver.lib.users import get_api_key
@ -28,6 +30,24 @@ class JiraHookTests(WebhookTestCase):
self.send_and_test_stream_message('created_v1', expected_subject, expected_message)
self.send_and_test_stream_message('created_v2', expected_subject, expected_message)
def test_created_with_stream_with_spaces_escaped(self) -> None:
self.STREAM_NAME = quote('jira alerts')
self.url = self.build_webhook_url()
self.subscribe(self.test_user, unquote(self.STREAM_NAME))
payload = self.get_body('created_v1')
result = self.client_post(self.url, payload, content_type='application/json')
self.assert_json_success(result)
expected_subject = "BUG-15: New bug with hook"
expected_message = """Leo Franchi **created** [BUG-15](http://lfranchi.com:8080/browse/BUG-15) priority Major, assigned to **no one**:
> New bug with hook"""
msg = self.get_last_message()
self.assertEqual(msg.content, expected_message)
self.assertEqual(msg.topic_name(), expected_subject)
def test_created_with_unicode(self) -> None:
expected_subject = u"BUG-15: New bug with à hook"
expected_message = u"""Leo Franchià **created** [BUG-15](http://lfranchi.com:8080/browse/BUG-15) priority Major, assigned to **no one**:

View File

@ -241,5 +241,7 @@ def api_jira_webhook(request: HttpRequest, user_profile: UserProfile,
else:
raise UnexpectedWebhookEventType('Jira', event)
check_send_webhook_message(request, user_profile, subject, content)
check_send_webhook_message(request, user_profile,
subject, content,
unquote_stream=True)
return json_success()