mirror of
https://github.com/django/django.git
synced 2025-01-03 06:55:47 +00:00
Fixed #28201 -- Added ProhibitNullCharactersValidator and used it on CharField form field.
This commit is contained in:
parent
b78d100fa6
commit
90d7b912b9
@ -503,3 +503,27 @@ def get_available_image_extensions():
|
|||||||
validate_image_file_extension = FileExtensionValidator(
|
validate_image_file_extension = FileExtensionValidator(
|
||||||
allowed_extensions=get_available_image_extensions(),
|
allowed_extensions=get_available_image_extensions(),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@deconstructible
|
||||||
|
class ProhibitNullCharactersValidator:
|
||||||
|
"""Validate that the string doesn't contain the null character."""
|
||||||
|
message = _('Null characters are not allowed.')
|
||||||
|
code = 'null_characters_not_allowed'
|
||||||
|
|
||||||
|
def __init__(self, message=None, code=None):
|
||||||
|
if message is not None:
|
||||||
|
self.message = message
|
||||||
|
if code is not None:
|
||||||
|
self.code = code
|
||||||
|
|
||||||
|
def __call__(self, value):
|
||||||
|
if '\x00' in str(value):
|
||||||
|
raise ValidationError(self.message, code=self.code)
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
return (
|
||||||
|
isinstance(other, self.__class__) and
|
||||||
|
self.message == other.message and
|
||||||
|
self.code == other.code
|
||||||
|
)
|
||||||
|
@ -217,6 +217,7 @@ class CharField(Field):
|
|||||||
self.validators.append(validators.MinLengthValidator(int(min_length)))
|
self.validators.append(validators.MinLengthValidator(int(min_length)))
|
||||||
if max_length is not None:
|
if max_length is not None:
|
||||||
self.validators.append(validators.MaxLengthValidator(int(max_length)))
|
self.validators.append(validators.MaxLengthValidator(int(max_length)))
|
||||||
|
self.validators.append(validators.ProhibitNullCharactersValidator())
|
||||||
|
|
||||||
def to_python(self, value):
|
def to_python(self, value):
|
||||||
"""Return a string."""
|
"""Return a string."""
|
||||||
|
@ -304,3 +304,27 @@ to, or in lieu of custom ``field.clean()`` methods.
|
|||||||
Uses Pillow to ensure that ``value.name`` (``value`` is a
|
Uses Pillow to ensure that ``value.name`` (``value`` is a
|
||||||
:class:`~django.core.files.File`) has `a valid image extension
|
:class:`~django.core.files.File`) has `a valid image extension
|
||||||
<https://pillow.readthedocs.io/en/latest/handbook/image-file-formats.html>`_.
|
<https://pillow.readthedocs.io/en/latest/handbook/image-file-formats.html>`_.
|
||||||
|
|
||||||
|
``ProhibitNullCharactersValidator``
|
||||||
|
-----------------------------------
|
||||||
|
|
||||||
|
.. class:: ProhibitNullCharactersValidator(message=None, code=None)
|
||||||
|
|
||||||
|
.. versionadded:: 2.0
|
||||||
|
|
||||||
|
Raises a :exc:`~django.core.exceptions.ValidationError` if ``str(value)``
|
||||||
|
contains one or more nulls characters (``'\x00'``).
|
||||||
|
|
||||||
|
:param message: If not ``None``, overrides :attr:`.message`.
|
||||||
|
:param code: If not ``None``, overrides :attr:`code`.
|
||||||
|
|
||||||
|
.. attribute:: message
|
||||||
|
|
||||||
|
The error message used by
|
||||||
|
:exc:`~django.core.exceptions.ValidationError` if validation fails.
|
||||||
|
Defaults to ``"Null characters are not allowed."``.
|
||||||
|
|
||||||
|
.. attribute:: code
|
||||||
|
|
||||||
|
The error code used by :exc:`~django.core.exceptions.ValidationError`
|
||||||
|
if validation fails. Defaults to ``"null_characters_not_allowed"``.
|
||||||
|
@ -318,7 +318,12 @@ URLs
|
|||||||
Validators
|
Validators
|
||||||
~~~~~~~~~~
|
~~~~~~~~~~
|
||||||
|
|
||||||
* ...
|
* The new :class:`.ProhibitNullCharactersValidator` disallows the null
|
||||||
|
character in the input of the :class:`~django.forms.CharField` form field
|
||||||
|
and its subclasses. Null character input was observed from vulnerability
|
||||||
|
scanning tools. Most databases silently discard null characters, but
|
||||||
|
psycopg2 2.7+ raises an exception when trying to save a null character to
|
||||||
|
a char/text field with PostgreSQL.
|
||||||
|
|
||||||
.. _backwards-incompatible-2.0:
|
.. _backwards-incompatible-2.0:
|
||||||
|
|
||||||
|
@ -123,3 +123,9 @@ class CharFieldTest(FormFieldAssertionsMixin, SimpleTestCase):
|
|||||||
def test_charfield_disabled(self):
|
def test_charfield_disabled(self):
|
||||||
f = CharField(disabled=True)
|
f = CharField(disabled=True)
|
||||||
self.assertWidgetRendersTo(f, '<input type="text" name="f" id="id_f" disabled required />')
|
self.assertWidgetRendersTo(f, '<input type="text" name="f" id="id_f" disabled required />')
|
||||||
|
|
||||||
|
def test_null_characters_prohibited(self):
|
||||||
|
f = CharField()
|
||||||
|
msg = 'Null characters are not allowed.'
|
||||||
|
with self.assertRaisesMessage(ValidationError, msg):
|
||||||
|
f.clean('\x00something')
|
||||||
|
@ -9,11 +9,11 @@ from django.core.files.base import ContentFile
|
|||||||
from django.core.validators import (
|
from django.core.validators import (
|
||||||
BaseValidator, DecimalValidator, EmailValidator, FileExtensionValidator,
|
BaseValidator, DecimalValidator, EmailValidator, FileExtensionValidator,
|
||||||
MaxLengthValidator, MaxValueValidator, MinLengthValidator,
|
MaxLengthValidator, MaxValueValidator, MinLengthValidator,
|
||||||
MinValueValidator, RegexValidator, URLValidator, int_list_validator,
|
MinValueValidator, ProhibitNullCharactersValidator, RegexValidator,
|
||||||
validate_comma_separated_integer_list, validate_email,
|
URLValidator, int_list_validator, validate_comma_separated_integer_list,
|
||||||
validate_image_file_extension, validate_integer, validate_ipv4_address,
|
validate_email, validate_image_file_extension, validate_integer,
|
||||||
validate_ipv6_address, validate_ipv46_address, validate_slug,
|
validate_ipv4_address, validate_ipv6_address, validate_ipv46_address,
|
||||||
validate_unicode_slug,
|
validate_slug, validate_unicode_slug,
|
||||||
)
|
)
|
||||||
from django.test import SimpleTestCase
|
from django.test import SimpleTestCase
|
||||||
|
|
||||||
@ -264,6 +264,10 @@ TEST_DATA = [
|
|||||||
(validate_image_file_extension, ContentFile('contents', name='file.PNG'), None),
|
(validate_image_file_extension, ContentFile('contents', name='file.PNG'), None),
|
||||||
(validate_image_file_extension, ContentFile('contents', name='file.txt'), ValidationError),
|
(validate_image_file_extension, ContentFile('contents', name='file.txt'), ValidationError),
|
||||||
(validate_image_file_extension, ContentFile('contents', name='file'), ValidationError),
|
(validate_image_file_extension, ContentFile('contents', name='file'), ValidationError),
|
||||||
|
|
||||||
|
(ProhibitNullCharactersValidator(), '\x00something', ValidationError),
|
||||||
|
(ProhibitNullCharactersValidator(), 'something', None),
|
||||||
|
(ProhibitNullCharactersValidator(), None, None),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@ -488,3 +492,21 @@ class TestValidatorEquality(TestCase):
|
|||||||
FileExtensionValidator(['txt']),
|
FileExtensionValidator(['txt']),
|
||||||
FileExtensionValidator(['txt'], message='custom error message')
|
FileExtensionValidator(['txt'], message='custom error message')
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_prohibit_null_characters_validator_equality(self):
|
||||||
|
self.assertEqual(
|
||||||
|
ProhibitNullCharactersValidator(message='message', code='code'),
|
||||||
|
ProhibitNullCharactersValidator(message='message', code='code')
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
ProhibitNullCharactersValidator(),
|
||||||
|
ProhibitNullCharactersValidator()
|
||||||
|
)
|
||||||
|
self.assertNotEqual(
|
||||||
|
ProhibitNullCharactersValidator(message='message1', code='code'),
|
||||||
|
ProhibitNullCharactersValidator(message='message2', code='code')
|
||||||
|
)
|
||||||
|
self.assertNotEqual(
|
||||||
|
ProhibitNullCharactersValidator(message='message', code='code1'),
|
||||||
|
ProhibitNullCharactersValidator(message='message', code='code2')
|
||||||
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user