diff --git a/src/pretix/base/templatetags/rich_text.py b/src/pretix/base/templatetags/rich_text.py index 2fabad485c..307a2d6d5a 100644 --- a/src/pretix/base/templatetags/rich_text.py +++ b/src/pretix/base/templatetags/rich_text.py @@ -156,7 +156,7 @@ def safelink_callback(attrs, new=False): Makes sure that all links to a different domain are passed through a redirection handler to ensure there's no passing of referers with secrets inside them. """ - url = attrs.get((None, 'href'), '/') + url = html.unescape(attrs.get((None, 'href'), '/')) if not url_has_allowed_host_and_scheme(url, allowed_hosts=None) and not url.startswith('mailto:') and not url.startswith('tel:'): signer = signing.Signer(salt='safe-redirect') attrs[None, 'href'] = reverse('redirect') + '?url=' + urllib.parse.quote(signer.sign(url)) diff --git a/src/tests/base/test_rich_text.py b/src/tests/base/test_rich_text.py index c893b7d3bb..5b9b6592d1 100644 --- a/src/tests/base/test_rich_text.py +++ b/src/tests/base/test_rich_text.py @@ -19,7 +19,11 @@ # You should have received a copy of the GNU Affero General Public License along with this program. If not, see # . # +import html +import urllib.parse + import pytest +from django.core import signing from pretix.base.templatetags.rich_text import ( ALLOWED_ATTRIBUTES, ALLOWED_TAGS, markdown_compile_email, rich_text, @@ -43,6 +47,10 @@ from pretix.base.templatetags.rich_text import ( "[Foo](/foo)", 'Foo', ), + ( + "[Foo](/foo?bar&baz)", + 'Foo', + ), ("mail@example.org", 'mail@example.org'), # Test truelink_callback ( @@ -111,6 +119,40 @@ def test_linkify_abs(link): assert markdown_compile_email(input) == f"

{output}

" +signer = signing.Signer(salt='safe-redirect') + + +@pytest.mark.parametrize( + "url,result", + [ + ('http://example.com/foo', '{}'), + ('http://example.com/foo?bar&baz', '{}'), + ('http://example.com/foo?bar&baz>', '{}'), + ( + 'http://example.com/foo?bar&baz">', + '{}">'.format( + urllib.parse.quote(signer.sign('http://example.com/foo?bar&baz')), + html.escape('http://example.com/foo?bar&baz'), + ) + ), + ( + 'http://example.com/foo?bar&baz\\">', + '{}\\">'.format( + urllib.parse.quote(signer.sign('http://example.com/foo?bar&baz')), + html.escape('http://example.com/foo?bar&baz'), + ) + ), + ], +) +def test_linkify_safelinks(url, result): + output = result.format( + urllib.parse.quote(signer.sign(url)), + html.escape(url), + ) + assert rich_text_snippet(url, safelinks=True) == output + assert rich_text(url, safelinks=True) == f"

{output}

" + + @pytest.mark.parametrize( "content,result", [