This commit is contained in:
Ryan Johnson 2024-01-25 10:22:35 -08:00 коммит произвёл GitHub
Родитель c9e07b1917
Коммит 9cda6858f1
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
5 изменённых файлов: 5 добавлений и 144 удалений

Просмотреть файл

@ -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

Просмотреть файл

@ -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

Просмотреть файл

@ -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"""
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100">
<script>alert('This is an unsafe SVG file!');</script>
<rect x="10" y="10" width="80" height="80" fill="blue" />
</svg>""",
)
self.assertEqual(field.clean(data), data)
content = data.read()
self.assertIn(b'<svg xmlns="http://www.w3.org/2000/svg"', content)
self.assertNotIn(b"<script>", 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"""<svg xmlns="http://www.w3.org/2000/svg"></svg>"""
)
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))

75
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"

Просмотреть файл

@ -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"