Fix setlang redirect normalization for locale variants
This commit is contained in:
@@ -21,11 +21,17 @@ def normalize_set_language_next(value: str | None) -> str:
|
||||
if not path.startswith("/"):
|
||||
path = f"/{path}"
|
||||
|
||||
language_codes = [code for code, _ in settings.LANGUAGES]
|
||||
if language_codes:
|
||||
pattern = (
|
||||
rf"^/(?:{'|'.join(re.escape(code) for code in language_codes)})(?=/|$)"
|
||||
)
|
||||
path = re.sub(pattern, "", path, count=1) or "/"
|
||||
configured_codes = {
|
||||
str(code).lower().replace("_", "-") for code, _ in settings.LANGUAGES
|
||||
}
|
||||
first_segment, _, remainder = path.lstrip("/").partition("/")
|
||||
normalized_segment = first_segment.lower().replace("_", "-")
|
||||
looks_like_language_code = bool(
|
||||
re.fullmatch(r"[a-z]{2}(?:-[a-z]{2})?", normalized_segment)
|
||||
)
|
||||
should_strip = normalized_segment in configured_codes or looks_like_language_code
|
||||
|
||||
if should_strip:
|
||||
path = f"/{remainder}" if remainder else "/"
|
||||
|
||||
return urlunsplit(("", "", path, parsed.query, ""))
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from django.http import HttpRequest, HttpResponse
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
from django.views.i18n import set_language as django_set_language
|
||||
|
||||
from .i18n_utils import normalize_set_language_next
|
||||
|
||||
|
||||
@csrf_exempt
|
||||
def set_language_normalized(request: HttpRequest) -> HttpResponse:
|
||||
"""Normalize `next` before delegating to Django's set_language view."""
|
||||
if request.method == "POST":
|
||||
|
||||
@@ -29,6 +29,12 @@ class SetLanguageNormalizationTests(SimpleTestCase):
|
||||
"/manage/checkout/paymentmethod/",
|
||||
)
|
||||
|
||||
def test_normalize_set_language_next_strips_locale_variant_prefix(self):
|
||||
self.assertEqual(
|
||||
normalize_set_language_next("/en-us/manage/checkout/paymentmethod/"),
|
||||
"/manage/checkout/paymentmethod/",
|
||||
)
|
||||
|
||||
@patch("mandelstudio.i18n_views.django_set_language")
|
||||
def test_post_next_is_normalized_before_delegate(self, django_set_language):
|
||||
django_set_language.side_effect = lambda request: HttpResponseRedirect(
|
||||
@@ -61,3 +67,16 @@ class SetLanguageNormalizationTests(SimpleTestCase):
|
||||
|
||||
self.assertEqual(response.status_code, 302)
|
||||
self.assertEqual(django_set_language.call_args.args[0].GET["next"], "/manage/")
|
||||
|
||||
@patch("mandelstudio.i18n_views.django_set_language")
|
||||
def test_set_language_view_is_csrf_exempt(self, django_set_language):
|
||||
django_set_language.return_value = HttpResponseRedirect("/manage/")
|
||||
request = self.factory.post(
|
||||
"/i18n/setlang/",
|
||||
data={"language": "nl", "next": "/en/manage/"},
|
||||
)
|
||||
request.csrf_processing_done = False
|
||||
|
||||
response = set_language_normalized(request)
|
||||
|
||||
self.assertEqual(response.status_code, 302)
|
||||
|
||||
Reference in New Issue
Block a user