Skip to content

Commit

Permalink
getVocabulary: Call scrub_html on individual items, but check for scr…
Browse files Browse the repository at this point in the history
…ipt/html first

Fixes JSONDecodeError when terms contain incomplete HTML
  • Loading branch information
reinhardt committed Aug 2, 2024
1 parent 4806eb6 commit 2524e28
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 6 deletions.
1 change: 1 addition & 0 deletions news/288.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
getVocabulary: Fix for terms with incomplete HTML
18 changes: 12 additions & 6 deletions plone/app/content/browser/vocabulary.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from Products.Five import BrowserView
from Products.MimetypesRegistry.MimeTypeItem import guess_icon_path
from Products.MimetypesRegistry.MimeTypeItem import PREFIX
from Products.PortalTransforms.transforms.safe_html import hasScript
from Products.PortalTransforms.transforms.safe_html import SafeHTML
from types import FunctionType
from z3c.form.interfaces import IAddForm
Expand Down Expand Up @@ -128,6 +129,12 @@ def get_translated_ignored(self):
def get_base_path(self, context):
return get_navigation_root(context)

def maybe_scrub(self, value):
if value and (hasScript(value) or "<" in value):
transform = SafeHTML()
return transform.scrub_html(value)
return value

def __call__(self):
"""
Accepts GET parameters of:
Expand Down Expand Up @@ -210,7 +217,6 @@ def __call__(self):
attributes = attributes.split(",")

translate_ignored = self.get_translated_ignored()
transform = SafeHTML()
if attributes:
base_path = self.get_base_path(context)
sm = getSecurityManager()
Expand Down Expand Up @@ -261,18 +267,18 @@ def __call__(self):
else:
items = [
{
"id": item.value,
"text": (item.title if item.title else ""),
"id": unescape(self.maybe_scrub(item.value)),
"text": (
unescape(self.maybe_scrub(item.title)) if item.title else ""
),
}
for item in results
]

if total == 0:
total = len(items)

return unescape(
transform.scrub_html(json_dumps({"results": items, "total": total}))
)
return json_dumps({"results": items, "total": total})

def parsed_query(
self,
Expand Down
18 changes: 18 additions & 0 deletions plone/app/content/tests/test_widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -680,6 +680,24 @@ def testGetMimeIcon(self):
[{"getMimeIcon": "/plone/++resource++mimetype.icons/unknown.png"}],
)

def testScrubHtml(self):
from zope.schema.vocabulary import SimpleTerm
from zope.schema.vocabulary import SimpleVocabulary

view = VocabularyView(self.portal, self.request)
vocab = SimpleVocabulary(
[
SimpleTerm(
token=f"term {idx} <b>",
value=f"term {idx} <b>",
title=f"term {idx} <b>",
)
for idx in range(3)
]
)
with mock.patch.object(view, "get_vocabulary", return_value=vocab):
json.loads(view())


class FunctionalBrowserTest(unittest.TestCase):
layer = PLONE_APP_CONTENT_DX_FUNCTIONAL_TESTING
Expand Down

0 comments on commit 2524e28

Please sign in to comment.