Browse Source

Escape markdown in MS Teams notifications. cc: #426

pull/437/head
Pēteris Caune 4 years ago
parent
commit
05c81e0a41
No known key found for this signature in database GPG Key ID: E28D7679E9A9EDE2
4 changed files with 32 additions and 4 deletions
  1. +1
    -0
      CHANGELOG.md
  2. +20
    -0
      hc/api/tests/test_notify.py
  3. +11
    -3
      hc/api/transports.py
  4. +0
    -1
      templates/integrations/msteams_message.json

+ 1
- 0
CHANGELOG.md View File

@ -20,6 +20,7 @@ All notable changes to this project will be documented in this file.
- When copying a check, copy all fields from the "Filtering Rules" dialog (#417) - When copying a check, copy all fields from the "Filtering Rules" dialog (#417)
- Fix missing Resume button (#421) - Fix missing Resume button (#421)
- When decoding inbound emails, decode encoded headers (#420) - When decoding inbound emails, decode encoded headers (#420)
- Escape markdown in MS Teams notifications (#426)
## v1.16.0 - 2020-08-04 ## v1.16.0 - 2020-08-04


+ 20
- 0
hc/api/tests/test_notify.py View File

@ -866,6 +866,26 @@ class NotifyTestCase(BaseTestCase):
payload = kwargs["json"] payload = kwargs["json"]
self.assertEqual(payload["@type"], "MessageCard") self.assertEqual(payload["@type"], "MessageCard")
@patch("hc.api.transports.requests.request")
def test_msteams_escapes_markdown(self, mock_post):
self._setup_data("msteams", "http://example.com/webhook")
mock_post.return_value.status_code = 200
self.check.name = """
TEST _underscore_ `backticks` <u>underline</u> \\backslash\\ "quoted"
"""
self.channel.notify(self.check)
args, kwargs = mock_post.call_args
text = kwargs["json"]["text"]
self.assertIn(r"\_underscore\_", text)
self.assertIn(r"\`backticks\`", text)
self.assertIn("&lt;u&gt;underline&lt;/u&gt;", text)
self.assertIn(r"\\backslash\\ ", text)
self.assertIn("&quot;quoted&quot;", text)
@patch("hc.api.transports.os.system") @patch("hc.api.transports.os.system")
@override_settings(SHELL_ENABLED=True) @override_settings(SHELL_ENABLED=True)
def test_shell(self, mock_system): def test_shell(self, mock_system):


+ 11
- 3
hc/api/transports.py View File

@ -3,6 +3,7 @@ import os
from django.conf import settings from django.conf import settings
from django.template.loader import render_to_string from django.template.loader import render_to_string
from django.utils import timezone from django.utils import timezone
from django.utils.html import escape
import json import json
import requests import requests
from urllib.parse import quote, urlencode from urllib.parse import quote, urlencode
@ -582,6 +583,15 @@ class MsTeams(HttpTransport):
def notify(self, check): def notify(self, check):
text = tmpl("msteams_message.json", check=check) text = tmpl("msteams_message.json", check=check)
payload = json.loads(text) payload = json.loads(text)
# Escape special HTML characters in check's name
safe_name = escape(check.name_then_code())
# Escape characters that have special meaning in Markdown
for c in r"\`*_{}[]()#+-.!|":
safe_name = safe_name.replace(c, "\\" + c)
payload["text"] = f"“{safe_name}” is {check.status.upper()}."
return self.post(self.channel.value, json=payload) return self.post(self.channel.value, json=payload)
@ -629,7 +639,5 @@ class LineNotify(HttpTransport):
"Content-Type": "application/x-www-form-urlencoded", "Content-Type": "application/x-www-form-urlencoded",
"Authorization": "Bearer %s" % self.channel.linenotify_token, "Authorization": "Bearer %s" % self.channel.linenotify_token,
} }
payload = {
"message": tmpl("linenotify_message.html", check=check)
}
payload = {"message": tmpl("linenotify_message.html", check=check)}
return self.post(self.URL, headers=headers, params=payload) return self.post(self.URL, headers=headers, params=payload)

+ 0
- 1
templates/integrations/msteams_message.json View File

@ -3,7 +3,6 @@
"@type": "MessageCard", "@type": "MessageCard",
"@context": "https://schema.org/extensions", "@context": "https://schema.org/extensions",
"themeColor": "{% if check.status == "up" %}5cb85c{% endif %}{% if check.status == "down" %}d9534f{% endif %}", "themeColor": "{% if check.status == "up" %}5cb85c{% endif %}{% if check.status == "down" %}d9534f{% endif %}",
"text": "“{{ check.name_then_code|escapejs }}” is {{ check.status|upper }}.",
"sections": [ "sections": [
{ {
"facts": [ "facts": [


Loading…
Cancel
Save