diff options
| author | Aymeric Augustin <aymeric.augustin@m4x.org> | 2013-02-12 11:22:41 +0100 |
|---|---|---|
| committer | Carl Meyer <carl@oddbird.net> | 2013-02-19 10:37:54 -0700 |
| commit | 0cc350a896f70ace18280410eb616a9197d862b0 (patch) | |
| tree | fd6c30263e36aa3a22058e9ffd82132d9bb760a7 /tests | |
| parent | 0e7861aec73702f7933ce2a93056f7983939f0d6 (diff) | |
[1.4.x] Added a default limit to the maximum number of forms in a formset.
This is a security fix. Disclosure and advisory coming shortly.
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/regressiontests/forms/tests/formsets.py | 70 | ||||
| -rw-r--r-- | tests/regressiontests/generic_inline_admin/tests.py | 3 |
2 files changed, 66 insertions, 7 deletions
diff --git a/tests/regressiontests/forms/tests/formsets.py b/tests/regressiontests/forms/tests/formsets.py index 05ef978c45..7c69e7e20a 100644 --- a/tests/regressiontests/forms/tests/formsets.py +++ b/tests/regressiontests/forms/tests/formsets.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from django.forms import Form, CharField, IntegerField, ValidationError, DateField +from django.forms import Form, CharField, IntegerField, ValidationError, DateField, formsets from django.forms.formsets import formset_factory, BaseFormSet from django.test import TestCase @@ -47,7 +47,7 @@ class FormsFormsetTestCase(TestCase): # for adding data. By default, it displays 1 blank form. It can display more, # but we'll look at how to do so later. formset = ChoiceFormSet(auto_id=False, prefix='choices') - self.assertHTMLEqual(str(formset), """<input type="hidden" name="choices-TOTAL_FORMS" value="1" /><input type="hidden" name="choices-INITIAL_FORMS" value="0" /><input type="hidden" name="choices-MAX_NUM_FORMS" /> + self.assertHTMLEqual(str(formset), """<input type="hidden" name="choices-TOTAL_FORMS" value="1" /><input type="hidden" name="choices-INITIAL_FORMS" value="0" /><input type="hidden" name="choices-MAX_NUM_FORMS" value="1000" /> <tr><th>Choice:</th><td><input type="text" name="choices-0-choice" /></td></tr> <tr><th>Votes:</th><td><input type="text" name="choices-0-votes" /></td></tr>""") @@ -650,8 +650,8 @@ class FormsFormsetTestCase(TestCase): # Limiting the maximum number of forms ######################################## # Base case for max_num. - # When not passed, max_num will take its default value of None, i.e. unlimited - # number of forms, only controlled by the value of the extra parameter. + # When not passed, max_num will take a high default value, leaving the + # number of forms only controlled by the value of the extra parameter. LimitedFavoriteDrinkFormSet = formset_factory(FavoriteDrinkForm, extra=3) formset = LimitedFavoriteDrinkFormSet() @@ -698,8 +698,8 @@ class FormsFormsetTestCase(TestCase): def test_max_num_with_initial_data(self): # max_num with initial data - # When not passed, max_num will take its default value of None, i.e. unlimited - # number of forms, only controlled by the values of the initial and extra + # When not passed, max_num will take a high default value, leaving the + # number of forms only controlled by the value of the initial and extra # parameters. initial = [ @@ -844,6 +844,64 @@ class FormsFormsetTestCase(TestCase): self.assertEqual(len(formset.forms), 0) self.assertTrue(formset) + def test_hard_limit_on_instantiated_forms(self): + """A formset has a hard limit on the number of forms instantiated.""" + # reduce the default limit of 1000 temporarily for testing + _old_DEFAULT_MAX_NUM = formsets.DEFAULT_MAX_NUM + try: + formsets.DEFAULT_MAX_NUM = 3 + ChoiceFormSet = formset_factory(Choice) + # someone fiddles with the mgmt form data... + formset = ChoiceFormSet( + { + 'choices-TOTAL_FORMS': '4', + 'choices-INITIAL_FORMS': '0', + 'choices-MAX_NUM_FORMS': '4', + 'choices-0-choice': 'Zero', + 'choices-0-votes': '0', + 'choices-1-choice': 'One', + 'choices-1-votes': '1', + 'choices-2-choice': 'Two', + 'choices-2-votes': '2', + 'choices-3-choice': 'Three', + 'choices-3-votes': '3', + }, + prefix='choices', + ) + # But we still only instantiate 3 forms + self.assertEqual(len(formset.forms), 3) + finally: + formsets.DEFAULT_MAX_NUM = _old_DEFAULT_MAX_NUM + + def test_increase_hard_limit(self): + """Can increase the built-in forms limit via a higher max_num.""" + # reduce the default limit of 1000 temporarily for testing + _old_DEFAULT_MAX_NUM = formsets.DEFAULT_MAX_NUM + try: + formsets.DEFAULT_MAX_NUM = 3 + # for this form, we want a limit of 4 + ChoiceFormSet = formset_factory(Choice, max_num=4) + formset = ChoiceFormSet( + { + 'choices-TOTAL_FORMS': '4', + 'choices-INITIAL_FORMS': '0', + 'choices-MAX_NUM_FORMS': '4', + 'choices-0-choice': 'Zero', + 'choices-0-votes': '0', + 'choices-1-choice': 'One', + 'choices-1-votes': '1', + 'choices-2-choice': 'Two', + 'choices-2-votes': '2', + 'choices-3-choice': 'Three', + 'choices-3-votes': '3', + }, + prefix='choices', + ) + # This time four forms are instantiated + self.assertEqual(len(formset.forms), 4) + finally: + formsets.DEFAULT_MAX_NUM = _old_DEFAULT_MAX_NUM + data = { 'choices-TOTAL_FORMS': '1', # the number of forms rendered diff --git a/tests/regressiontests/generic_inline_admin/tests.py b/tests/regressiontests/generic_inline_admin/tests.py index db81eec47a..237e396dd2 100644 --- a/tests/regressiontests/generic_inline_admin/tests.py +++ b/tests/regressiontests/generic_inline_admin/tests.py @@ -7,6 +7,7 @@ from django.contrib import admin from django.contrib.admin.sites import AdminSite from django.contrib.contenttypes.generic import ( generic_inlineformset_factory, GenericTabularInline) +from django.forms.formsets import DEFAULT_MAX_NUM from django.forms.models import ModelForm from django.test import TestCase @@ -241,7 +242,7 @@ class GenericInlineModelAdminTest(TestCase): # Create a formset with default arguments formset = media_inline.get_formset(request) - self.assertEqual(formset.max_num, None) + self.assertEqual(formset.max_num, DEFAULT_MAX_NUM) self.assertEqual(formset.can_order, False) # Create a formset with custom keyword arguments |
