widgets: add check on field_id parameter for select2.json urls (#88250) #281

Merged
yweber merged 1 commits from wip/88250-select2-json-bugfix into main 2024-03-20 09:28:08 +01:00
4 changed files with 25 additions and 2 deletions

View File

@ -20,7 +20,7 @@ from functools import reduce
from django.contrib import messages
from django.contrib.auth import get_user_model
from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import PermissionDenied, ValidationError
from django.core.exceptions import BadRequest, PermissionDenied, ValidationError
from django.core.paginator import EmptyPage, Paginator
from django.db import transaction
from django.db.models import BooleanField, Count, ExpressionWrapper, F, Prefetch, Q, Value
@ -772,6 +772,8 @@ class UserOrRoleSelect2View(DetailView):
role = self.get_object()
field_id = self.kwargs.get('field_id', self.request.GET.get('field_id', None))
if not field_id:
raise BadRequest('Invalid ID')
yweber marked this conversation as resolved Outdated

L'exception à lever est plutôt HttpResponseBadRequest (c'est sûrement équivalent mais mieux vaut faire comme d'habitude)

L'exception à lever est plutôt HttpResponseBadRequest (c'est sûrement équivalent mais mieux vaut faire comme d'habitude)

A priori HttpResponseBadRequest n'est pas une classe d'exception (et ne peut pas être raise).

J'imagine que lever BadRequest renvoie une instance de HttpResponseBadRequest.

Comme on est dans une méthode qui renvoie une Response je peux renvoyer une instance de HttpResponseBadRequest, mais je trouvais ça plus clair/cohérent de raise entre les raise Http404 : dis moi ce que tu en penses.

A priori `HttpResponseBadRequest` n'est pas une classe d'exception (et ne peut pas être raise). J'imagine que lever `BadRequest` renvoie une instance de `HttpResponseBadRequest`. Comme on est dans une méthode qui renvoie une `Response` je peux renvoyer une instance de `HttpResponseBadRequest`, mais je trouvais ça plus clair/cohérent de raise entre les raise `Http404` : dis moi ce que tu en penses.

OK je viens de voir « New in Django 3.2. », pour ça qu'il y en a nulle part : let's go vivre avec son temps !

OK je viens de voir « New in Django 3.2. », pour ça qu'il y en a nulle part : let's go vivre avec son temps !
try:
crypto.loads(field_id)
except (crypto.SignatureExpired, crypto.BadSignature):

View File

@ -22,7 +22,7 @@ import pickle
import random
from django.contrib.messages.views import SuccessMessageMixin
from django.core.exceptions import PermissionDenied, ValidationError
from django.core.exceptions import BadRequest, PermissionDenied, ValidationError
from django.db import transaction
from django.forms import MediaDefiningClass
from django.http import Http404, HttpResponse
@ -837,10 +837,13 @@ class Select2View(AutoResponseView):
if not self.request.user.is_authenticated or not hasattr(self.request.user, 'filter_by_perm'):
raise Http404('Invalid user')
field_data = self.kwargs.get('field_id', self.request.GET.get('field_id', None))
if not field_data:
raise BadRequest('Invalid ID')
try:
field_data = crypto.loads(field_data)
except (crypto.SignatureExpired, crypto.BadSignature):
raise Http404('Invalid or expired signature.')
widget_class = field_data.get('class')
if not widget_class or not hasattr(widgets, widget_class):
raise Http404('Missing or unknown widget class.')

View File

@ -1476,3 +1476,9 @@ def test_manager_empty_kebab(app, admin, simple_user):
resp = login(app, admin, '/manage/users/')
assert '"extra-actions-menu-opener"' in resp
def test_manager_select2(app, superuser):
login(app, superuser)
response = app.get(reverse('django_select2-json'), expect_errors=True)
assert response.status_code == 400

View File

@ -736,6 +736,18 @@ def test_role_members_user_role_add_remove(app, superuser, settings, simple_role
resp = form.submit().maybe_follow()
def test_role_members_select2(app, superuser, simple_user, settings):
assert superuser.ou is None and simple_user.ou == get_default_ou()
r = Role.objects.create(name='role', slug='role', ou=get_default_ou())
url = reverse('a2-manager-role-members', kwargs={'pk': r.pk})
response = login(app, superuser, url)
select2_url = response.pyquery('select')[0].attrib['data-ajax--url']
select2_response = app.get(select2_url, expect_errors=True)
assert select2_response.status_code == 400
def test_role_table_ordering(app, admin):
Role.objects.create(name='a role')
Role.objects.create(name='bD role')