diff --git a/CVE-2023-31047.patch b/CVE-2023-31047.patch deleted file mode 100644 index 33c8681..0000000 --- a/CVE-2023-31047.patch +++ /dev/null @@ -1,322 +0,0 @@ -From 7c240c2f1030daf455f04b163fa9807d6bb2a21a Mon Sep 17 00:00:00 2001 -From: starlet-dx <15929766099@163.com> -Date: Tue, 16 May 2023 11:23:26 +0800 -Subject: [PATCH 1/1] [4.1.x] Fixed CVE-2023-31047, Fixed #31710 -- Prevented - potential bypass of validation when uploading multiple files using one form - field. - -Thanks Moataz Al-Sharida and nawaik for reports. - -Co-authored-by: Shai Berger -Co-authored-by: nessita <124304+nessita@users.noreply.github.com> - -Origin: -https://github.com/django/django/commit/e7c3a2ccc3a562328600be05068ed9149e12ce64 ---- - django/forms/widgets.py | 26 ++++++- - docs/topics/http/file-uploads.txt | 64 +++++++++++++++-- - .../forms_tests/field_tests/test_filefield.py | 68 ++++++++++++++++++- - .../widget_tests/test_clearablefileinput.py | 5 ++ - .../widget_tests/test_fileinput.py | 44 ++++++++++++ - 5 files changed, 199 insertions(+), 8 deletions(-) - -diff --git a/django/forms/widgets.py b/django/forms/widgets.py -index 972267b..ce0d4f7 100644 ---- a/django/forms/widgets.py -+++ b/django/forms/widgets.py -@@ -413,17 +413,41 @@ class MultipleHiddenInput(HiddenInput): - - - class FileInput(Input): -+ allow_multiple_selected = False - input_type = "file" - needs_multipart_form = True - template_name = "django/forms/widgets/file.html" - -+ def __init__(self, attrs=None): -+ if ( -+ attrs is not None -+ and not self.allow_multiple_selected -+ and attrs.get("multiple", False) -+ ): -+ raise ValueError( -+ "%s doesn't support uploading multiple files." -+ % self.__class__.__qualname__ -+ ) -+ if self.allow_multiple_selected: -+ if attrs is None: -+ attrs = {"multiple": True} -+ else: -+ attrs.setdefault("multiple", True) -+ super().__init__(attrs) -+ - def format_value(self, value): - """File input never renders a value.""" - return - - def value_from_datadict(self, data, files, name): - "File widgets take data from FILES, not POST" -- return files.get(name) -+ getter = files.get -+ if self.allow_multiple_selected: -+ try: -+ getter = files.getlist -+ except AttributeError: -+ pass -+ return getter(name) - - def value_omitted_from_data(self, data, files, name): - return name not in files -diff --git a/docs/topics/http/file-uploads.txt b/docs/topics/http/file-uploads.txt -index 94b7432..52a7f09 100644 ---- a/docs/topics/http/file-uploads.txt -+++ b/docs/topics/http/file-uploads.txt -@@ -139,19 +139,53 @@ a :class:`~django.core.files.File` like object to the - instance = ModelWithFileField(file_field=content_file) - instance.save() - -+.. _uploading_multiple_files: -+ - Uploading multiple files - ------------------------ - --If you want to upload multiple files using one form field, set the ``multiple`` --HTML attribute of field's widget: -+.. -+ Tests in tests.forms_tests.field_tests.test_filefield.MultipleFileFieldTest -+ should be updated after any changes in the following snippets. -+ -+If you want to upload multiple files using one form field, create a subclass -+of the field's widget and set the ``allow_multiple_selected`` attribute on it -+to ``True``. -+ -+In order for such files to be all validated by your form (and have the value of -+the field include them all), you will also have to subclass ``FileField``. See -+below for an example. -+ -+.. admonition:: Multiple file field -+ -+ Django is likely to have a proper multiple file field support at some point -+ in the future. - - .. code-block:: python - :caption: ``forms.py`` - - from django import forms - -+ class MultipleFileInput(forms.ClearableFileInput): -+ allow_multiple_selected = True -+ -+ -+ class MultipleFileField(forms.FileField): -+ def __init__(self, *args, **kwargs): -+ kwargs.setdefault("widget", MultipleFileInput()) -+ super().__init__(*args, **kwargs) -+ -+ def clean(self, data, initial=None): -+ single_file_clean = super().clean -+ if isinstance(data, (list, tuple)): -+ result = [single_file_clean(d, initial) for d in data] -+ else: -+ result = single_file_clean(data, initial) -+ return result -+ -+ - class FileFieldForm(forms.Form): -- file_field = forms.FileField(widget=forms.ClearableFileInput(attrs={'multiple': True})) -+ file_field = MultipleFileField() - - Then override the ``post`` method of your - :class:`~django.views.generic.edit.FormView` subclass to handle multiple file -@@ -171,14 +205,32 @@ uploads: - def post(self, request, *args, **kwargs): - form_class = self.get_form_class() - form = self.get_form(form_class) -- files = request.FILES.getlist('file_field') - if form.is_valid(): -- for f in files: -- ... # Do something with each file. - return self.form_valid(form) - else: - return self.form_invalid(form) - -+ def form_valid(self, form): -+ files = form.cleaned_data["file_field"] -+ for f in files: -+ ... # Do something with each file. -+ return super().form_valid() -+ -+.. warning:: -+ -+ This will allow you to handle multiple files at the form level only. Be -+ aware that you cannot use it to put multiple files on a single model -+ instance (in a single field), for example, even if the custom widget is used -+ with a form field related to a model ``FileField``. -+ -+.. versionchanged:: 3.2.19 -+ -+ In previous versions, there was no support for the ``allow_multiple_selected`` -+ class attribute, and users were advised to create the widget with the HTML -+ attribute ``multiple`` set through the ``attrs`` argument. However, this -+ caused validation of the form field to be applied only to the last file -+ submitted, which could have adverse security implications. -+ - Upload Handlers - =============== - -diff --git a/tests/forms_tests/field_tests/test_filefield.py b/tests/forms_tests/field_tests/test_filefield.py -index 56aaa31..00c74a7 100644 ---- a/tests/forms_tests/field_tests/test_filefield.py -+++ b/tests/forms_tests/field_tests/test_filefield.py -@@ -2,7 +2,8 @@ import pickle - - from django.core.exceptions import ValidationError - from django.core.files.uploadedfile import SimpleUploadedFile --from django.forms import FileField -+from django.core.validators import validate_image_file_extension -+from django.forms import FileField, FileInput - from django.test import SimpleTestCase - - -@@ -109,3 +110,68 @@ class FileFieldTest(SimpleTestCase): - - def test_file_picklable(self): - self.assertIsInstance(pickle.loads(pickle.dumps(FileField())), FileField) -+ -+ -+class MultipleFileInput(FileInput): -+ allow_multiple_selected = True -+ -+ -+class MultipleFileField(FileField): -+ def __init__(self, *args, **kwargs): -+ kwargs.setdefault("widget", MultipleFileInput()) -+ super().__init__(*args, **kwargs) -+ -+ def clean(self, data, initial=None): -+ single_file_clean = super().clean -+ if isinstance(data, (list, tuple)): -+ result = [single_file_clean(d, initial) for d in data] -+ else: -+ result = single_file_clean(data, initial) -+ return result -+ -+ -+class MultipleFileFieldTest(SimpleTestCase): -+ def test_file_multiple(self): -+ f = MultipleFileField() -+ files = [ -+ SimpleUploadedFile("name1", b"Content 1"), -+ SimpleUploadedFile("name2", b"Content 2"), -+ ] -+ self.assertEqual(f.clean(files), files) -+ -+ def test_file_multiple_empty(self): -+ f = MultipleFileField() -+ files = [ -+ SimpleUploadedFile("empty", b""), -+ SimpleUploadedFile("nonempty", b"Some Content"), -+ ] -+ msg = "'The submitted file is empty.'" -+ with self.assertRaisesMessage(ValidationError, msg): -+ f.clean(files) -+ with self.assertRaisesMessage(ValidationError, msg): -+ f.clean(files[::-1]) -+ -+ def test_file_multiple_validation(self): -+ f = MultipleFileField(validators=[validate_image_file_extension]) -+ -+ good_files = [ -+ SimpleUploadedFile("image1.jpg", b"fake JPEG"), -+ SimpleUploadedFile("image2.png", b"faux image"), -+ SimpleUploadedFile("image3.bmp", b"fraudulent bitmap"), -+ ] -+ self.assertEqual(f.clean(good_files), good_files) -+ -+ evil_files = [ -+ SimpleUploadedFile("image1.sh", b"#!/bin/bash -c 'echo pwned!'\n"), -+ SimpleUploadedFile("image2.png", b"faux image"), -+ SimpleUploadedFile("image3.jpg", b"fake JPEG"), -+ ] -+ -+ evil_rotations = ( -+ evil_files[i:] + evil_files[:i] # Rotate by i. -+ for i in range(len(evil_files)) -+ ) -+ msg = "File extension “sh” is not allowed. Allowed extensions are: " -+ for rotated_evil_files in evil_rotations: -+ with self.assertRaisesMessage(ValidationError, msg): -+ f.clean(rotated_evil_files) -diff --git a/tests/forms_tests/widget_tests/test_clearablefileinput.py b/tests/forms_tests/widget_tests/test_clearablefileinput.py -index fb6a2f6..0b34335 100644 ---- a/tests/forms_tests/widget_tests/test_clearablefileinput.py -+++ b/tests/forms_tests/widget_tests/test_clearablefileinput.py -@@ -232,3 +232,8 @@ class ClearableFileInputTest(WidgetTest): - '', - form.render(), - ) -+ -+ def test_multiple_error(self): -+ msg = "ClearableFileInput doesn't support uploading multiple files." -+ with self.assertRaisesMessage(ValueError, msg): -+ ClearableFileInput(attrs={"multiple": True}) -diff --git a/tests/forms_tests/widget_tests/test_fileinput.py b/tests/forms_tests/widget_tests/test_fileinput.py -index ea73e57..a49f481 100644 ---- a/tests/forms_tests/widget_tests/test_fileinput.py -+++ b/tests/forms_tests/widget_tests/test_fileinput.py -@@ -1,4 +1,6 @@ -+from django.core.files.uploadedfile import SimpleUploadedFile - from django.forms import FileField, FileInput, Form -+from django.utils.datastructures import MultiValueDict - - from .base import WidgetTest - -@@ -48,3 +50,45 @@ class FileInputTest(WidgetTest): - 'name="field" required type="file">', - form.render(), - ) -+ -+ def test_multiple_error(self): -+ msg = "FileInput doesn't support uploading multiple files." -+ with self.assertRaisesMessage(ValueError, msg): -+ FileInput(attrs={"multiple": True}) -+ -+ def test_value_from_datadict_multiple(self): -+ class MultipleFileInput(FileInput): -+ allow_multiple_selected = True -+ -+ file_1 = SimpleUploadedFile("something1.txt", b"content 1") -+ file_2 = SimpleUploadedFile("something2.txt", b"content 2") -+ # Uploading multiple files is allowed. -+ widget = MultipleFileInput(attrs={"multiple": True}) -+ value = widget.value_from_datadict( -+ data={"name": "Test name"}, -+ files=MultiValueDict({"myfile": [file_1, file_2]}), -+ name="myfile", -+ ) -+ self.assertEqual(value, [file_1, file_2]) -+ # Uploading multiple files is not allowed. -+ widget = FileInput() -+ value = widget.value_from_datadict( -+ data={"name": "Test name"}, -+ files=MultiValueDict({"myfile": [file_1, file_2]}), -+ name="myfile", -+ ) -+ self.assertEqual(value, file_2) -+ -+ def test_multiple_default(self): -+ class MultipleFileInput(FileInput): -+ allow_multiple_selected = True -+ -+ tests = [ -+ (None, True), -+ ({"class": "myclass"}, True), -+ ({"multiple": False}, False), -+ ] -+ for attrs, expected in tests: -+ with self.subTest(attrs=attrs): -+ widget = MultipleFileInput(attrs=attrs) -+ self.assertIs(widget.attrs["multiple"], expected) --- -2.30.0 - diff --git a/django-4.1.7.tar.gz b/Django-4.2.3.tar.gz similarity index 56% rename from django-4.1.7.tar.gz rename to Django-4.2.3.tar.gz index 33db06a..7ba120f 100644 Binary files a/django-4.1.7.tar.gz and b/Django-4.2.3.tar.gz differ diff --git a/python-django.spec b/python-django.spec index 38836bd..86d1e07 100644 --- a/python-django.spec +++ b/python-django.spec @@ -1,12 +1,11 @@ %global _empty_manifest_terminate_build 0 Name: python-django -Version: 4.1.7 -Release: 2 +Version: 4.2.3 +Release: 1 Summary: A high-level Python Web framework that encourages rapid development and clean, pragmatic design. License: Apache-2.0 and Python-2.0 and BSD-3-Clause URL: https://www.djangoproject.com/ -Source0: https://github.com/django/django/archive/%{version}/django-%{version}.tar.gz -Patch0: CVE-2023-31047.patch +Source0: https://files.pythonhosted.org/packages/36/24/d0e78e667f98efcca76c8b670ef247583349a8f5241cdb3c98eeb92726ff/Django-4.2.3.tar.gz BuildArch: noarch %description @@ -33,7 +32,7 @@ Provides: python3-Django-doc Development documents and examples for Django %prep -%autosetup -n django-%{version} -p1 +%autosetup -n Django-%{version} -p1 %build %py3_build @@ -73,6 +72,9 @@ mv %{buildroot}/doclist.lst . %{_docdir}/* %changelog +* Tue Jul 11 2023 chenzixuan - 4.2.3-1 +- Update to 4.2.3 + * Tue May 16 2023 yaoxin - 4.1.7-2 - Fix CVE-2023-31047