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.defaultfilters import floatformat
|
||||||
from django.template.loader import render_to_string
|
from django.template.loader import render_to_string
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
|
from django.utils.html import conditional_escape
|
||||||
from django.utils.safestring import SafeText, mark_safe
|
from django.utils.safestring import SafeText, mark_safe
|
||||||
|
|
||||||
from common.utils import truncate
|
from common.utils import truncate
|
||||||
@@ -47,13 +48,11 @@ def Component(
|
|||||||
raise ValueError("One of template or tag_name is required.")
|
raise ValueError("One of template or tag_name is required.")
|
||||||
if isinstance(children, str):
|
if isinstance(children, str):
|
||||||
children = [children]
|
children = [children]
|
||||||
childrenBlob = "\n".join(children)
|
childrenBlob = "\n".join(conditional_escape(child) for child in children)
|
||||||
if len(attributes) == 0:
|
if len(attributes) == 0:
|
||||||
attributesBlob = ""
|
attributesBlob = ""
|
||||||
else:
|
else:
|
||||||
attributesList = [f'{name}="{value}"' for name, value in attributes]
|
attributesList = [f'{name}="{conditional_escape(str(value))}"' for name, value in attributes]
|
||||||
# make attribute list into a string
|
|
||||||
# and insert space between tag and attribute list
|
|
||||||
attributesBlob = f" {' '.join(attributesList)}"
|
attributesBlob = f" {' '.join(attributesList)}"
|
||||||
tag: str = ""
|
tag: str = ""
|
||||||
if tag_name != "":
|
if tag_name != "":
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ from unittest.mock import MagicMock, patch
|
|||||||
import django
|
import django
|
||||||
|
|
||||||
from django.template import TemplateDoesNotExist
|
from django.template import TemplateDoesNotExist
|
||||||
from django.utils.safestring import SafeText
|
from django.utils.safestring import SafeText, mark_safe
|
||||||
|
|
||||||
from common import components
|
from common import components
|
||||||
from games.models import Platform, Game, Purchase, Session
|
from games.models import Platform, Game, Purchase, Session
|
||||||
@@ -426,13 +426,33 @@ class ComponentEdgeCasesTest(unittest.TestCase):
|
|||||||
|
|
||||||
def test_multiple_children_joined_with_newlines(self):
|
def test_multiple_children_joined_with_newlines(self):
|
||||||
result = components.Component(
|
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("hello\nworld", result)
|
||||||
self.assertIn("<span>b</span>", result)
|
|
||||||
self.assertIn("<div>", result)
|
self.assertIn("<div>", 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):
|
def test_attributes_serialized_correctly(self):
|
||||||
result = components.Component(
|
result = components.Component(
|
||||||
tag_name="div", attributes=[("class", "foo"), ("id", "bar")]
|
tag_name="div", attributes=[("class", "foo"), ("id", "bar")]
|
||||||
|
|||||||
Reference in New Issue
Block a user