diff options
-rw-r--r-- | pkgs/applications/version-management/git/default.nix | 4 | ||||
-rw-r--r-- | pkgs/development/libraries/glib/default.nix | 4 | ||||
-rw-r--r-- | pkgs/development/libraries/glibc/2.38-master.patch.gz | bin | 79225 -> 89075 bytes | |||
-rw-r--r-- | pkgs/development/libraries/glibc/common.nix | 4 | ||||
-rw-r--r-- | pkgs/development/libraries/tpm2-tss/default.nix | 4 | ||||
-rw-r--r-- | pkgs/development/python-modules/aiohttp/3.8.6-CVE-2024-30251.patch | 665 | ||||
-rw-r--r-- | pkgs/development/python-modules/aiohttp/default.nix | 1 | ||||
-rw-r--r-- | pkgs/development/python-modules/django/4.nix | 16 | ||||
-rw-r--r-- | pkgs/development/python-modules/python-jose/default.nix | 14 | ||||
-rw-r--r-- | pkgs/os-specific/linux/util-linux/default.nix | 8 | ||||
-rw-r--r-- | pkgs/servers/sql/postgresql/default.nix | 20 |
11 files changed, 715 insertions, 25 deletions
diff --git a/pkgs/applications/version-management/git/default.nix b/pkgs/applications/version-management/git/default.nix index 1b92778e65ccb..3339575b7391b 100644 --- a/pkgs/applications/version-management/git/default.nix +++ b/pkgs/applications/version-management/git/default.nix @@ -29,7 +29,7 @@ assert sendEmailSupport -> perlSupport; assert svnSupport -> perlSupport; let - version = "2.42.0"; + version = "2.42.2"; svn = subversionClient.override { perlBindings = perlSupport; }; gitwebPerlLibs = with perlPackages; [ CGI HTMLParser CGIFast FCGI FCGIProcManager HTMLTagCloud ]; in @@ -42,7 +42,7 @@ stdenv.mkDerivation (finalAttrs: { src = fetchurl { url = "https://www.kernel.org/pub/software/scm/git/git-${version}.tar.xz"; - hash = "sha256-MnghDp/SmUuEhN1+Pd2eqLlA71IXDNtgbaqU2IfJOw0="; + hash = "sha256-R3/xAbahVqS88JyOh0KT6pvBr8vGvHo9b50KL0lwkEQ="; }; outputs = [ "out" ] ++ lib.optional withManual "doc"; diff --git a/pkgs/development/libraries/glib/default.nix b/pkgs/development/libraries/glib/default.nix index fa3936386ed97..5a9a07fdd2b15 100644 --- a/pkgs/development/libraries/glib/default.nix +++ b/pkgs/development/libraries/glib/default.nix @@ -50,11 +50,11 @@ in stdenv.mkDerivation (finalAttrs: { pname = "glib"; - version = "2.78.4"; + version = "2.78.6"; src = fetchurl { url = "mirror://gnome/sources/glib/${lib.versions.majorMinor finalAttrs.version}/glib-${finalAttrs.version}.tar.xz"; - sha256 = "sha256-JLjgZy3KEgzDLTlLzLhYROcy4E/nXRi7BXOy28dUj2M="; + sha256 = "sha256-JEhUZU3YLH68svjiRhVtKgXrnNGtB+16d5ZZtGAsn64="; }; patches = lib.optionals stdenv.isDarwin [ diff --git a/pkgs/development/libraries/glibc/2.38-master.patch.gz b/pkgs/development/libraries/glibc/2.38-master.patch.gz index 4b9fd43a54e35..3babd2f706dfa 100644 --- a/pkgs/development/libraries/glibc/2.38-master.patch.gz +++ b/pkgs/development/libraries/glibc/2.38-master.patch.gz Binary files differdiff --git a/pkgs/development/libraries/glibc/common.nix b/pkgs/development/libraries/glibc/common.nix index 649b81980f10e..90d6e0fc1c29f 100644 --- a/pkgs/development/libraries/glibc/common.nix +++ b/pkgs/development/libraries/glibc/common.nix @@ -44,7 +44,7 @@ let version = "2.38"; - patchSuffix = "-66"; + patchSuffix = "-77"; sha256 = "sha256-+4KZiZiyspllRnvBtp0VLpwwfSzzAcnq+0VVt3DvP9I="; in @@ -60,7 +60,7 @@ stdenv.mkDerivation ({ [ /* No tarballs for stable upstream branch, only https://sourceware.org/git/glibc.git and using git would complicate bootstrapping. $ git fetch --all -p && git checkout origin/release/2.38/master && git describe - glibc-2.38-66-ge1135387de + glibc-2.38-77-gf510d75ff7 $ git show --minimal --reverse glibc-2.38.. | gzip -9n --rsyncable - > 2.38-master.patch.gz To compare the archive contents zdiff can be used. diff --git a/pkgs/development/libraries/tpm2-tss/default.nix b/pkgs/development/libraries/tpm2-tss/default.nix index 628f32a91c69d..d6bd6c94d27fe 100644 --- a/pkgs/development/libraries/tpm2-tss/default.nix +++ b/pkgs/development/libraries/tpm2-tss/default.nix @@ -15,13 +15,13 @@ in stdenv.mkDerivation rec { pname = "tpm2-tss"; - version = "4.0.1"; + version = "4.0.2"; src = fetchFromGitHub { owner = "tpm2-software"; repo = pname; rev = version; - sha256 = "sha256-75yiKVZrR1vcCwKp4tDO4A9JB0KDM0MXPJ1N85kAaRk="; + hash = "sha256-8JQxv0NPnUZCJsUAJ9J40GVfJs4nXyM1zRobL+h7gos="; }; outputs = [ "out" "man" "dev" ]; diff --git a/pkgs/development/python-modules/aiohttp/3.8.6-CVE-2024-30251.patch b/pkgs/development/python-modules/aiohttp/3.8.6-CVE-2024-30251.patch new file mode 100644 index 0000000000000..bc5cac9c47d03 --- /dev/null +++ b/pkgs/development/python-modules/aiohttp/3.8.6-CVE-2024-30251.patch @@ -0,0 +1,665 @@ +From 87893e51b9425487017b132a9ef11ecb32a1e36f Mon Sep 17 00:00:00 2001 +From: Sam Bull <git@sambull.org> +Date: Sun, 7 Apr 2024 13:19:31 +0100 +Subject: [PATCH 1/3] Fix handling of multipart/form-data (#8280) (#8302) + +https://datatracker.ietf.org/doc/html/rfc7578 +(cherry picked from commit 7d0be3fee540a3d4161ac7dc76422f1f5ea60104) +(cherry picked from commit cebe526b9c34dc3a3da9140409db63014bc4cf19) +--- + CHANGES/8280.bugfix.rst | 1 + + CHANGES/8280.deprecation.rst | 2 + + aiohttp/formdata.py | 12 +++- + aiohttp/multipart.py | 121 +++++++++++++++++++++----------- + tests/test_client_functional.py | 44 +----------- + tests/test_multipart.py | 68 ++++++++++++++---- + tests/test_web_functional.py | 27 ++----- + 7 files changed, 155 insertions(+), 120 deletions(-) + create mode 100644 CHANGES/8280.bugfix.rst + create mode 100644 CHANGES/8280.deprecation.rst + +diff --git a/CHANGES/8280.bugfix.rst b/CHANGES/8280.bugfix.rst +new file mode 100644 +index 00000000..3aebe36f +--- /dev/null ++++ b/CHANGES/8280.bugfix.rst +@@ -0,0 +1 @@ ++Fixed ``multipart/form-data`` compliance with :rfc:`7578` -- by :user:`Dreamsorcerer`. +diff --git a/CHANGES/8280.deprecation.rst b/CHANGES/8280.deprecation.rst +new file mode 100644 +index 00000000..302dbb2f +--- /dev/null ++++ b/CHANGES/8280.deprecation.rst +@@ -0,0 +1,2 @@ ++Deprecated ``content_transfer_encoding`` parameter in :py:meth:`FormData.add_field() ++<aiohttp.FormData.add_field>` -- by :user:`Dreamsorcerer`. +diff --git a/aiohttp/formdata.py b/aiohttp/formdata.py +index e7cd24ca..2b75b3de 100644 +--- a/aiohttp/formdata.py ++++ b/aiohttp/formdata.py +@@ -1,4 +1,5 @@ + import io ++import warnings + from typing import Any, Iterable, List, Optional + from urllib.parse import urlencode + +@@ -53,7 +54,12 @@ class FormData: + if isinstance(value, io.IOBase): + self._is_multipart = True + elif isinstance(value, (bytes, bytearray, memoryview)): ++ msg = ( ++ "In v4, passing bytes will no longer create a file field. " ++ "Please explicitly use the filename parameter or pass a BytesIO object." ++ ) + if filename is None and content_transfer_encoding is None: ++ warnings.warn(msg, DeprecationWarning) + filename = name + + type_options: MultiDict[str] = MultiDict({"name": name}) +@@ -81,7 +87,11 @@ class FormData: + "content_transfer_encoding must be an instance" + " of str. Got: %s" % content_transfer_encoding + ) +- headers[hdrs.CONTENT_TRANSFER_ENCODING] = content_transfer_encoding ++ msg = ( ++ "content_transfer_encoding is deprecated. " ++ "To maintain compatibility with v4 please pass a BytesPayload." ++ ) ++ warnings.warn(msg, DeprecationWarning) + self._is_multipart = True + + self._fields.append((type_options, headers, value)) +diff --git a/aiohttp/multipart.py b/aiohttp/multipart.py +index 73801f45..0e2e6f85 100644 +--- a/aiohttp/multipart.py ++++ b/aiohttp/multipart.py +@@ -255,13 +255,22 @@ class BodyPartReader: + chunk_size = 8192 + + def __init__( +- self, boundary: bytes, headers: "CIMultiDictProxy[str]", content: StreamReader ++ self, ++ boundary: bytes, ++ headers: "CIMultiDictProxy[str]", ++ content: StreamReader, ++ *, ++ subtype: str = "mixed", ++ default_charset: Optional[str] = None, + ) -> None: + self.headers = headers + self._boundary = boundary + self._content = content ++ self._default_charset = default_charset + self._at_eof = False +- length = self.headers.get(CONTENT_LENGTH, None) ++ self._is_form_data = subtype == "form-data" ++ # https://datatracker.ietf.org/doc/html/rfc7578#section-4.8 ++ length = None if self._is_form_data else self.headers.get(CONTENT_LENGTH, None) + self._length = int(length) if length is not None else None + self._read_bytes = 0 + # TODO: typeing.Deque is not supported by Python 3.5 +@@ -329,6 +338,8 @@ class BodyPartReader: + assert self._length is not None, "Content-Length required for chunked read" + chunk_size = min(size, self._length - self._read_bytes) + chunk = await self._content.read(chunk_size) ++ if self._content.at_eof(): ++ self._at_eof = True + return chunk + + async def _read_chunk_from_stream(self, size: int) -> bytes: +@@ -444,7 +455,8 @@ class BodyPartReader: + """ + if CONTENT_TRANSFER_ENCODING in self.headers: + data = self._decode_content_transfer(data) +- if CONTENT_ENCODING in self.headers: ++ # https://datatracker.ietf.org/doc/html/rfc7578#section-4.8 ++ if not self._is_form_data and CONTENT_ENCODING in self.headers: + return self._decode_content(data) + return data + +@@ -478,7 +490,7 @@ class BodyPartReader: + """Returns charset parameter from Content-Type header or default.""" + ctype = self.headers.get(CONTENT_TYPE, "") + mimetype = parse_mimetype(ctype) +- return mimetype.parameters.get("charset", default) ++ return mimetype.parameters.get("charset", self._default_charset or default) + + @reify + def name(self) -> Optional[str]: +@@ -533,9 +545,17 @@ class MultipartReader: + part_reader_cls = BodyPartReader + + def __init__(self, headers: Mapping[str, str], content: StreamReader) -> None: ++ self._mimetype = parse_mimetype(headers[CONTENT_TYPE]) ++ assert self._mimetype.type == "multipart", "multipart/* content type expected" ++ if "boundary" not in self._mimetype.parameters: ++ raise ValueError( ++ "boundary missed for Content-Type: %s" % headers[CONTENT_TYPE] ++ ) ++ + self.headers = headers + self._boundary = ("--" + self._get_boundary()).encode() + self._content = content ++ self._default_charset: Optional[str] = None + self._last_part: Optional[Union["MultipartReader", BodyPartReader]] = None + self._at_eof = False + self._at_bof = True +@@ -587,7 +607,24 @@ class MultipartReader: + await self._read_boundary() + if self._at_eof: # we just read the last boundary, nothing to do there + return None +- self._last_part = await self.fetch_next_part() ++ ++ part = await self.fetch_next_part() ++ # https://datatracker.ietf.org/doc/html/rfc7578#section-4.6 ++ if ( ++ self._last_part is None ++ and self._mimetype.subtype == "form-data" ++ and isinstance(part, BodyPartReader) ++ ): ++ _, params = parse_content_disposition(part.headers.get(CONTENT_DISPOSITION)) ++ if params.get("name") == "_charset_": ++ # Longest encoding in https://encoding.spec.whatwg.org/encodings.json ++ # is 19 characters, so 32 should be more than enough for any valid encoding. ++ charset = await part.read_chunk(32) ++ if len(charset) > 31: ++ raise RuntimeError("Invalid default charset") ++ self._default_charset = charset.strip().decode() ++ part = await self.fetch_next_part() ++ self._last_part = part + return self._last_part + + async def release(self) -> None: +@@ -623,19 +660,16 @@ class MultipartReader: + return type(self)(headers, self._content) + return self.multipart_reader_cls(headers, self._content) + else: +- return self.part_reader_cls(self._boundary, headers, self._content) +- +- def _get_boundary(self) -> str: +- mimetype = parse_mimetype(self.headers[CONTENT_TYPE]) +- +- assert mimetype.type == "multipart", "multipart/* content type expected" +- +- if "boundary" not in mimetype.parameters: +- raise ValueError( +- "boundary missed for Content-Type: %s" % self.headers[CONTENT_TYPE] ++ return self.part_reader_cls( ++ self._boundary, ++ headers, ++ self._content, ++ subtype=self._mimetype.subtype, ++ default_charset=self._default_charset, + ) + +- boundary = mimetype.parameters["boundary"] ++ def _get_boundary(self) -> str: ++ boundary = self._mimetype.parameters["boundary"] + if len(boundary) > 70: + raise ValueError("boundary %r is too long (70 chars max)" % boundary) + +@@ -726,6 +760,7 @@ class MultipartWriter(Payload): + super().__init__(None, content_type=ctype) + + self._parts: List[_Part] = [] ++ self._is_form_data = subtype == "form-data" + + def __enter__(self) -> "MultipartWriter": + return self +@@ -803,32 +838,36 @@ class MultipartWriter(Payload): + + def append_payload(self, payload: Payload) -> Payload: + """Adds a new body part to multipart writer.""" +- # compression +- encoding: Optional[str] = payload.headers.get( +- CONTENT_ENCODING, +- "", +- ).lower() +- if encoding and encoding not in ("deflate", "gzip", "identity"): +- raise RuntimeError(f"unknown content encoding: {encoding}") +- if encoding == "identity": +- encoding = None +- +- # te encoding +- te_encoding: Optional[str] = payload.headers.get( +- CONTENT_TRANSFER_ENCODING, +- "", +- ).lower() +- if te_encoding not in ("", "base64", "quoted-printable", "binary"): +- raise RuntimeError( +- "unknown content transfer encoding: {}" "".format(te_encoding) ++ encoding: Optional[str] = None ++ te_encoding: Optional[str] = None ++ if self._is_form_data: ++ # https://datatracker.ietf.org/doc/html/rfc7578#section-4.7 ++ # https://datatracker.ietf.org/doc/html/rfc7578#section-4.8 ++ assert CONTENT_DISPOSITION in payload.headers ++ assert "name=" in payload.headers[CONTENT_DISPOSITION] ++ assert ( ++ not {CONTENT_ENCODING, CONTENT_LENGTH, CONTENT_TRANSFER_ENCODING} ++ & payload.headers.keys() + ) +- if te_encoding == "binary": +- te_encoding = None +- +- # size +- size = payload.size +- if size is not None and not (encoding or te_encoding): +- payload.headers[CONTENT_LENGTH] = str(size) ++ else: ++ # compression ++ encoding = payload.headers.get(CONTENT_ENCODING, "").lower() ++ if encoding and encoding not in ("deflate", "gzip", "identity"): ++ raise RuntimeError(f"unknown content encoding: {encoding}") ++ if encoding == "identity": ++ encoding = None ++ ++ # te encoding ++ te_encoding = payload.headers.get(CONTENT_TRANSFER_ENCODING, "").lower() ++ if te_encoding not in ("", "base64", "quoted-printable", "binary"): ++ raise RuntimeError(f"unknown content transfer encoding: {te_encoding}") ++ if te_encoding == "binary": ++ te_encoding = None ++ ++ # size ++ size = payload.size ++ if size is not None and not (encoding or te_encoding): ++ payload.headers[CONTENT_LENGTH] = str(size) + + self._parts.append((payload, encoding, te_encoding)) # type: ignore[arg-type] + return payload +diff --git a/tests/test_client_functional.py b/tests/test_client_functional.py +index 4f62b479..8801423b 100644 +--- a/tests/test_client_functional.py ++++ b/tests/test_client_functional.py +@@ -1158,48 +1158,6 @@ async def test_POST_DATA_with_charset_post(aiohttp_client) -> None: + resp.close() + + +-async def test_POST_DATA_with_context_transfer_encoding(aiohttp_client) -> None: +- async def handler(request): +- data = await request.post() +- assert data["name"] == "text" +- return web.Response(text=data["name"]) +- +- app = web.Application() +- app.router.add_post("/", handler) +- client = await aiohttp_client(app) +- +- form = aiohttp.FormData() +- form.add_field("name", "text", content_transfer_encoding="base64") +- +- resp = await client.post("/", data=form) +- assert 200 == resp.status +- content = await resp.text() +- assert content == "text" +- resp.close() +- +- +-async def test_POST_DATA_with_content_type_context_transfer_encoding(aiohttp_client): +- async def handler(request): +- data = await request.post() +- assert data["name"] == "text" +- return web.Response(body=data["name"]) +- +- app = web.Application() +- app.router.add_post("/", handler) +- client = await aiohttp_client(app) +- +- form = aiohttp.FormData() +- form.add_field( +- "name", "text", content_type="text/plain", content_transfer_encoding="base64" +- ) +- +- resp = await client.post("/", data=form) +- assert 200 == resp.status +- content = await resp.text() +- assert content == "text" +- resp.close() +- +- + async def test_POST_MultiDict(aiohttp_client) -> None: + async def handler(request): + data = await request.post() +@@ -1249,7 +1207,7 @@ async def test_POST_FILES(aiohttp_client, fname) -> None: + client = await aiohttp_client(app) + + with fname.open("rb") as f: +- resp = await client.post("/", data={"some": f, "test": b"data"}, chunked=True) ++ resp = await client.post("/", data={"some": f, "test": io.BytesIO(b"data")}, chunked=True) + assert 200 == resp.status + resp.close() + +diff --git a/tests/test_multipart.py b/tests/test_multipart.py +index cc3f5ff7..68f5ab9e 100644 +--- a/tests/test_multipart.py ++++ b/tests/test_multipart.py +@@ -942,6 +942,58 @@ class TestMultipartReader: + assert first.at_eof() + assert not second.at_eof() + ++ async def test_read_form_default_encoding(self) -> None: ++ with Stream( ++ b"--:\r\n" ++ b'Content-Disposition: form-data; name="_charset_"\r\n\r\n' ++ b"ascii" ++ b"\r\n" ++ b"--:\r\n" ++ b'Content-Disposition: form-data; name="field1"\r\n\r\n' ++ b"foo" ++ b"\r\n" ++ b"--:\r\n" ++ b"Content-Type: text/plain;charset=UTF-8\r\n" ++ b'Content-Disposition: form-data; name="field2"\r\n\r\n' ++ b"foo" ++ b"\r\n" ++ b"--:\r\n" ++ b'Content-Disposition: form-data; name="field3"\r\n\r\n' ++ b"foo" ++ b"\r\n" ++ ) as stream: ++ reader = aiohttp.MultipartReader( ++ {CONTENT_TYPE: 'multipart/form-data;boundary=":"'}, ++ stream, ++ ) ++ field1 = await reader.next() ++ assert field1.name == "field1" ++ assert field1.get_charset("default") == "ascii" ++ field2 = await reader.next() ++ assert field2.name == "field2" ++ assert field2.get_charset("default") == "UTF-8" ++ field3 = await reader.next() ++ assert field3.name == "field3" ++ assert field3.get_charset("default") == "ascii" ++ ++ async def test_read_form_invalid_default_encoding(self) -> None: ++ with Stream( ++ b"--:\r\n" ++ b'Content-Disposition: form-data; name="_charset_"\r\n\r\n' ++ b"this-value-is-too-long-to-be-a-charset" ++ b"\r\n" ++ b"--:\r\n" ++ b'Content-Disposition: form-data; name="field1"\r\n\r\n' ++ b"foo" ++ b"\r\n" ++ ) as stream: ++ reader = aiohttp.MultipartReader( ++ {CONTENT_TYPE: 'multipart/form-data;boundary=":"'}, ++ stream, ++ ) ++ with pytest.raises(RuntimeError, match="Invalid default charset"): ++ await reader.next() ++ + + async def test_writer(writer) -> None: + assert writer.size == 7 +@@ -1278,7 +1330,6 @@ class TestMultipartWriter: + CONTENT_TYPE: "text/python", + }, + ) +- content_length = part.size + await writer.write(stream) + + assert part.headers[CONTENT_TYPE] == "text/python" +@@ -1289,9 +1340,7 @@ class TestMultipartWriter: + assert headers == ( + b"--:\r\n" + b"Content-Type: text/python\r\n" +- b'Content-Disposition: attachments; filename="bug.py"\r\n' +- b"Content-Length: %s" +- b"" % (str(content_length).encode(),) ++ b'Content-Disposition: attachments; filename="bug.py"' + ) + + async def test_set_content_disposition_override(self, buf, stream): +@@ -1305,7 +1354,6 @@ class TestMultipartWriter: + CONTENT_TYPE: "text/python", + }, + ) +- content_length = part.size + await writer.write(stream) + + assert part.headers[CONTENT_TYPE] == "text/python" +@@ -1316,9 +1364,7 @@ class TestMultipartWriter: + assert headers == ( + b"--:\r\n" + b"Content-Type: text/python\r\n" +- b'Content-Disposition: attachments; filename="bug.py"\r\n' +- b"Content-Length: %s" +- b"" % (str(content_length).encode(),) ++ b'Content-Disposition: attachments; filename="bug.py"' + ) + + async def test_reset_content_disposition_header(self, buf, stream): +@@ -1330,8 +1376,6 @@ class TestMultipartWriter: + headers={CONTENT_TYPE: "text/plain"}, + ) + +- content_length = part.size +- + assert CONTENT_DISPOSITION in part.headers + + part.set_content_disposition("attachments", filename="bug.py") +@@ -1344,9 +1388,7 @@ class TestMultipartWriter: + b"--:\r\n" + b"Content-Type: text/plain\r\n" + b"Content-Disposition:" +- b' attachments; filename="bug.py"\r\n' +- b"Content-Length: %s" +- b"" % (str(content_length).encode(),) ++ b' attachments; filename="bug.py"' + ) + + +diff --git a/tests/test_web_functional.py b/tests/test_web_functional.py +index 5fdfb234..61739e95 100644 +--- a/tests/test_web_functional.py ++++ b/tests/test_web_functional.py +@@ -34,7 +34,8 @@ def fname(here): + + def new_dummy_form(): + form = FormData() +- form.add_field("name", b"123", content_transfer_encoding="base64") ++ with pytest.warns(DeprecationWarning, match="BytesPayload"): ++ form.add_field("name", b"123", content_transfer_encoding="base64") + return form + + +@@ -429,25 +430,6 @@ async def test_release_post_data(aiohttp_client) -> None: + await resp.release() + + +-async def test_POST_DATA_with_content_transfer_encoding(aiohttp_client) -> None: +- async def handler(request): +- data = await request.post() +- assert b"123" == data["name"] +- return web.Response() +- +- app = web.Application() +- app.router.add_post("/", handler) +- client = await aiohttp_client(app) +- +- form = FormData() +- form.add_field("name", b"123", content_transfer_encoding="base64") +- +- resp = await client.post("/", data=form) +- assert 200 == resp.status +- +- await resp.release() +- +- + async def test_post_form_with_duplicate_keys(aiohttp_client) -> None: + async def handler(request): + data = await request.post() +@@ -505,7 +487,8 @@ async def test_100_continue(aiohttp_client) -> None: + return web.Response() + + form = FormData() +- form.add_field("name", b"123", content_transfer_encoding="base64") ++ with pytest.warns(DeprecationWarning, match="BytesPayload"): ++ form.add_field("name", b"123", content_transfer_encoding="base64") + + app = web.Application() + app.router.add_post("/", handler) +@@ -683,7 +666,7 @@ async def test_upload_file(aiohttp_client) -> None: + app.router.add_post("/", handler) + client = await aiohttp_client(app) + +- resp = await client.post("/", data={"file": data}) ++ resp = await client.post("/", data={"file": io.BytesIO(data)}) + assert 200 == resp.status + + await resp.release() +-- +2.45.0 + + +From 0d0a305762a9071933d95281a36a0c0dfdfff930 Mon Sep 17 00:00:00 2001 +From: "patchback[bot]" <45432694+patchback[bot]@users.noreply.github.com> +Date: Mon, 15 Apr 2024 20:47:19 +0100 +Subject: [PATCH 2/3] [PR #8332/482e6cdf backport][3.9] Add + set_content_disposition test (#8333) + +**This is a backport of PR #8332 as merged into master +(482e6cdf6516607360666a48c5828d3dbe959fbd).** + +Co-authored-by: Oleg A <t0rr@mail.ru> +(cherry picked from commit 7eecdff163ccf029fbb1ddc9de4169d4aaeb6597) +--- + CHANGES/8332.bugfix.rst | 1 + + aiohttp/multipart.py | 7 +++++-- + tests/test_multipart.py | 7 +++++++ + 3 files changed, 13 insertions(+), 2 deletions(-) + create mode 100644 CHANGES/8332.bugfix.rst + +diff --git a/CHANGES/8332.bugfix.rst b/CHANGES/8332.bugfix.rst +new file mode 100644 +index 00000000..70cad26b +--- /dev/null ++++ b/CHANGES/8332.bugfix.rst +@@ -0,0 +1 @@ ++Fixed regression with adding Content-Disposition to form-data part after appending to writer -- by :user:`Dreamsorcerer`/:user:`Olegt0rr`. +diff --git a/aiohttp/multipart.py b/aiohttp/multipart.py +index 0e2e6f85..e59e0a68 100644 +--- a/aiohttp/multipart.py ++++ b/aiohttp/multipart.py +@@ -843,8 +843,6 @@ class MultipartWriter(Payload): + if self._is_form_data: + # https://datatracker.ietf.org/doc/html/rfc7578#section-4.7 + # https://datatracker.ietf.org/doc/html/rfc7578#section-4.8 +- assert CONTENT_DISPOSITION in payload.headers +- assert "name=" in payload.headers[CONTENT_DISPOSITION] + assert ( + not {CONTENT_ENCODING, CONTENT_LENGTH, CONTENT_TRANSFER_ENCODING} + & payload.headers.keys() +@@ -925,6 +923,11 @@ class MultipartWriter(Payload): + async def write(self, writer: Any, close_boundary: bool = True) -> None: + """Write body.""" + for part, encoding, te_encoding in self._parts: ++ if self._is_form_data: ++ # https://datatracker.ietf.org/doc/html/rfc7578#section-4.2 ++ assert CONTENT_DISPOSITION in part.headers ++ assert "name=" in part.headers[CONTENT_DISPOSITION] ++ + await writer.write(b"--" + self._boundary + b"\r\n") + await writer.write(part._binary_headers) + +diff --git a/tests/test_multipart.py b/tests/test_multipart.py +index 68f5ab9e..08279e49 100644 +--- a/tests/test_multipart.py ++++ b/tests/test_multipart.py +@@ -1280,6 +1280,13 @@ class TestMultipartWriter: + part = writer._parts[0][0] + assert part.headers[CONTENT_TYPE] == "test/passed" + ++ async def test_set_content_disposition_after_append(self): ++ writer = aiohttp.MultipartWriter("form-data") ++ payload = writer.append("some-data") ++ payload.set_content_disposition("form-data", name="method") ++ assert CONTENT_DISPOSITION in payload.headers ++ assert "name=" in payload.headers[CONTENT_DISPOSITION] ++ + def test_with(self) -> None: + with aiohttp.MultipartWriter(boundary=":") as writer: + writer.append("foo") +-- +2.45.0 + + +From b5f94118ff3f0d3711d85b8089fd46f1d5e87e4d Mon Sep 17 00:00:00 2001 +From: "patchback[bot]" <45432694+patchback[bot]@users.noreply.github.com> +Date: Mon, 15 Apr 2024 21:54:12 +0100 +Subject: [PATCH 3/3] [PR #8335/5a6949da backport][3.9] Add Content-Disposition + automatically (#8336) + +**This is a backport of PR #8335 as merged into master +(5a6949da642d1db6cf414fd0d1f70e54c7b7be14).** + +Co-authored-by: Sam Bull <git@sambull.org> +(cherry picked from commit f21c6f2ca512a026ce7f0f6c6311f62d6a638866) +--- + CHANGES/8335.bugfix.rst | 1 + + aiohttp/multipart.py | 4 ++++ + tests/test_multipart.py | 22 +++++++++++++++++----- + 3 files changed, 22 insertions(+), 5 deletions(-) + create mode 100644 CHANGES/8335.bugfix.rst + +diff --git a/CHANGES/8335.bugfix.rst b/CHANGES/8335.bugfix.rst +new file mode 100644 +index 00000000..cd93b864 +--- /dev/null ++++ b/CHANGES/8335.bugfix.rst +@@ -0,0 +1 @@ ++Added default Content-Disposition in multipart/form-data responses -- by :user:`Dreamsorcerer`. +diff --git a/aiohttp/multipart.py b/aiohttp/multipart.py +index e59e0a68..9cd49bb5 100644 +--- a/aiohttp/multipart.py ++++ b/aiohttp/multipart.py +@@ -847,6 +847,10 @@ class MultipartWriter(Payload): + not {CONTENT_ENCODING, CONTENT_LENGTH, CONTENT_TRANSFER_ENCODING} + & payload.headers.keys() + ) ++ # Set default Content-Disposition in case user doesn't create one ++ if CONTENT_DISPOSITION not in payload.headers: ++ name = f"section-{len(self._parts)}" ++ payload.set_content_disposition("form-data", name=name) + else: + # compression + encoding = payload.headers.get(CONTENT_ENCODING, "").lower() +diff --git a/tests/test_multipart.py b/tests/test_multipart.py +index 08279e49..1d036fbe 100644 +--- a/tests/test_multipart.py ++++ b/tests/test_multipart.py +@@ -1280,12 +1280,24 @@ class TestMultipartWriter: + part = writer._parts[0][0] + assert part.headers[CONTENT_TYPE] == "test/passed" + +- async def test_set_content_disposition_after_append(self): ++ def test_set_content_disposition_after_append(self): + writer = aiohttp.MultipartWriter("form-data") +- payload = writer.append("some-data") +- payload.set_content_disposition("form-data", name="method") +- assert CONTENT_DISPOSITION in payload.headers +- assert "name=" in payload.headers[CONTENT_DISPOSITION] ++ part = writer.append("some-data") ++ part.set_content_disposition("form-data", name="method") ++ assert 'name="method"' in part.headers[CONTENT_DISPOSITION] ++ ++ def test_automatic_content_disposition(self): ++ writer = aiohttp.MultipartWriter("form-data") ++ writer.append_json(()) ++ part = payload.StringPayload("foo") ++ part.set_content_disposition("form-data", name="second") ++ writer.append_payload(part) ++ writer.append("foo") ++ ++ disps = tuple(p[0].headers[CONTENT_DISPOSITION] for p in writer._parts) ++ assert 'name="section-0"' in disps[0] ++ assert 'name="second"' in disps[1] ++ assert 'name="section-2"' in disps[2] + + def test_with(self) -> None: + with aiohttp.MultipartWriter(boundary=":") as writer: +-- +2.45.0 + diff --git a/pkgs/development/python-modules/aiohttp/default.nix b/pkgs/development/python-modules/aiohttp/default.nix index 75d2421c56b0b..c5cd90264082f 100644 --- a/pkgs/development/python-modules/aiohttp/default.nix +++ b/pkgs/development/python-modules/aiohttp/default.nix @@ -49,6 +49,7 @@ buildPythonPackage rec { hash = "sha256-ZzhlE50bmA+e2XX2RH1FuWQHZIAa6Dk/hZjxPoX5t4g="; }) ./3.8.6-CVE-2024-23334.patch + ./3.8.6-CVE-2024-30251.patch ]; postPatch = '' diff --git a/pkgs/development/python-modules/django/4.nix b/pkgs/development/python-modules/django/4.nix index 65ebba3aa857f..0c69a72370db3 100644 --- a/pkgs/development/python-modules/django/4.nix +++ b/pkgs/development/python-modules/django/4.nix @@ -1,7 +1,8 @@ { lib , stdenv , buildPythonPackage -, fetchPypi +, fetchFromGitHub +, pythonAtLeast , pythonOlder , substituteAll @@ -41,15 +42,17 @@ }: buildPythonPackage rec { - pname = "Django"; - version = "4.2.11"; + pname = "django"; + version = "4.2.12"; format = "pyproject"; disabled = pythonOlder "3.10"; - src = fetchPypi { - inherit pname version; - hash = "sha256-bm/z2y2N0MmGtO7IVUyOT5GbXB/2KltDkMF6/y7W5cQ="; + src = fetchFromGitHub { + owner = "django"; + repo = "django"; + rev = "refs/tags/${version}"; + hash = "sha256-n6esWUpZpCP4J4bNckNKJ9E61qFjTPS7XF+WgxNS2JE="; }; patches = [ @@ -60,6 +63,7 @@ buildPythonPackage rec { # make sure the tests don't remove packages from our pythonpath # and disable failing tests ./django_4_tests.patch + ] ++ lib.optionals withGdal [ (substituteAll { src = ./django_4_set_geos_gdal_lib.patch; diff --git a/pkgs/development/python-modules/python-jose/default.nix b/pkgs/development/python-modules/python-jose/default.nix index 6e3f406fe5a30..edd545b3511c5 100644 --- a/pkgs/development/python-modules/python-jose/default.nix +++ b/pkgs/development/python-modules/python-jose/default.nix @@ -1,6 +1,7 @@ { lib , buildPythonPackage , fetchFromGitHub +, fetchpatch # build-system , setuptools @@ -31,6 +32,19 @@ buildPythonPackage rec { hash = "sha256-6VGC6M5oyGCOiXcYp6mpyhL+JlcYZKIqOQU9Sm/TkKM="; }; + patches = [ + (fetchpatch { + name = "CVE-2024-33663.patch"; + url = "https://build.opensuse.org/public/source/openSUSE:Factory/python-python-jose/CVE-2024-33663.patch?rev=36cd8815411620042f56a3b81599b341"; + hash = "sha256-uxOCa7Lg82zY2nuHzw6CbcymCKUodITrFU3lLY1XMFU="; + }) + (fetchpatch { + name = "CVE-2024-33664.patch"; + url = "https://build.opensuse.org/public/source/openSUSE:Factory/python-python-jose/CVE-2024-33664.patch?rev=36cd8815411620042f56a3b81599b341"; + hash = "sha256-wx/U1T7t7TloP+dMXxGxEVB3bMC7e6epmN8RE8FKksM="; + }) + ]; + postPatch = '' substituteInPlace setup.py \ --replace '"pytest-runner",' "" diff --git a/pkgs/os-specific/linux/util-linux/default.nix b/pkgs/os-specific/linux/util-linux/default.nix index d710fabb7ace0..58213e1947456 100644 --- a/pkgs/os-specific/linux/util-linux/default.nix +++ b/pkgs/os-specific/linux/util-linux/default.nix @@ -1,4 +1,4 @@ -{ lib, stdenv, fetchurl, pkg-config, zlib, shadow +{ lib, stdenv, fetchurl, fetchpatch, pkg-config, zlib, shadow , capabilitiesSupport ? stdenv.isLinux , libcap_ng , libxcrypt @@ -30,6 +30,12 @@ stdenv.mkDerivation rec { patches = [ ./rtcwake-search-PATH-for-shutdown.patch ./bcachefs-patch-set.patch + + (fetchpatch { + name = "CVE-2024-28085.patch"; + url = "https://git.kernel.org/pub/scm/utils/util-linux/util-linux.git/patch/?id=f4f0782f66692112311659086fd552d40d7a6f59"; + hash = "sha256-1OQ/FG/gCeGKF+FpeNABMuv+dLhMhFclTfk/vB3Y1N0="; + }) ]; # We separate some of the utilities into their own outputs. This diff --git a/pkgs/servers/sql/postgresql/default.nix b/pkgs/servers/sql/postgresql/default.nix index d3066474bbd69..e0469b0a2b845 100644 --- a/pkgs/servers/sql/postgresql/default.nix +++ b/pkgs/servers/sql/postgresql/default.nix @@ -346,45 +346,45 @@ let mkPackages = self: { postgresql_12 = self.callPackage generic { - version = "12.18"; + version = "12.19"; psqlSchema = "12"; - hash = "sha256-T5kZcl2UHOmGjgf+HtHTqGdIWZtIM4ZUdYOSi3TDkYo="; + hash = "sha256-YX495Swi6CL09X0B1bIkBQPhmKnsyvWYqFEQm9GOb7s="; this = self.postgresql_12; thisAttr = "postgresql_12"; inherit self; }; postgresql_13 = self.callPackage generic { - version = "13.14"; + version = "13.15"; psqlSchema = "13"; - hash = "sha256-uN8HhVGJiWC9UA3F04oXfpkFN234H+fytmChQH+mpe0="; + hash = "sha256-Qu3UFURtM7jCQr520a0FdTGyJksuhpOTObcHXG5OySU="; this = self.postgresql_13; thisAttr = "postgresql_13"; inherit self; }; postgresql_14 = self.callPackage generic { - version = "14.11"; + version = "14.12"; psqlSchema = "14"; - hash = "sha256-pnC9fc4i3K1Cl7JhE2s7HUoJpvVBcZViqhTKY78paKg="; + hash = "sha256-YRjQj53cwb2Dzyt8x007WDvc7C835iRaisADuPqoCSM="; this = self.postgresql_14; thisAttr = "postgresql_14"; inherit self; }; postgresql_15 = self.callPackage generic { - version = "15.6"; + version = "15.7"; psqlSchema = "15"; - hash = "sha256-hFUUbtnGnJOlfelUrq0DAsr60DXCskIXXWqh4X68svs="; + hash = "sha256-pG/klIWrY4Xjnau7tlT10wSSBvds1pXiJCaHKVIJmPc="; this = self.postgresql_15; thisAttr = "postgresql_15"; inherit self; }; postgresql_16 = self.callPackage generic { - version = "16.2"; + version = "16.3"; psqlSchema = "16"; - hash = "sha256-RG6IKU28LJCFq0twYaZG+mBLS+wDUh1epnHC5a2bKVI="; + hash = "sha256-Mxlj1dPcTK9CFqBJ+kC2bWvLjHMGFYWUEblRh2TmBYU="; this = self.postgresql_16; thisAttr = "postgresql_16"; inherit self; |