Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/django_nh3/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ def __init__(
set_tag_attribute_values: dict[str, dict[str, str]] | None = None,
strip_comments: bool = False,
tag_attribute_values: dict[str, dict[str, set[str]]] | None = None,
filter_style_properties: set[str] | None = None,
url_schemes: set[str] | None = None,
**kwargs: dict[Any, Any],
):
Expand All @@ -44,6 +45,7 @@ def __init__(
strip_comments=strip_comments,
tags=allowed_tags,
tag_attribute_values=tag_attribute_values,
filter_style_properties=filter_style_properties,
url_schemes=url_schemes,
)

Expand Down
10 changes: 10 additions & 0 deletions src/django_nh3/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ def __init__(
set_tag_attribute_values: dict[str, dict[str, str]] | None = None,
strip_comments: bool = False,
tag_attribute_values: dict[str, dict[str, set[str]]] | None = None,
filter_style_properties: set[str] | None = None,
url_schemes: set[str] | None = None,
**kwargs: Any,
) -> None:
Expand All @@ -44,6 +45,7 @@ def __init__(
strip_comments=strip_comments,
tags=allowed_tags,
tag_attribute_values=tag_attribute_values,
filter_style_properties=filter_style_properties,
url_schemes=url_schemes,
)

Expand Down Expand Up @@ -75,6 +77,9 @@ def formfield(
"tag_attribute_values": self.nh3_options.get(
"tag_attribute_values"
),
"filter_style_properties": self.nh3_options.get(
"filter_style_properties"
),
"url_schemes": self.nh3_options.get("url_schemes"),
}
)
Expand All @@ -86,6 +91,11 @@ def pre_save(self, model_instance: Model, add: bool) -> Any:
if data is None:
return data
clean_value = nh3.clean(data, **self.nh3_options) if data else ""

# nh3 leaves an empty style="" if it cleans all style attributes.
# remove it manually until ammonia/nh3 addresses it
clean_value = clean_value.replace(' style=""', "").replace(" style=''", "")

setattr(model_instance, self.attname, mark_safe(clean_value)) # type: ignore[attr-defined]
return clean_value

Expand Down
10 changes: 9 additions & 1 deletion src/django_nh3/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ def get_nh3_configured_default_options() -> dict[str, Any]:

While other settings have no current support in nh3:

BLEACH_ALLOWED_STYLES -> There is no support for styling
BLEACH_ALLOWED_STYLES -> NH3_FILTER_STYLE_PROPERTIES
BLEACH_STRIP_TAGS -> This is the default behavior of nh3

"""
Expand Down Expand Up @@ -71,6 +71,9 @@ def get_nh3_configured_default_options() -> dict[str, Any]:
"NH3_SET_TAG_ATTRIBUTE_VALUES": "set_tag_attribute_values",
# Sets the URL schemes permitted on href and src attributes
"NH3_ALLOWED_URL_SCHEMES": "url_schemes",
# Sets the allowed inline style properties. Valid if "style" is in
# allowed attributes
"NH3_FILTER_STYLE_PROPERTIES": "filter_style_properties",
}

return {
Expand Down Expand Up @@ -153,6 +156,7 @@ def get_nh3_options(
generic_attribute_prefixes: set[str] | None = None,
tag_attribute_values: dict[str, dict[str, set[str]]] | None = None,
set_tag_attribute_values: dict[str, dict[str, str]] | None = None,
filter_style_properties: set[str] | None = None,
url_schemes: set[str] | None = None,
) -> dict[str, Any]:
defaults = get_nh3_configured_default_options()
Expand All @@ -177,6 +181,9 @@ def get_nh3_options(
set_tag_attribute_values or defaults.get("set_tag_attribute_values", None) or {}
)
url_schemes = url_schemes or defaults.get("url_schemes", None) or set()
filter_style_properties = filter_style_properties or defaults.get(
"filter_style_properties", None
)

return normalize_nh3_options(
{
Expand All @@ -189,6 +196,7 @@ def get_nh3_options(
"generic_attribute_prefixes": generic_attribute_prefixes,
"tag_attribute_values": tag_attribute_values,
"set_tag_attribute_values": set_tag_attribute_values,
"filter_style_properties": filter_style_properties,
"url_schemes": url_schemes,
}
)
7 changes: 7 additions & 0 deletions tests/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,10 @@
},
}
]

NH3_ALLOWED_ATTRIBUTES = {
"a": {"style"},
"img": {"src"},
}
NH3_FILTER_STYLE_PROPERTIES = {"text-align"}
NH3_ALLOWED_TAGS = {"a"}
12 changes: 12 additions & 0 deletions tests/test_forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,15 @@ def test_values(self):
self.assertEqual(field.to_python("some text"), "some text")
self.assertEqual(field.to_python(" some text "), "some text")
self.assertEqual(field.to_python("<h1>some text</h1>"), "some text")
self.assertEqual(
field.to_python("<h1 style='text-align: center'>some text</h1>"),
"some text",
)
self.assertEqual(
field.to_python("<a style='text-align: center'>some text</a>"),
'<a style="text-align:center">some text</a>',
)
self.assertEqual(
field.to_python("<a style='margin-top: 1px'>some text</a>"),
'<a style="">some text</a>',
)
10 changes: 10 additions & 0 deletions tests/test_models_charfield.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,16 @@ def test_cleaning(self):
"""Test values are sanitized"""
test_data = {
"html_data": "<h1>Heading</h1>",
"html_data_not_allowed_style": "<a style='background: url(github.com)'>"
"Heading</a>",
"html_data_allowed_style": "<a style='text-align:center'>Heading</a>",
"no_html": "Heading",
"html_comment": "<!-- this is a comment -->",
}
expected_values = {
"html_data": "Heading",
"html_data_not_allowed_style": "<a>Heading</a>",
"html_data_allowed_style": '<a style="text-align:center">Heading</a>',
"no_html": "Heading",
"html_comment": "",
}
Expand Down Expand Up @@ -77,11 +82,16 @@ def test_cleaning(self):
"""Test values are sanitized"""
test_data = {
"html_data": "<h1>Heading</h1>",
"html_data_not_allowed_style": "<a style='background: url(github.com)'>"
"Heading</a>",
"html_data_allowed_style": "<a style='text-align:center'>Heading</a>",
"no_html": "Heading",
"spacing": " Heading ",
}
expected_values = {
"html_data": "Heading",
"html_data_not_allowed_style": "<a>Heading</a>",
"html_data_allowed_style": '<a style="text-align:center">Heading</a>',
"no_html": "Heading",
"spacing": "Heading",
}
Expand Down
11 changes: 11 additions & 0 deletions tests/test_models_textfield.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,17 @@ def test_cleaning(self):
"""Test values are sanitized"""
test_data = {
"html_data": "<h1>Heading</h1>",
"html_data_not_allowed_style": "<a style='background: url(github.com)'>"
"Heading"
"</a>",
"html_data_allowed_style": "<a style='text-align:center'>Heading</a>",
"no_html": "Heading",
"html_comment": "<!-- this is a comment -->",
}
expected_values = {
"html_data": "Heading",
"html_data_not_allowed_style": "<a>Heading</a>",
"html_data_allowed_style": '<a style="text-align:center">Heading</a>',
"no_html": "Heading",
"html_comment": "",
}
Expand Down Expand Up @@ -77,11 +83,16 @@ def test_cleaning(self):
"""Test values are sanitized"""
test_data = {
"html_data": "<h1>Heading</h1>",
"html_data_not_allowed_style": "<a style='background: url(github.com)'>"
"Heading</a>",
"html_data_allowed_style": "<a style='text-align:center'>Heading</a>",
"no_html": "Heading",
"spacing": " Heading ",
}
expected_values = {
"html_data": "Heading",
"html_data_not_allowed_style": "<a>Heading</a>",
"html_data_allowed_style": '<a style="text-align:center">Heading</a>',
"no_html": "Heading",
"spacing": "Heading",
}
Expand Down
Loading