diff --git a/Dockerfile b/Dockerfile index 70d59ffd7..4a3fd2bcc 100644 --- a/Dockerfile +++ b/Dockerfile @@ -21,7 +21,7 @@ RUN set -xe \ && apt-get install -y --no-install-recommends \ gettext build-essential \ libxml2-dev libxslt1-dev zlib1g-dev git \ - libjpeg-dev libcairo2-dev libffi-dev libssl-dev libxslt1.1 \ + libjpeg-dev libffi-dev libssl-dev libxslt1.1 \ optipng postgresql zip \ # python && python -m venv /venv \ @@ -103,7 +103,7 @@ COPY --chown=kitsune:kitsune . . RUN apt-get update && \ apt-get upgrade -y && \ apt-get install -y --no-install-recommends \ - libcairo2 libxslt1.1 optipng postgresql && \ + libxslt1.1 optipng postgresql && \ rm -rf /var/lib/apt/lists/* RUN mkdir /app/media && chown kitsune:kitsune /app/media diff --git a/kitsune/sumo/form_fields.py b/kitsune/sumo/form_fields.py index 58383e808..21d56ec6a 100644 --- a/kitsune/sumo/form_fields.py +++ b/kitsune/sumo/form_fields.py @@ -1,6 +1,5 @@ from pathlib import Path -from cairosvg import svg2svg from django import forms from django.contrib.auth.models import User from django.core import validators @@ -86,7 +85,7 @@ class MultiUsernameField(forms.Field): class ImagePlusField(forms.ImageField): """ - Same as django.forms.ImageField but with support for SVG images as well. + Same as django.forms.ImageField but with support for trusted SVG images as well. """ default_validators = [ @@ -98,7 +97,7 @@ class ImagePlusField(forms.ImageField): def to_python(self, data): """ Check that the file-upload field data contains an image that - Pillow supports or a valid SVG image. + Pillow supports or an SVG image (assumed to be trusted). """ try: return super().to_python(data) @@ -108,38 +107,4 @@ class ImagePlusField(forms.ImageField): ): raise - def scrub(svg_as_bytes): - """ - Accepts an SVG file as bytes and returns a safe version of that - SVG file as bytes. - """ - try: - return svg2svg(bytestring=svg_as_bytes) - except Exception as exc: - # CairoSVG doesn't recognize it as an SVG image. - msg = _("Invalid or unsupported SVG image: {reason}") - raise ValidationError( - msg.format(reason=str(exc)), - code="invalid_svg_image", - ) from exc - - if hasattr(data, "read"): - # This is typically an instance of a sub-class of UploadedFile, - # which shouldn't be closed, otherwise it will be deleted. - data.seek(0) - try: - scrubbed = scrub(data.read()) - finally: - # The read pointer is expected to point to the start of the file. - data.seek(0) - try: - # Over-write the image with its scrubbed version. - data.truncate() - data.write(scrubbed) - finally: - # The read pointer is expected to point to the start of the file. - data.seek(0) - else: - data["content"] = scrub(data["content"]) - return data diff --git a/kitsune/sumo/tests/test_form_fields.py b/kitsune/sumo/tests/test_form_fields.py index 1393b4ed3..7d7fe507e 100644 --- a/kitsune/sumo/tests/test_form_fields.py +++ b/kitsune/sumo/tests/test_form_fields.py @@ -105,22 +105,6 @@ class ImagePlusFieldTestCases(TestCase): data = self.get_uploaded_file("stuff.svg") self.assertEqual(field.clean(data), data) - def test_svg_image_with_unsafe_file(self): - """Test for the case when the uploaded file is unsafe.""" - field = ImagePlusField() - data = self.get_uploaded_file( - "stuff.svg", - content=b""" - - - - """, - ) - self.assertEqual(field.clean(data), data) - content = data.read() - self.assertIn(b'", content) - def test_svg_image_without_proper_extension(self): """SVG images without an "svg" extension should be considered invalid.""" field = ImagePlusField() @@ -131,17 +115,3 @@ class ImagePlusFieldTestCases(TestCase): self.assertTrue(hasattr(arm.exception, "code")) self.assertEqual(arm.exception.code, "invalid_image") - - def test_invalid_svg_image(self): - """Invalid SVG images should raise a validation error.""" - field = ImagePlusField() - data = self.get_uploaded_file( - "stuff.svg", content=b"""""" - ) - - with self.assertRaises(ValidationError) as arm: - field.clean(data) - - self.assertTrue(hasattr(arm.exception, "code")) - self.assertEqual(arm.exception.code, "invalid_svg_image") - self.assertIn("The SVG size is undefined", str(arm.exception)) diff --git a/poetry.lock b/poetry.lock index e46661263..82702066d 100644 --- a/poetry.lock +++ b/poetry.lock @@ -317,47 +317,6 @@ files = [ {file = "cachetools-5.3.2.tar.gz", hash = "sha256:086ee420196f7b2ab9ca2db2520aca326318b68fe5ba8bc4d49cca91add450f2"}, ] -[[package]] -name = "cairocffi" -version = "1.6.1" -description = "cffi-based cairo bindings for Python" -optional = false -python-versions = ">=3.7" -files = [ - {file = "cairocffi-1.6.1-py3-none-any.whl", hash = "sha256:aa78ee52b9069d7475eeac457389b6275aa92111895d78fbaa2202a52dac112e"}, - {file = "cairocffi-1.6.1.tar.gz", hash = "sha256:78e6bbe47357640c453d0be929fa49cd05cce2e1286f3d2a1ca9cbda7efdb8b7"}, -] - -[package.dependencies] -cffi = ">=1.1.0" - -[package.extras] -doc = ["sphinx", "sphinx_rtd_theme"] -test = ["flake8", "isort", "numpy", "pikepdf", "pytest"] -xcb = ["xcffib (>=1.4.0)"] - -[[package]] -name = "cairosvg" -version = "2.7.1" -description = "A Simple SVG Converter based on Cairo" -optional = false -python-versions = ">=3.5" -files = [ - {file = "CairoSVG-2.7.1-py3-none-any.whl", hash = "sha256:8a5222d4e6c3f86f1f7046b63246877a63b49923a1cd202184c3a634ef546b3b"}, - {file = "CairoSVG-2.7.1.tar.gz", hash = "sha256:432531d72347291b9a9ebfb6777026b607563fd8719c46ee742db0aef7271ba0"}, -] - -[package.dependencies] -cairocffi = "*" -cssselect2 = "*" -defusedxml = "*" -pillow = "*" -tinycss2 = "*" - -[package.extras] -doc = ["sphinx", "sphinx-rtd-theme"] -test = ["flake8", "isort", "pytest"] - [[package]] name = "celery" version = "5.2.7" @@ -752,25 +711,6 @@ files = [ {file = "cssselect-1.2.0.tar.gz", hash = "sha256:666b19839cfaddb9ce9d36bfe4c969132c647b92fc9088c4e23f786b30f1b3dc"}, ] -[[package]] -name = "cssselect2" -version = "0.7.0" -description = "CSS selectors for Python ElementTree" -optional = false -python-versions = ">=3.7" -files = [ - {file = "cssselect2-0.7.0-py3-none-any.whl", hash = "sha256:fd23a65bfd444595913f02fc71f6b286c29261e354c41d722ca7a261a49b5969"}, - {file = "cssselect2-0.7.0.tar.gz", hash = "sha256:1ccd984dab89fc68955043aca4e1b03e0cf29cad9880f6e28e3ba7a74b14aa5a"}, -] - -[package.dependencies] -tinycss2 = "*" -webencodings = "*" - -[package.extras] -doc = ["sphinx", "sphinx_rtd_theme"] -test = ["flake8", "isort", "pytest"] - [[package]] name = "cssutils" version = "2.9.0" @@ -824,17 +764,6 @@ files = [ {file = "decorator-5.1.1.tar.gz", hash = "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330"}, ] -[[package]] -name = "defusedxml" -version = "0.7.1" -description = "XML bomb protection for Python stdlib modules" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -files = [ - {file = "defusedxml-0.7.1-py2.py3-none-any.whl", hash = "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61"}, - {file = "defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69"}, -] - [[package]] name = "dennis" version = "1.1.0" @@ -2991,8 +2920,6 @@ files = [ {file = "psycopg2-2.9.9-cp310-cp310-win_amd64.whl", hash = "sha256:426f9f29bde126913a20a96ff8ce7d73fd8a216cfb323b1f04da402d452853c3"}, {file = "psycopg2-2.9.9-cp311-cp311-win32.whl", hash = "sha256:ade01303ccf7ae12c356a5e10911c9e1c51136003a9a1d92f7aa9d010fb98372"}, {file = "psycopg2-2.9.9-cp311-cp311-win_amd64.whl", hash = "sha256:121081ea2e76729acfb0673ff33755e8703d45e926e416cb59bae3a86c6a4981"}, - {file = "psycopg2-2.9.9-cp312-cp312-win32.whl", hash = "sha256:d735786acc7dd25815e89cc4ad529a43af779db2e25aa7c626de864127e5a024"}, - {file = "psycopg2-2.9.9-cp312-cp312-win_amd64.whl", hash = "sha256:a7653d00b732afb6fc597e29c50ad28087dcb4fbfb28e86092277a559ae4e693"}, {file = "psycopg2-2.9.9-cp37-cp37m-win32.whl", hash = "sha256:5e0d98cade4f0e0304d7d6f25bbfbc5bd186e07b38eac65379309c4ca3193efa"}, {file = "psycopg2-2.9.9-cp37-cp37m-win_amd64.whl", hash = "sha256:7e2dacf8b009a1c1e843b5213a87f7c544b2b042476ed7755be813eaf4e8347a"}, {file = "psycopg2-2.9.9-cp38-cp38-win32.whl", hash = "sha256:ff432630e510709564c01dafdbe996cb552e0b9f3f065eb89bdce5bd31fabf4c"}, @@ -4865,4 +4792,4 @@ testing = ["coverage (>=5.0.3)", "zope.event", "zope.testing"] [metadata] lock-version = "2.0" python-versions = "^3.11" -content-hash = "9fe0f9faf7b1a91e8d82b1f49f2ecf391badae9aaf13889649165d0718c8fdb0" +content-hash = "4b195c7ed47a191a50009675cdde566b34ee23e080a9d94343781a6083e44b53" diff --git a/pyproject.toml b/pyproject.toml index 9091945cf..5839e2966 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -88,7 +88,6 @@ psycopg2 = "^2.9.9" mkdocs = "^1.5.3" mkdocs-material = "^9.5.3" dockerflow = "^2022.8.0" -cairosvg = "^2.7.1" [tool.poetry.group.dev.dependencies] ipdb = "^0.13.11"