Automatically escape text in components

This commit is contained in:
2026-06-02 16:09:39 +02:00
parent 66ec8e1eed
commit ad47684dc1
2 changed files with 27 additions and 8 deletions
+3 -4
View File
@@ -8,6 +8,7 @@ from django.template import TemplateDoesNotExist
from django.template.defaultfilters import floatformat
from django.template.loader import render_to_string
from django.urls import reverse
from django.utils.html import conditional_escape
from django.utils.safestring import SafeText, mark_safe
from common.utils import truncate
@@ -47,13 +48,11 @@ def Component(
raise ValueError("One of template or tag_name is required.")
if isinstance(children, str):
children = [children]
childrenBlob = "\n".join(children)
childrenBlob = "\n".join(conditional_escape(child) for child in children)
if len(attributes) == 0:
attributesBlob = ""
else:
attributesList = [f'{name}="{value}"' for name, value in attributes]
# make attribute list into a string
# and insert space between tag and attribute list
attributesList = [f'{name}="{conditional_escape(str(value))}"' for name, value in attributes]
attributesBlob = f" {' '.join(attributesList)}"
tag: str = ""
if tag_name != "":
+24 -4
View File
@@ -5,7 +5,7 @@ from unittest.mock import MagicMock, patch
import django
from django.template import TemplateDoesNotExist
from django.utils.safestring import SafeText
from django.utils.safestring import SafeText, mark_safe
from common import components
from games.models import Platform, Game, Purchase, Session
@@ -426,13 +426,33 @@ class ComponentEdgeCasesTest(unittest.TestCase):
def test_multiple_children_joined_with_newlines(self):
result = components.Component(
tag_name="div", children=["<span>a</span>", "<span>b</span>"]
tag_name="div", children=["hello", "world"]
)
self.assertIn("<span>a</span>", result)
self.assertIn("<span>b</span>", result)
self.assertIn("hello\nworld", result)
self.assertIn("<div>", result)
self.assertIn("</div>", result)
def test_raw_html_children_are_escaped(self):
result = components.Component(
tag_name="div", children=["<script>alert('xss')</script>"]
)
self.assertNotIn("<script>", result)
self.assertIn("&lt;script&gt;", result)
def test_mark_safe_children_pass_through(self):
result = components.Component(
tag_name="div", children=[mark_safe("<span>safe</span>")]
)
self.assertIn("<span>safe</span>", result)
def test_attribute_values_are_escaped(self):
result = components.Component(
tag_name="div",
attributes=[("data-x", 'foo"bar')],
)
self.assertIn("&quot;", result)
self.assertNotIn('"foo"bar"', result)
def test_attributes_serialized_correctly(self):
result = components.Component(
tag_name="div", attributes=[("class", "foo"), ("id", "bar")]