changeset 2952:42a7d30a6ee0

add allow_style_attributes config option; when true user edited CKEditor style attributes are processed, fixes #519, #520
author RogerHaase <haaserd@gmail.com>
date Wed, 17 Jun 2015 13:30:39 -0700
parents e85b62acee29
children 395ac7691975
files MoinMoin/config/default.py MoinMoin/converter/html_in.py MoinMoin/converter/html_out.py MoinMoin/static/js/common.js
diffstat 4 files changed, 36 insertions(+), 6 deletions(-) [+]
line wrap: on
line diff
--- a/MoinMoin/config/default.py	Sat Jun 13 15:05:12 2015 -0700
+++ b/MoinMoin/config/default.py	Wed Jun 17 13:30:39 2015 -0700
@@ -349,6 +349,7 @@
             # vary rounds parameter randomly when creating new hashes...
             # all__vary_rounds=0.1,
         ), "passlib CryptContext arguments, see passlib docs"),
+        ('allow_style_attributes', False, 'trust editors to not abuse style attribute security holes within HTML (CKEditor) or Markdown items'),
     )),
     # ==========================================================================
     'spam_leech_dos': ('Anti-Spam / Leech / DOS', 'These settings help limiting ressource usage and avoiding abuse.', (
--- a/MoinMoin/converter/html_in.py	Sat Jun 13 15:05:12 2015 -0700
+++ b/MoinMoin/converter/html_in.py	Wed Jun 17 13:30:39 2015 -0700
@@ -36,7 +36,7 @@
     }
 
     # HTML tags which can be converted directly to the moin_page namespace
-    symmetric_tags = set(['div', 'p', 'strong', 'code', 'quote', 'blockquote'])
+    symmetric_tags = set(['div', 'p', 'strong', 'code', 'quote', 'blockquote', 'span'])
 
     # HTML tags to define a list, except dl which is a little bit different
     list_tags = set(['ul', 'dir', 'ol'])
@@ -369,7 +369,7 @@
         <img src="URI" /> --> <object xlink:href="URI />
         """
         key = xlink('href')
-        attrib = {}
+        attrib = self.convert_attributes(element)
         if self.base_url:
             attrib[key] = ''.join([self.base_url, element.get(html.src)])
         else:
@@ -524,6 +524,7 @@
         return ET.Element(moin_page.list_item, attrib={}, children=[list_item_body])
 
     def visit_xhtml_table(self, element):
+        attrib = self.convert_attributes(element)
         # we should not have any strings in the child
         list_table_elements = []
         for child in element:
@@ -534,7 +535,7 @@
                 elif not isinstance(r, (list, tuple)):
                     r = (r, )
                 list_table_elements.extend(r)
-        return ET.Element(moin_page.table, attrib={}, children=list_table_elements)
+        return ET.Element(moin_page.table, attrib=attrib, children=list_table_elements)
 
     def visit_xhtml_thead(self, element):
         return self.new_copy(moin_page.table_header, element, attrib={})
--- a/MoinMoin/converter/html_out.py	Sat Jun 13 15:05:12 2015 -0700
+++ b/MoinMoin/converter/html_out.py	Wed Jun 17 13:30:39 2015 -0700
@@ -15,6 +15,7 @@
 import re
 
 from flask import request
+from flask import current_app as app
 from emeraldtree import ElementTree as ET
 
 from MoinMoin import wikiutil
@@ -30,6 +31,22 @@
 logging = log.getLogger(__name__)
 
 
+# strings not allowed in style attributes
+SUSPECT = set(('/*', '/>', '\\', '`', 'script', '&#', 'http', 'expression', 'behavior', ))
+
+
+def style_attr_filter(style):
+    """
+    If allow_style_attributes option is True check style attribute for suspect strings, else return ''.
+    """
+    if app.cfg.allow_style_attributes:
+        s = "".join(style.strip().lower().split())
+        if any(x in s for x in SUSPECT):
+            return ' /*style suppressed, failed test for suspect strings*/ '
+        return style
+    return ''
+
+
 def convert_getlink_to_showlink(href):
     """
     If the incoming transclusion reference is within this domain, then remove "+get/<revision number>/".
@@ -116,6 +133,8 @@
         new_default = {}
 
         for key, value in self.element.attrib.iteritems():
+            if key == html.style:
+                value = style_attr_filter(value)
             if key.uri == moin_page:
                 # We never have _ in attribute names, so ignore them instead of
                 # create ambigues matches.
@@ -382,14 +401,21 @@
 
     def visit_moinpage_object(self, elem):
         """
-        elem of type img are converted to img tags here, others are left as object tags
+        elem of type img are converted to img tags here, others are left as object tags.
+
+        We do not use Attributes.convert to convert all attributes, but copy selected attributes
+        and follow html5 validation rules to place right attributes within img and object tags.
         """
         href = elem.get(xlink.href, None)
         attrib = {}
-        whitelist = ['width', 'height', 'alt', 'class', 'data-href']
+
+        whitelist = ['width', 'height', 'alt', 'class', 'data-href', 'style']
         for key in elem.attrib:
             if key.name in whitelist:
-                attrib[key] = elem.attrib[key]
+                if key.name == 'style':
+                    attrib[key] = style_attr_filter(elem.attrib[key])
+                else:
+                    attrib[key] = elem.attrib[key]
         mimetype = Type(_type=elem.get(moin_page.type_, CONTENTTYPE_NONEXISTENT))
         if elem.get(moin_page.type_):
             del elem.attrib[moin_page.type_]
--- a/MoinMoin/static/js/common.js	Sat Jun 13 15:05:12 2015 -0700
+++ b/MoinMoin/static/js/common.js	Wed Jun 17 13:30:39 2015 -0700
@@ -136,6 +136,8 @@
                 // copy all classes from img tags
                 $(wrapper).addClass($(elem).find(">:first-child").attr('class'));
             }
+            // copy float styling to the wrapper so a SPAN enclosing an IMG does the floating (float will be 'none' if not specified)
+            $(wrapper).css('float', $(elem).filter(":first").css('float'));
             // insert wrapper after elem, append (move) elem, append overlays
             $(elem).after(wrapper);
             $(wrapper).append(elem);