diff --git a/src/pretix/control/views/auth.py b/src/pretix/control/views/auth.py index c882b30c00..d8e67c0e15 100644 --- a/src/pretix/control/views/auth.py +++ b/src/pretix/control/views/auth.py @@ -61,6 +61,7 @@ from pretix.base.forms.auth import ( ) from pretix.base.models import TeamInvite, U2FDevice, User, WebAuthnDevice from pretix.base.services.mail import SendMailException +from pretix.helpers.http import redirect_to_url from pretix.helpers.webauthn import generate_challenge logger = logging.getLogger(__name__) @@ -81,7 +82,7 @@ def process_login(request, user, keep_logged_in): twofa_url = reverse('control:auth.login.2fa') if next_url and url_has_allowed_host_and_scheme(next_url, allowed_hosts=None): twofa_url += '?next=' + quote(next_url) - return redirect(twofa_url) + return redirect_to_url(twofa_url) else: auth_login(request, user) request.session['pretix_auth_login_time'] = int(time.time()) @@ -110,7 +111,7 @@ def login(request): if request.user.is_authenticated: next_url = backend.get_next_url(request) or 'control:index' if next_url and url_has_allowed_host_and_scheme(next_url, allowed_hosts=None): - return redirect(next_url) + return redirect_to_url(next_url) return redirect(reverse('control:index')) if request.method == 'POST': form = LoginForm(backend=backend, data=request.POST, request=request) @@ -136,8 +137,8 @@ def logout(request): if 'next' in request.GET and url_has_allowed_host_and_scheme(request.GET.get('next'), allowed_hosts=None): next += '?next=' + quote(request.GET.get('next')) if 'back' in request.GET and url_has_allowed_host_and_scheme(request.GET.get('back'), allowed_hosts=None): - return redirect(request.GET.get('back')) - return redirect(next) + return redirect_to_url(request.GET.get('back')) + return redirect_to_url(next) def register(request): @@ -443,7 +444,7 @@ class Login2FAView(TemplateView): del request.session['pretix_auth_2fa_user'] del request.session['pretix_auth_2fa_time'] if "next" in request.GET and url_has_allowed_host_and_scheme(request.GET.get("next"), allowed_hosts=None): - return redirect(request.GET.get("next")) + return redirect_to_url(request.GET.get("next")) return redirect(reverse('control:index')) else: messages.error(request, _('Invalid code, please try again.')) diff --git a/src/pretix/control/views/user.py b/src/pretix/control/views/user.py index e78e5c43af..575afc420b 100644 --- a/src/pretix/control/views/user.py +++ b/src/pretix/control/views/user.py @@ -71,6 +71,7 @@ from pretix.control.permissions import ( AdministratorPermissionRequiredMixin, StaffMemberRequiredMixin, ) from pretix.control.views.auth import get_u2f_appid +from pretix.helpers.http import redirect_to_url from pretix.helpers.webauthn import generate_challenge, generate_ukey REAL_DEVICE_TYPES = (TOTPDevice, WebAuthnDevice, U2FDevice) @@ -138,7 +139,7 @@ class ReauthView(TemplateView): request.session['pretix_auth_last_used'] = t next_url = get_auth_backends()[request.user.auth_backend].get_next_url(request) if next_url and url_has_allowed_host_and_scheme(next_url, allowed_hosts=None): - return redirect(next_url) + return redirect_to_url(next_url) return redirect(reverse('control:index')) else: messages.error(request, _('The password you entered was invalid, please try again.')) @@ -153,7 +154,7 @@ class ReauthView(TemplateView): request.session['pretix_auth_login_time'] = t request.session['pretix_auth_last_used'] = t if next_url and url_has_allowed_host_and_scheme(next_url, allowed_hosts=None): - return redirect(next_url) + return redirect_to_url(next_url) return redirect(reverse('control:index')) return super().get(request, *args, **kwargs) @@ -749,7 +750,7 @@ class StartStaffSession(StaffMemberRequiredMixin, RecentAuthenticationRequiredMi ) if "next" in request.GET and url_has_allowed_host_and_scheme(request.GET.get("next"), allowed_hosts=None): - return redirect(request.GET.get("next")) + return redirect_to_url(request.GET.get("next")) else: return redirect(reverse("control:index")) diff --git a/src/pretix/helpers/http.py b/src/pretix/helpers/http.py index c8721ebba3..eec2b437c5 100644 --- a/src/pretix/helpers/http.py +++ b/src/pretix/helpers/http.py @@ -20,7 +20,9 @@ # . # from django.conf import settings -from django.http import StreamingHttpResponse +from django.http import ( + HttpResponsePermanentRedirect, HttpResponseRedirect, StreamingHttpResponse, +) class ChunkBasedFileResponse(StreamingHttpResponse): @@ -40,3 +42,8 @@ def get_client_ip(request): if x_forwarded_for: ip = x_forwarded_for.split(',')[0] return ip + + +def redirect_to_url(to, permanent=False): + redirect_class = HttpResponsePermanentRedirect if permanent else HttpResponseRedirect + return redirect_class(to) diff --git a/src/pretix/presale/views/cart.py b/src/pretix/presale/views/cart.py index 6b258f0a70..5650c65312 100644 --- a/src/pretix/presale/views/cart.py +++ b/src/pretix/presale/views/cart.py @@ -63,6 +63,7 @@ from pretix.base.services.cart import ( remove_cart_position, ) from pretix.base.views.tasks import AsyncAction +from pretix.helpers.http import redirect_to_url from pretix.multidomain.urlreverse import eventreverse from pretix.presale.views import ( CartMixin, EventViewMixin, allow_cors_if_namespaced, @@ -652,7 +653,7 @@ class RedeemView(NoSearchIndexViewMixin, EventViewMixin, CartMixin, TemplateView if err: messages.error(request, _(err)) - return redirect(self.get_next_url() + "?voucher_invalid") + return redirect_to_url(self.get_next_url() + "?voucher_invalid") return super().dispatch(request, *args, **kwargs) diff --git a/src/pretix/presale/views/customer.py b/src/pretix/presale/views/customer.py index a0cc8e6c29..e99e0f0f05 100644 --- a/src/pretix/presale/views/customer.py +++ b/src/pretix/presale/views/customer.py @@ -50,6 +50,7 @@ from pretix.base.customersso.oidc import ( from pretix.base.models import Customer, InvoiceAddress, Order, OrderPosition from pretix.base.services.mail import mail from pretix.base.settings import PERSON_NAME_SCHEMES +from pretix.helpers.http import redirect_to_url from pretix.multidomain.models import KnownDomain from pretix.multidomain.urlreverse import build_absolute_uri, eventreverse from pretix.presale.forms.customer import ( @@ -620,7 +621,7 @@ class SSOLoginView(RedirectBackMixin, View): }) if self.provider.method == "oidc": - return redirect(oidc_authorize_url(self.provider, f'{nonce}§{next_url}', redirect_uri)) + return redirect_to_url(oidc_authorize_url(self.provider, f'{nonce}§{next_url}', redirect_uri)) else: raise Http404("Unknown SSO method.") @@ -814,7 +815,7 @@ class SSOLoginReturnView(RedirectBackMixin, View): }) else: customer_login(self.request, customer) - return redirect(self.get_success_url(redirect_to)) + return redirect_to_url(self.get_success_url(redirect_to)) def _fail(self, message, popup_origin): if not popup_origin: