From ad47684dc198e2f12281b64250231940073e6784 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Kucharczyk?= Date: Tue, 2 Jun 2026 16:09:39 +0200 Subject: [PATCH] Automatically escape text in components --- common/components.py | 7 +++---- tests/test_components.py | 28 ++++++++++++++++++++++++---- 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/common/components.py b/common/components.py index 71f8d92..a82c69b 100644 --- a/common/components.py +++ b/common/components.py @@ -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 != "": diff --git a/tests/test_components.py b/tests/test_components.py index 9600193..3c610fb 100644 --- a/tests/test_components.py +++ b/tests/test_components.py @@ -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=["a", "b"] + tag_name="div", children=["hello", "world"] ) - self.assertIn("a", result) - self.assertIn("b", result) + self.assertIn("hello\nworld", result) self.assertIn("
", result) self.assertIn("
", result) + def test_raw_html_children_are_escaped(self): + result = components.Component( + tag_name="div", children=[""] + ) + self.assertNotIn("