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
This commit is contained in:
Mira
2024-03-01 09:56:22 +01:00
committed by GitHub
parent 56bbcb65c3
commit 4876a0b61f
3 changed files with 17 additions and 5 deletions

View File

@@ -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". "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. 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 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, 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 **regardless of whether it was successful or not**. We will append an ``error=…`` query parameter with an error

View File

@@ -71,11 +71,15 @@ def returnurl_process_request(sender, request, **kwargs):
u = request.GET.get('return_url') u = request.GET.get('return_url')
if not sender.settings.returnurl_prefix: if not sender.settings.returnurl_prefix:
raise PermissionDenied('No return URL prefix set.') 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.') raise PermissionDenied('Invalid return URL.')
request.session[key] = u 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') @receiver(nav_event_settings, dispatch_uid='returnurl_nav')
def navbar_info(sender, request, **kwargs): def navbar_info(sender, request, **kwargs):
url = resolve(request.path_info) url = resolve(request.path_info)

View File

@@ -19,6 +19,8 @@
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see # You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# <https://www.gnu.org/licenses/>. # <https://www.gnu.org/licenses/>.
# #
import re
from django import forms from django import forms
from django.urls import reverse from django.urls import reverse
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
@@ -31,10 +33,14 @@ from pretix.control.views.event import (
class ReturnSettingsForm(SettingsForm): class ReturnSettingsForm(SettingsForm):
returnurl_prefix = forms.URLField( returnurl_prefix = forms.RegexField(
label=_("Base redirection URL"), label=_("Base redirection URLs"),
help_text=_("Redirection will only be allowed to URLs that start with this prefix."), 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, required=False,
widget=forms.Textarea,
regex=re.compile(r'^((https://.*/.*|http://localhost[:/].*)\n*)*$')
) )