Automatically escape text in components
This commit is contained in:
@@ -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 != "":
|
||||
|
||||
@@ -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("<script>", 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(""", result)
|
||||
self.assertNotIn('"foo"bar"', result)
|
||||
|
||||
def test_attributes_serialized_correctly(self):
|
||||
result = components.Component(
|
||||
tag_name="div", attributes=[("class", "foo"), ("id", "bar")]
|
||||
|
||||
Reference in New Issue
Block a user