diff --git a/zerver/lib/webhooks/common.py b/zerver/lib/webhooks/common.py index 2232e401ea..6e40943fc2 100644 --- a/zerver/lib/webhooks/common.py +++ b/zerver/lib/webhooks/common.py @@ -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 diff --git a/zerver/webhooks/jira/tests.py b/zerver/webhooks/jira/tests.py index 9b81b7e30e..b9dd7fe423 100644 --- a/zerver/webhooks/jira/tests.py +++ b/zerver/webhooks/jira/tests.py @@ -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**: diff --git a/zerver/webhooks/jira/view.py b/zerver/webhooks/jira/view.py index 04259663d1..96b37f3800 100644 --- a/zerver/webhooks/jira/view.py +++ b/zerver/webhooks/jira/view.py @@ -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()