diff --git a/src/pretix/base/email.py b/src/pretix/base/email.py
index 3462315153..aa2ae2d21f 100644
--- a/src/pretix/base/email.py
+++ b/src/pretix/base/email.py
@@ -134,8 +134,11 @@ class TemplateBasedMailRenderer(BaseHTMLMailRenderer):
def template_name(self):
raise NotImplementedError()
+ def compile_markdown(self, plaintext):
+ return markdown_compile_email(plaintext)
+
def render(self, plain_body: str, plain_signature: str, subject: str, order, position) -> str:
- body_md = markdown_compile_email(plain_body)
+ body_md = self.compile_markdown(plain_body)
htmlctx = {
'site': settings.PRETIX_INSTANCE_NAME,
'site_url': settings.SITE_URL,
@@ -153,7 +156,7 @@ class TemplateBasedMailRenderer(BaseHTMLMailRenderer):
if plain_signature:
signature_md = plain_signature.replace('\n', '
\n')
- signature_md = markdown_compile_email(signature_md)
+ signature_md = self.compile_markdown(signature_md)
htmlctx['signature'] = signature_md
if order:
diff --git a/src/pretix/base/templatetags/rich_text.py b/src/pretix/base/templatetags/rich_text.py
index 8bba7951d4..ee2d5703ef 100644
--- a/src/pretix/base/templatetags/rich_text.py
+++ b/src/pretix/base/templatetags/rich_text.py
@@ -292,7 +292,7 @@ class LinkifyAndCleanExtension(Extension):
)
-def markdown_compile_email(source):
+def markdown_compile_email(source, allowed_tags=ALLOWED_TAGS, allowed_attributes=ALLOWED_ATTRIBUTES):
linker = bleach.Linker(
url_re=URL_RE,
email_re=EMAIL_RE,
@@ -306,8 +306,8 @@ def markdown_compile_email(source):
EmailNl2BrExtension(),
LinkifyAndCleanExtension(
linker,
- tags=ALLOWED_TAGS,
- attributes=ALLOWED_ATTRIBUTES,
+ tags=allowed_tags,
+ attributes=allowed_attributes,
protocols=ALLOWED_PROTOCOLS,
strip=False,
)
diff --git a/src/tests/base/test_rich_text.py b/src/tests/base/test_rich_text.py
index 435b3d5408..6a952ad2e6 100644
--- a/src/tests/base/test_rich_text.py
+++ b/src/tests/base/test_rich_text.py
@@ -22,79 +22,122 @@
import pytest
from pretix.base.templatetags.rich_text import (
- markdown_compile_email, rich_text, rich_text_snippet,
+ ALLOWED_ATTRIBUTES, ALLOWED_TAGS, markdown_compile_email, rich_text,
+ rich_text_snippet,
)
-@pytest.mark.parametrize("link", [
- # Test link detection
- ("google.com",
- 'google.com'),
- # Test link escaping
- ("google\\.com", 'google.com'),
- # Test abslink_callback
- ("[Call](tel:+12345)",
- 'Call'),
- ("[Foo](/foo)",
- 'Foo'),
- ("mail@example.org",
- 'mail@example.org'),
- # Test truelink_callback
- ('evilsite.com',
- 'evilsite.com'),
- ('cool-example.eu',
- 'cool-example.eu'),
- ('Evil GmbH & Co. KG',
- 'Evil GmbH & Co. KG'),
- ('Evil Site',
- 'Evil Site'),
- ('evilsite.com',
- 'evilsite.com'),
- ('goodsite.com',
- 'https://evilsite.com'),
- ('goodsite.com',
- 'https://goodsite.com.evilsite.com'),
- ('evilsite.com',
- 'evilsite.com'),
- ('broken', 'broken'),
-])
+@pytest.mark.parametrize(
+ "link",
+ [
+ # Test link detection
+ (
+ "google.com",
+ 'google.com',
+ ),
+ # Test link escaping
+ ("google\\.com", "google.com"),
+ # Test abslink_callback
+ ("[Call](tel:+12345)", 'Call'),
+ (
+ "[Foo](/foo)",
+ 'Foo',
+ ),
+ ("mail@example.org", 'mail@example.org'),
+ # Test truelink_callback
+ (
+ "evilsite.com",
+ 'evilsite.com',
+ ),
+ (
+ "cool-example.eu",
+ 'cool-example.eu',
+ ),
+ (
+ 'Evil GmbH & Co. KG',
+ 'Evil GmbH & Co. KG',
+ ),
+ (
+ 'Evil Site',
+ 'Evil Site',
+ ),
+ (
+ 'evilsite.com',
+ 'evilsite.com',
+ ),
+ (
+ 'goodsite.com',
+ 'https://evilsite.com',
+ ),
+ (
+ 'goodsite.com',
+ 'https://goodsite.com.evilsite.com',
+ ),
+ (
+ 'evilsite.com',
+ 'evilsite.com',
+ ),
+ ("broken", "broken"),
+ ],
+)
def test_linkify_abs(link):
input, output = link
assert rich_text_snippet(input, safelinks=False) == output
- assert rich_text(input, safelinks=False) == f'
{output}
' - assert markdown_compile_email(input) == f'{output}
' + assert rich_text(input, safelinks=False) == f"{output}
" + assert markdown_compile_email(input) == f"{output}
" -@pytest.mark.parametrize("content,result", [ - ('a\nb', 'a
\nb
a
\nb
a
\nb
'), -]) +@pytest.mark.parametrize( + "content,result", + [ + ("a\nb", "a
\nb
a
\nb
a
\nb
"), + ], +) def test_newline_handling(content, result): assert rich_text(content, safelinks=False) == result -@pytest.mark.parametrize("content,result", [ - ('a\nb', 'a\nb
'), - ('a \nb', 'a
\nb
a
\nb
'), -]) +@pytest.mark.parametrize( + "content,result", + [ + ("a\nb", "a\nb
"), + ("a \nb", "a
\nb
a
\nb
"), + ], +) def test_newline_handling_email(content, result): assert markdown_compile_email(content) == result -@pytest.mark.parametrize("content,result,result_snippet", [ - # attributes - ('foo', '', 'foo'), - ('foo', - 'foo
', - 'foo'), - # protocols - ('foo', '', 'foo'), - # tags - ('', '<script>foo</script>', 'foo'), -]) +@pytest.mark.parametrize( + "content,result,result_snippet", + [ + # attributes + ('foo', "", "foo"), + ( + 'foo', + "foo
", + "foo", + ), + # protocols + ('foo', "", "foo"), + # tags + ("", "<script>foo</script>", "foo"), + ], +) def test_cleanup(content, result, result_snippet): assert rich_text(content) == result assert rich_text_snippet(content) == result_snippet assert markdown_compile_email(content) == result + + +def test_markdown_email_custom_allowlist(): + source = "" + html = markdown_compile_email( + source, + allowed_tags=ALLOWED_TAGS + ["img"], + allowed_attributes=dict(ALLOWED_ATTRIBUTES, img=["src", "alt", "title"]), + ) + assert html == '