From 4316bca6242fced8716d8e1ecc77b9ea3518e30d Mon Sep 17 00:00:00 2001 From: Germain GUEUTIER Date: Mon, 11 Mar 2024 22:49:04 +0100 Subject: [PATCH] Fix Kozea#2093, Mark use of hashlib.md5() as not for security --- .github/workflows/tests.yml | 4 ++-- README.rst | 2 +- docs/first_steps.rst | 2 +- pyproject.toml | 3 +-- weasyprint/document.py | 3 ++- weasyprint/images.py | 2 +- weasyprint/pdf/anchors.py | 4 ++-- weasyprint/pdf/stream.py | 2 +- weasyprint/text/fonts.py | 11 ++++++----- 9 files changed, 17 insertions(+), 16 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 484a228a8..f7a376fe8 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -11,9 +11,9 @@ jobs: python-version: ['3.12'] include: - os: ubuntu-latest - python-version: '3.8' + python-version: '3.9' - os: ubuntu-latest - python-version: 'pypy-3.8' + python-version: 'pypy-3.9' steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 diff --git a/README.rst b/README.rst index aae4a147b..b2b8a0ebe 100644 --- a/README.rst +++ b/README.rst @@ -13,7 +13,7 @@ WebKit or Gecko. The CSS layout engine is written in Python, designed for pagination, and meant to be easy to hack on. * Free software: BSD license -* For Python 3.8+, tested on CPython and PyPy +* For Python 3.9+, tested on CPython and PyPy * Documentation: https://doc.courtbouillon.org/weasyprint * Examples: https://weasyprint.org/#samples * Changelog: https://github.com/Kozea/WeasyPrint/releases diff --git a/docs/first_steps.rst b/docs/first_steps.rst index 309e66b11..b5833aa9d 100644 --- a/docs/first_steps.rst +++ b/docs/first_steps.rst @@ -9,7 +9,7 @@ Installation WeasyPrint |version| depends on: -* Python_ ≥ 3.8.0 +* Python_ ≥ 3.9.0 * Pango_ ≥ 1.44.0 * pydyf_ ≥ 0.8.0 * CFFI_ ≥ 0.6 diff --git a/pyproject.toml b/pyproject.toml index c102706da..d3e1eb2e1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,7 +8,7 @@ description = 'The Awesome Document Factory' keywords = ['html', 'css', 'pdf', 'converter'] authors = [{name = 'Simon Sapin', email = 'simon.sapin@exyr.org'}] maintainers = [{name = 'CourtBouillon', email = 'contact@courtbouillon.org'}] -requires-python = '>=3.8' +requires-python = '>=3.9' readme = {file = 'README.rst', content-type = 'text/x-rst'} license = {file = 'LICENSE'} dependencies = [ @@ -29,7 +29,6 @@ classifiers = [ 'Programming Language :: Python', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3 :: Only', - 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', 'Programming Language :: Python :: 3.10', 'Programming Language :: Python :: 3.11', diff --git a/weasyprint/document.py b/weasyprint/document.py index b72e3b090..a1810b798 100644 --- a/weasyprint/document.py +++ b/weasyprint/document.py @@ -169,7 +169,8 @@ def __init__(self, folder): self._disk_paths = set() def _path_from_key(self, key): - return self._path / md5(key.encode()).hexdigest() + digest = md5(key.encode(), usedforsecurity=False).hexdigest() + return self._path / digest def __getitem__(self, key): if key in self._memory_cache: diff --git a/weasyprint/images.py b/weasyprint/images.py index fba459d42..93679f277 100644 --- a/weasyprint/images.py +++ b/weasyprint/images.py @@ -326,7 +326,7 @@ def get_image_from_uri(cache, url_fetcher, options, url, forced_mime_type=None, raise ImageLoadingError.from_exception(raster_exception) else: # Store image id to enable cache in Stream.add_image - image_id = md5(url.encode()).hexdigest() + image_id = md5(url.encode(), usedforsecurity=False).hexdigest() image = RasterImage( pillow_image, image_id, string, filename, cache, orientation, options) diff --git a/weasyprint/pdf/anchors.py b/weasyprint/pdf/anchors.py index 35550b999..dd12d5b99 100644 --- a/weasyprint/pdf/anchors.py +++ b/weasyprint/pdf/anchors.py @@ -1,8 +1,8 @@ """Insert anchors, links, bookmarks and inputs in PDFs.""" -import hashlib import io import mimetypes +from hashlib import md5 from os.path import basename from urllib.parse import unquote, urlsplit @@ -302,7 +302,7 @@ def write_pdf_attachment(pdf, attachment, compress): except URLFetchingError as exception: LOGGER.error('Failed to load attachment: %s', exception) return - attachment.md5 = hashlib.md5(stream).hexdigest() + attachment.md5 = md5(stream, usedforsecurity=False).hexdigest() # TODO: Use the result object from a URL fetch operation to provide more # details on the possible filename and MIME type. diff --git a/weasyprint/pdf/stream.py b/weasyprint/pdf/stream.py index 0f82ad175..2b657cd36 100644 --- a/weasyprint/pdf/stream.py +++ b/weasyprint/pdf/stream.py @@ -63,7 +63,7 @@ def __init__(self, pango_font): # Never use the built-in hash function here: it’s not stable self.hash = ''.join( chr(65 + letter % 26) for letter - in md5(description_string).digest()[:6]) + in md5(description_string, usedforsecurity=False).digest()[:6]) # Name fields = description_string.split(b' ') diff --git a/weasyprint/text/fonts.py b/weasyprint/text/fonts.py index f08b0be44..613e3c74d 100644 --- a/weasyprint/text/fonts.py +++ b/weasyprint/text/fonts.py @@ -1,6 +1,6 @@ """Interface with external libraries managing fonts installed on the system.""" -from hashlib import sha1 +from hashlib import md5 from io import BytesIO from pathlib import Path from shutil import rmtree @@ -121,10 +121,11 @@ def add_font_face(self, rule_descriptors, url_fetcher): rule_descriptors.get('font_weight', 'normal')] fontconfig_stretch = FONTCONFIG_STRETCH[ rule_descriptors.get('font_stretch', 'normal')] - config_key = sha1(( + config_key = ( f'{rule_descriptors["font_family"]}-{fontconfig_style}-' - f'{fontconfig_weight}-{features_string}').encode()).hexdigest() - font_path = self._folder / config_key + f'{fontconfig_weight}-{features_string}').encode() + config_digest = md5(config_key, usedforsecurity=False).hexdigest() + font_path = self._folder / config_digest if font_path.exists(): return @@ -209,7 +210,7 @@ def add_font_face(self, rule_descriptors, url_fetcher): continue font_path.write_bytes(font) - xml_path = self._folder / f'{config_key}.xml' + xml_path = self._folder / f'{config_digest}.xml' xml_path.write_text(f'''