Commit db65013977f059e29757ed115180fa43d43a5d67
1 parent
31b28c41
Exists in
master
and in
20 other branches
rails4: use new rails sanitizer (loofah)
Showing
6 changed files
with
55 additions
and
18 deletions
Show diff stats
app/models/tiny_mce_article.rb
@@ -9,7 +9,7 @@ class TinyMceArticle < TextArticle | @@ -9,7 +9,7 @@ class TinyMceArticle < TextArticle | ||
9 | def self.description | 9 | def self.description |
10 | _('Not accessible for visually impaired users.') | 10 | _('Not accessible for visually impaired users.') |
11 | end | 11 | end |
12 | - | 12 | + |
13 | xss_terminate :only => [ ] | 13 | xss_terminate :only => [ ] |
14 | 14 | ||
15 | xss_terminate :only => [ :name, :abstract, :body ], :with => 'white_list', :on => 'validation' | 15 | xss_terminate :only => [ :name, :abstract, :body ], :with => 'white_list', :on => 'validation' |
config/application.rb
@@ -15,12 +15,6 @@ module Noosfero | @@ -15,12 +15,6 @@ module Noosfero | ||
15 | 15 | ||
16 | require 'noosfero/plugin' | 16 | require 'noosfero/plugin' |
17 | 17 | ||
18 | - # Adds custom attributes to the Set of allowed html attributes for the #sanitize helper | ||
19 | - config.action_view.sanitized_allowed_attributes = 'align', 'border', 'alt', 'vspace', 'hspace', 'width', 'heigth', 'value', 'type', 'data', 'style', 'target', 'codebase', 'archive', 'classid', 'code', 'flashvars', 'scrolling', 'frameborder', 'controls', 'autoplay', 'colspan', 'rowspan' | ||
20 | - | ||
21 | - # Adds custom tags to the Set of allowed html tags for the #sanitize helper | ||
22 | - config.action_view.sanitized_allowed_tags = 'object', 'embed', 'param', 'table', 'tr', 'th', 'td', 'applet', 'comment', 'iframe', 'audio', 'video', 'source' | ||
23 | - | ||
24 | config.action_controller.include_all_helpers = false | 18 | config.action_controller.include_all_helpers = false |
25 | 19 | ||
26 | # Settings in config/environments/* take precedence over those specified here. | 20 | # Settings in config/environments/* take precedence over those specified here. |
@@ -0,0 +1,35 @@ | @@ -0,0 +1,35 @@ | ||
1 | +require 'loofah/helpers' | ||
2 | + | ||
3 | +ActionView::Base.full_sanitizer = Loofah::Helpers::ActionView::FullSanitizer.new | ||
4 | +ActionView::Base.white_list_sanitizer = Loofah::Helpers::ActionView::WhiteListSanitizer.new | ||
5 | + | ||
6 | +Loofah::HTML5::WhiteList::ALLOWED_ELEMENTS_WITH_LIBXML2.merge %w[ | ||
7 | + img object embed param table tr th td applet comment iframe audio video source | ||
8 | +] | ||
9 | + | ||
10 | +Loofah::HTML5::WhiteList::ALLOWED_ATTRIBUTES.merge %w[ | ||
11 | + align border alt vspace hspace width heigth value type data | ||
12 | + style target codebase archive classid code flashvars scrolling frameborder controls autoplay colspan | ||
13 | +] | ||
14 | + | ||
15 | +# do not escape COMMENT_NODE | ||
16 | +require 'loofah/scrubber' | ||
17 | +module Loofah | ||
18 | + class Scrubber | ||
19 | + private | ||
20 | + | ||
21 | + def html5lib_sanitize node | ||
22 | + case node.type | ||
23 | + when Nokogiri::XML::Node::ELEMENT_NODE | ||
24 | + if HTML5::Scrub.allowed_element? node.name | ||
25 | + HTML5::Scrub.scrub_attributes node | ||
26 | + return Scrubber::CONTINUE | ||
27 | + end | ||
28 | + when Nokogiri::XML::Node::TEXT_NODE, Nokogiri::XML::Node::CDATA_SECTION_NODE,Nokogiri::XML::Node::COMMENT_NODE | ||
29 | + return Scrubber::CONTINUE | ||
30 | + end | ||
31 | + Scrubber::STOP | ||
32 | + end | ||
33 | + | ||
34 | + end | ||
35 | +end |
test/test_helper.rb
@@ -135,16 +135,23 @@ class ActiveSupport::TestCase | @@ -135,16 +135,23 @@ class ActiveSupport::TestCase | ||
135 | assert !text.index('<'), "Text '#{text}' expected to be sanitized" | 135 | assert !text.index('<'), "Text '#{text}' expected to be sanitized" |
136 | end | 136 | end |
137 | 137 | ||
138 | + def find_tag_in_string text, options | ||
139 | + doc = Nokogiri::HTML.fragment text | ||
140 | + tag = doc.css(options[:tag]).first | ||
141 | + attributes = {}; tag.attributes.each do |a, v| | ||
142 | + a = a.to_sym | ||
143 | + next unless options[:attributes].has_key? a | ||
144 | + attributes[a] = v.value | ||
145 | + end | ||
146 | + tag if (tag and attributes == options[:attributes]) | ||
147 | + end | ||
148 | + | ||
138 | def assert_tag_in_string(text, options) | 149 | def assert_tag_in_string(text, options) |
139 | - doc = HTML::Document.new(text, false, false) | ||
140 | - tag = doc.find(options) | ||
141 | - assert tag, "expected tag #{options.inspect}, but not found in #{text.inspect}" | 150 | + assert find_tag_in_string(text, options), "expected tag #{options.inspect}, but not found in #{text.inspect}" |
142 | end | 151 | end |
143 | 152 | ||
144 | def assert_no_tag_in_string(text, options) | 153 | def assert_no_tag_in_string(text, options) |
145 | - doc = HTML::Document.new(text, false, false) | ||
146 | - tag = doc.find(options) | ||
147 | - assert !tag, "expected no tag #{options.inspect}, but tag found in #{text.inspect}" | 154 | + assert !find_tag_in_string(text, options), "expected no tag #{options.inspect}, but tag found in #{text.inspect}" |
148 | end | 155 | end |
149 | 156 | ||
150 | def assert_order(reference, original) | 157 | def assert_order(reference, original) |
test/unit/article_test.rb
@@ -935,7 +935,7 @@ class ArticleTest < ActiveSupport::TestCase | @@ -935,7 +935,7 @@ class ArticleTest < ActiveSupport::TestCase | ||
935 | article.name = "<h1 Malformed >> html >< tag" | 935 | article.name = "<h1 Malformed >> html >< tag" |
936 | article.valid? | 936 | article.valid? |
937 | 937 | ||
938 | - assert_no_match /[<>]/, article.name | 938 | + assert_equal '<h1>> html ></h1>', article.name |
939 | end | 939 | end |
940 | 940 | ||
941 | should 'return truncated title in short_title' do | 941 | should 'return truncated title in short_title' do |
@@ -1734,6 +1734,7 @@ class ArticleTest < ActiveSupport::TestCase | @@ -1734,6 +1734,7 @@ class ArticleTest < ActiveSupport::TestCase | ||
1734 | 1734 | ||
1735 | should 'store first image in tracked action' do | 1735 | should 'store first image in tracked action' do |
1736 | a = create TinyMceArticle, :name => 'Tracked Article', :body => '<p>Foo<img src="foo.png" />Bar</p>', :profile_id => profile.id | 1736 | a = create TinyMceArticle, :name => 'Tracked Article', :body => '<p>Foo<img src="foo.png" />Bar</p>', :profile_id => profile.id |
1737 | + assert_equal 'foo.png', a.first_image | ||
1737 | assert_equal 'foo.png', ActionTracker::Record.last.get_first_image | 1738 | assert_equal 'foo.png', ActionTracker::Record.last.get_first_image |
1738 | end | 1739 | end |
1739 | 1740 |
test/unit/tiny_mce_article_test.rb
@@ -82,16 +82,16 @@ class TinyMceArticleTest < ActiveSupport::TestCase | @@ -82,16 +82,16 @@ class TinyMceArticleTest < ActiveSupport::TestCase | ||
82 | assert_no_tag_in_string article.body, :tag => 'iframe', :attributes => { :src => "http://untrusted_site.com/videos.ogg"} | 82 | assert_no_tag_in_string article.body, :tag => 'iframe', :attributes => { :src => "http://untrusted_site.com/videos.ogg"} |
83 | end | 83 | end |
84 | 84 | ||
85 | - should 'remove iframe if it has 2 or more src' do | 85 | + should 'consider first src if there is 2 or more src' do |
86 | assert_includes Environment.default.trusted_sites_for_iframe, 'itheora.org' | 86 | assert_includes Environment.default.trusted_sites_for_iframe, 'itheora.org' |
87 | 87 | ||
88 | article = create(TinyMceArticle, :profile => profile, :name => 'article', :abstract => 'abstract', :body => "<iframe src='http://itheora.org/videos.ogg' src='http://untrusted_site.com/videos.ogg'></iframe>") | 88 | article = create(TinyMceArticle, :profile => profile, :name => 'article', :abstract => 'abstract', :body => "<iframe src='http://itheora.org/videos.ogg' src='http://untrusted_site.com/videos.ogg'></iframe>") |
89 | - assert_equal '', article.body | 89 | + assert_tag_in_string article.body, :tag => 'iframe', :attributes => { :src => "http://itheora.org/videos.ogg"} |
90 | end | 90 | end |
91 | 91 | ||
92 | should 'not sanitize html comments' do | 92 | should 'not sanitize html comments' do |
93 | article = TinyMceArticle.new | 93 | article = TinyMceArticle.new |
94 | - article.body = '<p><!-- <asdf> << aasdfa >>> --> <h1> Wellformed html code </h1>' | 94 | + article.body = '<!-- <asdf> << aasdfa >>> --> <h1> Wellformed html code </h1>' |
95 | article.valid? | 95 | article.valid? |
96 | 96 | ||
97 | assert_match /<!-- .* --> <h1> Wellformed html code <\/h1>/, article.body | 97 | assert_match /<!-- .* --> <h1> Wellformed html code <\/h1>/, article.body |
@@ -232,7 +232,7 @@ end | @@ -232,7 +232,7 @@ end | ||
232 | :profile => profile | 232 | :profile => profile |
233 | ) | 233 | ) |
234 | assert_tag_in_string article.body, :tag => 'table', | 234 | assert_tag_in_string article.body, :tag => 'table', |
235 | - :attributes => { :colspan => 2, :rowspan => 3 } | 235 | + :attributes => { :colspan => '2', :rowspan => '3' } |
236 | end | 236 | end |
237 | 237 | ||
238 | end | 238 | end |