Products.CMFPlone/robodoc: sync safe_html settings with tinymce

Peter Holzer <jenkins-z4DKO/[email protected]> Fri, 28 Jul 2017 05:39:02 -0700 (PDT)
Newsgroups gmane.comp.web.zope.plone.cvs
Message-ID <[email protected]>
Repository: Products.CMFPlone
Branch: refs/heads/robodoc
Date: 2017-07-28T12:36:55+02:00
Author: MrTango (MrTango) <md-r4/[email protected]>
Commit: https://github.com/plone/Products.CMFPlone/commit/946f3b3cee049646d3cf1eb0f176e9cb3c743a54

sync safe_html settings with tinymce

Files changed:
M Products/CMFPlone/controlpanel/browser/filter.py
M Products/CMFPlone/interfaces/controlpanel.py
M Products/CMFPlone/patterns/settings.py
M Products/CMFPlone/patterns/tinymce.py
M Products/CMFPlone/tests/robot/test_controlpanel_filter.robot
M setup.py

diff --git a/Products/CMFPlone/controlpanel/browser/filter.py b/Products/CMFPlone/controlpanel/browser/filter.py
index e9aebedb7..8c822d855 100644
--- a/Products/CMFPlone/controlpanel/browser/filter.py
+++ b/Products/CMFPlone/controlpanel/browser/filter.py
@@ -1,9 +1,9 @@
 # -*- coding: utf-8 -*-
+from plone.app.registry.browser import controlpanel
 from plone.z3cform import layout
 from Products.CMFPlone import PloneMessageFactory as _  # NOQA
 from Products.CMFPlone.interfaces import IFilterSchema
 from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
-from plone.app.registry.browser import controlpanel
 from Products.statusmessages.interfaces import IStatusMessage
 from z3c.form import button
 
diff --git a/Products/CMFPlone/interfaces/controlpanel.py b/Products/CMFPlone/interfaces/controlpanel.py
index fb28d4cc0..a8d7d4a83 100644
--- a/Products/CMFPlone/interfaces/controlpanel.py
+++ b/Products/CMFPlone/interfaces/controlpanel.py
@@ -365,90 +365,90 @@ class IFilterSchema(Interface):
         title=_(u'Valid tags'),
         description=_(u'A list of valid tags which will be not filtered out.'),
         default=[
-            'a',
-            'abbr',
-            'acronym',
-            'address',
-            'article',
-            'aside',
-            'audio',
-            'b',
-            'bdo',
-            'big',
-            'blockquote',
-            'body',
-            'br',
-            'canvas',
-            'caption',
-            'cite',
-            'code',
-            'col',
-            'colgroup',
-            'command',
-            'datalist',
-            'dd',
-            'del',
-            'details',
-            'dfn',
-            'dialog',
-            'div',
-            'dl',
-            'dt',
-            'em',
-            'figure',
-            'footer',
-            'h1',
-            'h2',
-            'h3',
-            'h4',
-            'h5',
-            'h6',
-            'head',
-            'header',
-            'hgroup',
-            'html',
-            'i',
-            'iframe',
-            'img',
-            'ins',
-            'kbd',
-            'keygen',
-            'li',
-            'map',
-            'mark',
-            'meter',
-            'nav',
-            'ol',
-            'output',
-            'p',
-            'pre',
-            'progress',
-            'q',
-            'rp',
-            'rt',
-            'ruby',
-            'samp',
-            'section',
-            'small',
-            'source',
-            'span',
-            'strong',
-            'sub',
-            'sup',
-            'table',
-            'tbody',
-            'td',
-            'tfoot',
-            'th',
-            'thead',
-            'time',
-            'title',
-            'tr',
-            'tt',
-            'u',
-            'ul',
-            'var',
-            'video',
+            u'a',
+            u'abbr',
+            u'acronym',
+            u'address',
+            u'article',
+            u'aside',
+            u'audio',
+            u'b',
+            u'bdo',
+            u'big',
+            u'blockquote',
+            u'body',
+            u'br',
+            u'canvas',
+            u'caption',
+            u'cite',
+            u'code',
+            u'col',
+            u'colgroup',
+            u'command',
+            u'datalist',
+            u'dd',
+            u'del',
+            u'details',
+            u'dfn',
+            u'dialog',
+            u'div',
+            u'dl',
+            u'dt',
+            u'em',
+            u'figure',
+            u'footer',
+            u'h1',
+            u'h2',
+            u'h3',
+            u'h4',
+            u'h5',
+            u'h6',
+            u'head',
+            u'header',
+            u'hgroup',
+            u'html',
+            u'i',
+            u'iframe',
+            u'img',
+            u'ins',
+            u'kbd',
+            u'keygen',
+            u'li',
+            u'map',
+            u'mark',
+            u'meter',
+            u'nav',
+            u'ol',
+            u'output',
+            u'p',
+            u'pre',
+            u'progress',
+            u'q',
+            u'rp',
+            u'rt',
+            u'ruby',
+            u'samp',
+            u'section',
+            u'small',
+            u'source',
+            u'span',
+            u'strong',
+            u'sub',
+            u'sup',
+            u'table',
+            u'tbody',
+            u'td',
+            u'tfoot',
+            u'th',
+            u'thead',
+            u'time',
+            u'title',
+            u'tr',
+            u'tt',
+            u'u',
+            u'ul',
+            u'var',
+            u'video',
         ],
         value_type=schema.TextLine(),
         missing_value=[],
diff --git a/Products/CMFPlone/patterns/settings.py b/Products/CMFPlone/patterns/settings.py
index c568c07fc..5f3ae140f 100644
--- a/Products/CMFPlone/patterns/settings.py
+++ b/Products/CMFPlone/patterns/settings.py
@@ -3,7 +3,6 @@
 from Acquisition import aq_parent
 from borg.localrole.interfaces import IFactoryTempFolder
 from plone.app.content.browser.interfaces import IFolderContentsView
-from plone.app.layout.navigation.root import getNavigationRootObject
 from plone.app.widgets.utils import get_relateditems_options
 from plone.app.z3cform.utils import call_callables
 from plone.registry.interfaces import IRegistry
@@ -81,7 +80,9 @@ def image_scales(self):
             'plone.app.vocabularies.ImagesScales'
         )
         vocabulary = factory(self.context)
-        ret = [{'title': translate(it.title), 'value': it.value} for it in vocabulary]
+        ret = [{
+            'title': translate(it.title), 'value': it.value}
+            for it in vocabulary]
         ret = sorted(ret, key=lambda it: it['title'])
         return json.dumps(ret)
 
diff --git a/Products/CMFPlone/patterns/tinymce.py b/Products/CMFPlone/patterns/tinymce.py
index 5e9e5dc14..b66f499c6 100644
--- a/Products/CMFPlone/patterns/tinymce.py
+++ b/Products/CMFPlone/patterns/tinymce.py
@@ -1,8 +1,10 @@
 # -*- coding: utf-8 -*-
+from lxml import html
 from plone.app.layout.navigation.root import getNavigationRootObject
 from plone.app.theming.utils import theming_policy
 from plone.registry.interfaces import IRegistry
 from Products.CMFCore.utils import getToolByName
+from Products.CMFPlone.interfaces import IFilterSchema
 from Products.CMFPlone.interfaces import ITinyMCESchema
 from Products.CMFPlone.utils import get_portal
 from zope.component import getUtility
@@ -20,6 +22,11 @@ def __init__(self, context, request):
             prefix="plone",
             check=False
         )
+        self.filter_settings = getUtility(IRegistry).forInterface(
+            IFilterSchema,
+            prefix="plone",
+            check=False
+        )
         self.nav_root = getNavigationRootObject(
             self.context,
             get_portal(),
@@ -197,6 +204,19 @@ def get_tiny_config(self):
             except ValueError:
                 pass
 
+        # add safe_html settings, which are useed in backend for filtering:
+        if not self.filter_settings.disable_filtering:
+            valid_tags = self.filter_settings.valid_tags
+            custom_attributes = self.filter_settings.custom_attributes
+            safe_attributes = [attr.decode() for attr in html.defs.safe_attrs]
+            valid_attributes = safe_attributes + custom_attributes
+            # valid_elements : 'a[href|target=_blank],strong/b,div[align],br'
+            tiny_valid_elements = []
+            for tag in valid_tags:
+                tag_str = "%s[%s]" % (tag, "|".join(valid_attributes))
+                tiny_valid_elements.append(tag_str)
+            tiny_config['valid_elements'] = ",".join(tiny_valid_elements)
+
         if settings.other_settings:
             try:
                 tiny_config.update(json.loads(settings.other_settings))
diff --git a/Products/CMFPlone/tests/robot/test_controlpanel_filter.robot b/Products/CMFPlone/tests/robot/test_controlpanel_filter.robot
index e55d39b56..b8698c6e1 100644
--- a/Products/CMFPlone/tests/robot/test_controlpanel_filter.robot
+++ b/Products/CMFPlone/tests/robot/test_controlpanel_filter.robot
@@ -14,6 +14,7 @@ Resource  plone/app/robotframework/keywords.robot
 Resource  plone/app/robotframework/saucelabs.robot
 
 Library  Remote  ${PLONE_URL}/RobotRemote
+Library  Collections
 
 Resource  keywords.robot
 
@@ -32,26 +33,20 @@ Scenario: Configure Filter Control Panel to filter out nasty tags
 Scenario: Configure Filter Control Panel to strip out tags
   Given a logged-in site administrator
     and the filter control panel
-   When I add 'h1' to the stripped tags list
+   When I remove 'h1' from the valid tags list
    Then the 'h1' tag is stripped when a document is saved
 
 Scenario: Configure Filter Control Panel to allow custom tags
   Given a logged-in site administrator
     and the filter control panel
-   When I add 'marquee' to the custom tags list
-   Then the 'marquee' tag is preserved when a document is saved
+   When I add 'foobar' to the valid tags list
+   Then the 'foobar' tag is preserved when a document is saved
 
-Scenario: Configure Filter Control Panel to strip out attributes
+Scenario: Configure Filter Control Panel to allow custom attributes
   Given a logged-in site administrator
     and the filter control panel
-   When I add 'data-stripme' to the stripped attributes list
-   Then the 'data-stripme' attribute is stripped when a document is saved
-
-Scenario: Configure Filter Control Panel to allow style attributes
-  Given a logged-in site administrator
-    and the filter control panel
-   When I add 'display' to the allowed style attributes
-   Then the 'display' style attribute is preserved when a document is saved
+   When I add 'foo-foo' to the custom attributes list
+   Then the 'foo-foo' attribute is preserved when a document is saved
 
 Scenario: Filter Control Panel displays information regarding caching when saved
   Given a logged-in site administrator
@@ -82,23 +77,18 @@ I add '${tag}' to the nasty tags list
   Click Button  Save
   Wait until page contains  Changes saved
 
-I add '${tag}' to the stripped tags list
-  Input Text  name=form.widgets.stripped_tags  ${tag}
-  Click Button  Save
-  Wait until page contains  Changes saved
-
-I add '${tag}' to the custom tags list
-  Input Text  name=form.widgets.custom_tags  ${tag}
+I remove '${tag}' from the valid tags list
+  Remove line from textarea  form.widgets.valid_tags  ${tag}
   Click Button  Save
   Wait until page contains  Changes saved
 
-I add '${tag}' to the stripped attributes list
-  Input Text  name=form.widgets.stripped_attributes  ${tag}
+I add '${tag}' to the valid tags list
+  Input Text  name=form.widgets.valid_tags  ${tag}
   Click Button  Save
   Wait until page contains  Changes saved
 
-I add '${tag}' to the allowed style attributes
-  Input text  name=form.widgets.style_whitelist  ${tag}
+I add '${tag}' to the custom attributes list
+  Input Text  name=form.widgets.custom_attributes  ${tag}
   Click Button  Save
   Wait until page contains  Changes saved
 
@@ -128,50 +118,23 @@ the 'h1' tag is stripped when a document is saved
   Page should contain  heading
   XPath Should Match X Times  //div[@id='content-core']//h1  0  message=h1 should have been stripped out
 
-the 'marquee' tag is preserved when a document is saved
+the '${tag}' tag is preserved when a document is saved
   ${doc1_uid}=  Create content  id=doc1  title=Document 1  type=Document
   Go To  ${PLONE_URL}/doc1/edit
   patterns are loaded
-  Input RichText  <marquee>lorem ipsum</marquee>
+  Input RichText  <${tag}>lorem ipsum</${tag}>
   Click Button  Save
   Wait until page contains  Changes saved
-  XPath Should Match X Times  //div[@id='content-core']//marquee  1  message=the marquee tag should have been preserved
+  XPath Should Match X Times  //div[@id='content-core']//${tag}  1  message=the ${tag} tag should have been preserved
 
-the 'data-stripme' attribute is stripped when a document is saved
+the '${attribute}' attribute is preserved when a document is saved
   ${doc1_uid}=  Create content  id=doc1  title=Document 1  type=Document
   Go To  ${PLONE_URL}/doc1/edit
   patterns are loaded
-  Input RichText  <h4 data-stripme="foo">lorem ipsum</h4>
+  Input RichText  <span ${attribute}="foo">lorem ipsum</span>
   Click Button  Save
   Wait until page contains  Changes saved
-  Page should contain  lorem ipsum
-
-  XPath Should Match X Times  //*[@id='content-core']//h4  1  message=h4 tag should be present
-  XPath Should Match X Times  //*[@id='content-core']//h4[@data-stripme='foo']  0  message=data-stripme attribute should have been filtered out
-
-the 'foobar' class is filtered out when a document is saved
-  ${doc1_uid}=  Create content  id=doc1  title=Document 1  type=Document
-  Go To  ${PLONE_URL}/doc1/edit
-  patterns are loaded
-  Input RichText  <h4 class="foobar">lorem ipsum</h4>
-  Click Button  Save
-  Wait until page contains  Changes saved
-  Page should contain  lorem ipsum
-
-  XPath Should Match X Times  //*[@id='content-core']//h4  1  message=h4 tag should be present
-  XPath Should Match X Times  //*[@id='content-core']//h4[@class='foobar']  0  message=class foobar should have been filtered out
-
-the 'display' style attribute is preserved when a document is saved
-  ${doc1_uid}=  Create content  id=doc1  title=Document 1  type=Document
-  Go To  ${PLONE_URL}/doc1/edit
-  patterns are loaded
-  Input RichText  <h4 style="display: block">lorem ipsum</h4>
-  Click Button  Save
-  Wait until page contains  Changes saved
-  Page should contain  lorem ipsum
-
-  XPath Should Match X Times  //*[@id='content-core']//h4  1  message=h4 tag should be present
-  XPath Should Match X Times  //*[@id='content-core']//h4[@style]  1  message=style attribute with display:block should be present
+  XPath Should Match X Times  //span[@${attribute}]  1  message=the ${attribute} tag should have been preserved
 
 success message should contain information regarding caching
   Element Should Contain  css=.portalMessage.warning  HTML generation is heavily cached across Plone. You may have to edit existing content or restart your server to see the changes.
diff --git a/setup.py b/setup.py
index 2764017a2..1819071b8 100644
--- a/setup.py
+++ b/setup.py
@@ -37,6 +37,7 @@
             'lxml',
             'mock',
             'plone.app.robotframework>0.9.16',
+            'robotframework-debuglibrary',
             'plone.app.testing',
             'zope.globalrequest',
             'zope.testing',



------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot