From 4876a0b61f9fff7fdd5d13bf5737c0d4129b1923 Mon Sep 17 00:00:00 2001 From: Mira Date: Fri, 1 Mar 2024 09:56:22 +0100 Subject: [PATCH] Allow multiple returnurl prefixes (Z#23145768) (#3941) * Allow multiple returnurl prefixes, improve validation and docs. * Fix typo * Allow URL prefixes starting with http://localhost * Add more explanation --- doc/api/guides/custom_checkout.rst | 4 +++- src/pretix/plugins/returnurl/signals.py | 6 +++++- src/pretix/plugins/returnurl/views.py | 12 +++++++++--- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/doc/api/guides/custom_checkout.rst b/doc/api/guides/custom_checkout.rst index 26fb904a6..dc6c34fe4 100644 --- a/doc/api/guides/custom_checkout.rst +++ b/doc/api/guides/custom_checkout.rst @@ -94,7 +94,9 @@ If you want the user to return to your application after the payment is complete "Plugins". Enable the plugin "Redirection from order page". Then, go to the new page "Settings", then "Redirection". Enter the base URL of your web application. This will allow you to redirect to pages under this base URL later on. For example, if you want users to be redirected to ``https://example.org/order/return?tx_id=1234``, you could now -either enter ``https://example.org`` or ``https://example.org/order/``. +either enter ``https://example.org/order/`` or ``https://example.org/``. +Please note that in the latter case the trailing slash is required, ``https://example.org`` is not allowed to prevent. +Only base URLs with a secure (``https://``) or local (``http://localhost``) origin are permitted. The user will be redirected back to your page instead of pretix' order confirmation page after the payment, **regardless of whether it was successful or not**. We will append an ``error=…`` query parameter with an error diff --git a/src/pretix/plugins/returnurl/signals.py b/src/pretix/plugins/returnurl/signals.py index 6ad8c2232..894bed67b 100644 --- a/src/pretix/plugins/returnurl/signals.py +++ b/src/pretix/plugins/returnurl/signals.py @@ -71,11 +71,15 @@ def returnurl_process_request(sender, request, **kwargs): u = request.GET.get('return_url') if not sender.settings.returnurl_prefix: raise PermissionDenied('No return URL prefix set.') - elif not u.startswith(sender.settings.returnurl_prefix): + elif not check_against_prefix_list(u, sender.settings.returnurl_prefix): raise PermissionDenied('Invalid return URL.') request.session[key] = u +def check_against_prefix_list(u, allowlist): + return any(u.startswith(allow.strip()) for allow in allowlist.split("\n") if allow.strip() != "") + + @receiver(nav_event_settings, dispatch_uid='returnurl_nav') def navbar_info(sender, request, **kwargs): url = resolve(request.path_info) diff --git a/src/pretix/plugins/returnurl/views.py b/src/pretix/plugins/returnurl/views.py index 68d87d47d..437a46695 100644 --- a/src/pretix/plugins/returnurl/views.py +++ b/src/pretix/plugins/returnurl/views.py @@ -19,6 +19,8 @@ # You should have received a copy of the GNU Affero General Public License along with this program. If not, see # . # +import re + from django import forms from django.urls import reverse from django.utils.translation import gettext_lazy as _ @@ -31,10 +33,14 @@ from pretix.control.views.event import ( class ReturnSettingsForm(SettingsForm): - returnurl_prefix = forms.URLField( - label=_("Base redirection URL"), - help_text=_("Redirection will only be allowed to URLs that start with this prefix."), + returnurl_prefix = forms.RegexField( + label=_("Base redirection URLs"), + help_text=_("Redirection will only be allowed to URLs that start with one of these prefixes. " + "Enter one or more allowed URL prefix per line. " + "URL prefixes must include a slash after the hostname."), required=False, + widget=forms.Textarea, + regex=re.compile(r'^((https://.*/.*|http://localhost[:/].*)\n*)*$') )