]> source.dussan.org Git - redmine.git/commitdiff
Allows custom styles in textile formatting using a white list of styles (#2416).
authorJean-Philippe Lang <jp_lang@yahoo.fr>
Sun, 12 Feb 2012 14:00:43 +0000 (14:00 +0000)
committerJean-Philippe Lang <jp_lang@yahoo.fr>
Sun, 12 Feb 2012 14:00:43 +0000 (14:00 +0000)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@8860 e93f8b46-1217-0410-a6f0-8f06a7374b81

lib/redcloth3.rb
lib/redmine/wiki_formatting/textile/formatter.rb
test/unit/lib/redmine/wiki_formatting/textile_formatter_test.rb

index d09804f41653f13464341012938e09dc8909a601..e15970822f9d82094cfe005d21dffc6cc8721643 100644 (file)
@@ -474,7 +474,10 @@ class RedCloth3 < String
             style << "vertical-align:#{ v_align( $& ) };" if text =~ A_VLGN
         end
 
-        style << "#{ htmlesc $1 };" if text.sub!( /\{([^}]*)\}/, '' ) && !filter_styles
+        if text.sub!( /\{([^"}]*)\}/, '' ) && !filter_styles
+          sanitized = sanitize_styles($1)
+          style << "#{ sanitized };" unless sanitized.blank?
+        end
 
         lang = $1 if
             text.sub!( /\[([^)]+?)\]/, '' )
@@ -502,6 +505,16 @@ class RedCloth3 < String
         atts
     end
 
+    STYLES_RE = /^(color|width|height|border|background|padding|margin|font|text)(-[a-z]+)*:\s*((\d+%?|\d+px|\d+(\.\d+)?em|#[0-9a-f]+|[a-z]+)\s*)+$/i
+
+    def sanitize_styles(str)
+      styles = str.split(";").map(&:strip)
+      styles.reject! do |style|
+        !style.match(STYLES_RE)
+      end
+      styles.join(";")
+    end
+
     TABLE_RE = /^(?:table(_?#{S}#{A}#{C})\. ?\n)?^(#{A}#{C}\.? ?\|.*?\|)(\n\n|\Z)/m
     
     # Parses a Textile table block, building HTML from the result.
index 22cd5cbf9bbd607495cab3be32807005f978df76..bbe47a15cf1e74f3c8089f68353c1d0e755d72a5 100644 (file)
@@ -31,7 +31,7 @@ module Redmine
           super
           self.hard_breaks=true
           self.no_span_caps=true
-          self.filter_styles=true
+          self.filter_styles=false
         end
 
         def to_html(*rules)
index 26250997eea938a90576a2e312d73ddbebe980d3..ce4feb62a5018558626c341ad718521183c5879f 100644 (file)
@@ -59,6 +59,50 @@ class Redmine::WikiFormatting::TextileFormatterTest < ActionView::TestCase
     end
   end
 
+  def test_styles
+    # single style
+    assert_html_output({
+      'p{color:red}. text'           => '<p style="color:red;">text</p>',
+      'p{color:red;}. text'          => '<p style="color:red;">text</p>',
+      'p{color: red}. text'          => '<p style="color: red;">text</p>',
+      'p{color:#f00}. text'          => '<p style="color:#f00;">text</p>',
+      'p{color:#ff0000}. text'       => '<p style="color:#ff0000;">text</p>',
+      'p{border:10px}. text'         => '<p style="border:10px;">text</p>',
+      'p{border:10}. text'           => '<p style="border:10;">text</p>',
+      'p{border:10%}. text'          => '<p style="border:10%;">text</p>',
+      'p{border:10em}. text'         => '<p style="border:10em;">text</p>',
+      'p{border:1.5em}. text'        => '<p style="border:1.5em;">text</p>',
+      'p{border-left:1px}. text'     => '<p style="border-left:1px;">text</p>',
+      'p{border-right:1px}. text'    => '<p style="border-right:1px;">text</p>',
+      'p{border-top:1px}. text'      => '<p style="border-top:1px;">text</p>',
+      'p{border-bottom:1px}. text'   => '<p style="border-bottom:1px;">text</p>',
+      }, false)
+
+    # multiple styles
+    assert_html_output({
+      'p{color:red; border-top:1px}. text'   => '<p style="color:red;border-top:1px;">text</p>',
+      'p{color:red ; border-top:1px}. text'  => '<p style="color:red;border-top:1px;">text</p>',
+      'p{color:red;border-top:1px}. text'    => '<p style="color:red;border-top:1px;">text</p>',
+      }, false)
+
+    # styles with multiple values
+    assert_html_output({
+      'p{border:1px solid red;}. text'             => '<p style="border:1px solid red;">text</p>',
+      'p{border-top-left-radius: 10px 5px;}. text' => '<p style="border-top-left-radius: 10px 5px;">text</p>',
+      }, false)
+  end
+
+  def test_invalid_styles_should_be_filtered
+    assert_html_output({
+      'p{invalid}. text'                     => '<p>text</p>',
+      'p{invalid:red}. text'                 => '<p>text</p>',
+      'p{color:(red)}. text'                 => '<p>text</p>',
+      'p{color:red;invalid:blue}. text'      => '<p style="color:red;">text</p>',
+      'p{invalid:blue;color:red}. text'      => '<p style="color:red;">text</p>',
+      'p{color:"}. text'                     => '<p>text</p>',
+      }, false)
+  end
+
   def test_inline_code
     assert_html_output(
       'this is @some code@'      => 'this is <code>some code</code>',