html-sanitizer 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f2aab4300a74e8223593489a108c42ccce6fc4a9
4
+ data.tar.gz: cc97dc16365fec2e38ab4ed4ac7cf8c250572236
5
+ SHA512:
6
+ metadata.gz: a1918cd81328e7051456b8e3f73cded0195fb78d3a76ccbb3cc7f8fcc8bb0af95e307699440830db5fb08363f2b5a3c463532c3528616c6e6478ee2c0905a6ff
7
+ data.tar.gz: 2df201d4cddd0df59b2d7240c818debf3d5d5b3efc93459e8648d0af54211a224b0e7f999e55caf787572d9c4ec0ad30533dbf5a02bac90cadd4c0b711a73a72
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Rafael Mendonça França, Kasper Timm Hansen
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,124 @@
1
+ This gem is a fork from [Rails Html Sanitizers](https://github.com/rails/rails-html-sanitizer) without rails dependency.
2
+
3
+ ## Installation
4
+
5
+ Add this line to your application's Gemfile:
6
+
7
+ gem 'html-sanitizer', github: 'dpisarewski/html-sanitizer'
8
+
9
+ And then execute:
10
+
11
+ $ bundle
12
+
13
+ ## Usage
14
+
15
+ ### Sanitizers
16
+
17
+ All sanitizers respond to `sanitize`.
18
+
19
+ #### FullSanitizer
20
+
21
+ ```ruby
22
+ full_sanitizer = Html::FullSanitizer.new
23
+ full_sanitizer.sanitize("<b>Bold</b> no more! <a href='more.html'>See more here</a>...")
24
+ # => Bold no more! See more here...
25
+ ```
26
+
27
+ #### LinkSanitizer
28
+
29
+ ```ruby
30
+ link_sanitizer = Html::LinkSanitizer.new
31
+ link_sanitizer.sanitize('<a href="example.com">Only the link text will be kept.</a>')
32
+ # => Only the link text will be kept.
33
+ ```
34
+
35
+ #### WhiteListSanitizer
36
+
37
+ ```ruby
38
+ white_list_sanitizer = Html::WhiteListSanitizer.new
39
+
40
+ # sanitize via an extensive white list of allowed elements
41
+ white_list_sanitizer.sanitize(@article.body)
42
+
43
+ # white list only the supplied tags and attributes
44
+ white_list_sanitizer.sanitize(@article.body, tags: %w(table tr td), attributes: %w(id class style))
45
+
46
+ # white list via a custom scrubber
47
+ white_list_sanitizer.sanitize(@article.body, scrubber: ArticleScrubber.new)
48
+
49
+ # white list sanitizer can also sanitize css
50
+ white_list_sanitizer.sanitize_css('background-color: #000;')
51
+ ```
52
+
53
+ ### Scrubbers
54
+
55
+ Scrubbers are objects responsible for removing nodes or attributes you don't want in your HTML document.
56
+
57
+ This gem includes two scrubbers `Html::PermitScrubber` and `Html::TargetScrubber`.
58
+
59
+ #### `Html::PermitScrubber`
60
+
61
+ This scrubber allows you to permit only the tags and attributes you want.
62
+
63
+ ```ruby
64
+ scrubber = Html::PermitScrubber.new
65
+ scrubber.tags = ['a']
66
+
67
+ html_fragment = Loofah.fragment('<a><img/ ></a>')
68
+ html_fragment.scrub!(scrubber)
69
+ html_fragment.to_s # => "<a></a>"
70
+ ```
71
+
72
+ #### `Html::TargetScrubber`
73
+
74
+ Where `PermitScrubber` picks out tags and attributes to permit in sanitization,
75
+ `Html::TargetScrubber` targets them for removal.
76
+
77
+
78
+ ```ruby
79
+ scrubber = Html::TargetScrubber.new
80
+ scrubber.tags = ['img']
81
+
82
+ html_fragment = Loofah.fragment('<a><img/ ></a>')
83
+ html_fragment.scrub!(scrubber)
84
+ html_fragment.to_s # => "<a></a>"
85
+ ```
86
+
87
+ #### Custom Scrubbers
88
+
89
+ You can also create custom scrubbers in your application if you want to.
90
+
91
+ ```ruby
92
+ class CommentScrubber < Html::PermitScrubber
93
+ def allowed_node?(node)
94
+ !%w(form script comment blockquote).include?(node.name)
95
+ end
96
+
97
+ def skip_node?(node)
98
+ node.text?
99
+ end
100
+
101
+ def scrub_attribute?(name)
102
+ name == "style"
103
+ end
104
+ end
105
+ ```
106
+
107
+ See `Html::PermitScrubber` documentation to learn more about which methods can be overridden.
108
+
109
+ ## Read more
110
+
111
+ Loofah is what underlies the sanitizers and scrubbers of rails-html-sanitizer.
112
+ - [Loofah and Loofah Scrubbers](https://github.com/flavorjones/loofah)
113
+
114
+ The `node` argument passed to some methods in a custom scrubber is an instance of `Nokogiri::XML::Node`.
115
+ - [`Nokogiri::XML::Node`](http://nokogiri.org/Nokogiri/XML/Node.html)
116
+ - [Nokogiri](http://nokogiri.org)
117
+
118
+ ## Contributing
119
+
120
+ 1. Fork it
121
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
122
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
123
+ 4. Push to the branch (`git push origin my-new-feature`)
124
+ 5. Create new Pull Request
@@ -0,0 +1,22 @@
1
+ require "html/sanitizer/version"
2
+ require "loofah"
3
+ require "html/sanitizer/scrubbers"
4
+ require "html/sanitizer/sanitizer"
5
+
6
+ module Html
7
+ class Sanitizer
8
+ class << self
9
+ def full_sanitizer
10
+ Html::FullSanitizer
11
+ end
12
+
13
+ def link_sanitizer
14
+ Html::LinkSanitizer
15
+ end
16
+
17
+ def white_list_sanitizer
18
+ Html::WhiteListSanitizer
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,139 @@
1
+ module Html
2
+ XPATHS_TO_REMOVE = %w{.//script .//form comment()}
3
+
4
+ class Sanitizer # :nodoc:
5
+ def sanitize(html, options = {})
6
+ raise NotImplementedError, "subclasses must implement sanitize method."
7
+ end
8
+
9
+ private
10
+
11
+ def remove_xpaths(node, xpaths)
12
+ node.xpath(*xpaths).remove
13
+ node
14
+ end
15
+ end
16
+
17
+ # === Html::FullSanitizer
18
+ # Removes all tags but strips out scripts, forms and comments.
19
+ #
20
+ # full_sanitizer = Html::FullSanitizer.new
21
+ # full_sanitizer.sanitize("<b>Bold</b> no more! <a href='more.html'>See more here</a>...")
22
+ # # => Bold no more! See more here...
23
+ class FullSanitizer < Sanitizer
24
+ def sanitize(html, options = {})
25
+ return unless html
26
+ return html if html.empty?
27
+
28
+ Loofah.fragment(html).tap do |fragment|
29
+ remove_xpaths(fragment, XPATHS_TO_REMOVE)
30
+ end.text
31
+ end
32
+ end
33
+
34
+ # === Html::LinkSanitizer
35
+ # Removes a tags and href attributes leaving only the link text
36
+ #
37
+ # link_sanitizer = Html::LinkSanitizer.new
38
+ # link_sanitizer.sanitize('<a href="example.com">Only the link text will be kept.</a>')
39
+ # # => Only the link text will be kept.
40
+ class LinkSanitizer < Sanitizer
41
+ def initialize
42
+ @link_scrubber = TargetScrubber.new
43
+ @link_scrubber.tags = %w(a href)
44
+ @link_scrubber.attributes = %w(href)
45
+ end
46
+
47
+ def sanitize(html, options = {})
48
+ Loofah.scrub_fragment(html, @link_scrubber).to_s
49
+ end
50
+ end
51
+
52
+ # === Html::WhiteListSanitizer
53
+ # Sanitizes html and css from an extensive white list (see link further down).
54
+ #
55
+ # === Whitespace
56
+ # We can't make any guarentees about whitespace being kept or stripped.
57
+ # Loofah uses Nokogiri, which wraps either a C or Java parser for the
58
+ # respective Ruby implementation.
59
+ # Those two parsers determine how whitespace is ultimately handled.
60
+ #
61
+ # When the stripped markup will be rendered the users browser won't take
62
+ # whitespace into account anyway. It might be better to suggest your users
63
+ # wrap their whitespace sensitive content in pre tags or that you do
64
+ # so automatically.
65
+ #
66
+ # === Options
67
+ # Sanitizes both html and css via the white lists found here:
68
+ # https://github.com/flavorjones/loofah/blob/master/lib/loofah/html5/whitelist.rb
69
+ #
70
+ # WhiteListSanitizer also accepts options to configure
71
+ # the white list used when sanitizing html.
72
+ # There's a class level option:
73
+ # Html::WhiteListSanitizer.allowed_tags = %w(table tr td)
74
+ # Html::WhiteListSanitizer.allowed_attributes = %w(id class style)
75
+ #
76
+ # Tags and attributes can also be passed to +sanitize+.
77
+ # Passed options take precedence over the class level options.
78
+ #
79
+ # === Examples
80
+ # white_list_sanitizer = Html::WhiteListSanitizer.new
81
+ #
82
+ # Sanitize css doesn't take options
83
+ # white_list_sanitizer.sanitize_css('background-color: #000;')
84
+ #
85
+ # Default: sanitize via a extensive white list of allowed elements
86
+ # white_list_sanitizer.sanitize(@article.body)
87
+ #
88
+ # White list via the supplied tags and attributes
89
+ # white_list_sanitizer.sanitize(@article.body, tags: %w(table tr td),
90
+ # attributes: %w(id class style))
91
+ #
92
+ # White list via a custom scrubber
93
+ # white_list_sanitizer.sanitize(@article.body, scrubber: ArticleScrubber.new)
94
+ class WhiteListSanitizer < Sanitizer
95
+ class << self
96
+ attr_accessor :allowed_tags
97
+ attr_accessor :allowed_attributes
98
+ end
99
+
100
+ def initialize
101
+ @permit_scrubber = PermitScrubber.new
102
+ end
103
+
104
+ def sanitize(html, options = {})
105
+ return unless html
106
+ return html if html.empty?
107
+
108
+ loofah_fragment = Loofah.fragment(html)
109
+
110
+ if scrubber = options[:scrubber]
111
+ # No duck typing, Loofah ensures subclass of Loofah::Scrubber
112
+ loofah_fragment.scrub!(scrubber)
113
+ elsif allowed_tags(options) || allowed_attributes(options)
114
+ @permit_scrubber.tags = allowed_tags(options)
115
+ @permit_scrubber.attributes = allowed_attributes(options)
116
+ loofah_fragment.scrub!(@permit_scrubber)
117
+ else
118
+ remove_xpaths(loofah_fragment, XPATHS_TO_REMOVE)
119
+ loofah_fragment.scrub!(:strip)
120
+ end
121
+
122
+ loofah_fragment.to_s
123
+ end
124
+
125
+ def sanitize_css(style_string)
126
+ Loofah::HTML5::Scrub.scrub_css(style_string)
127
+ end
128
+
129
+ private
130
+
131
+ def allowed_tags(options)
132
+ options[:tags] || self.class.allowed_tags
133
+ end
134
+
135
+ def allowed_attributes(options)
136
+ options[:attributes] || self.class.allowed_attributes
137
+ end
138
+ end
139
+ end
@@ -0,0 +1,146 @@
1
+ module Html
2
+ # === Html::PermitScrubber
3
+ #
4
+ # Html::PermitScrubber allows you to permit only your own tags and/or attributes.
5
+ #
6
+ # Html::PermitScrubber can be subclassed to determine:
7
+ # - When a node should be skipped via +skip_node?+.
8
+ # - When a node is allowed via +allowed_node?+.
9
+ # - When an attribute should be scrubbed via +scrub_attribute?+.
10
+ #
11
+ # Subclasses don't need to worry if tags or attributes are set or not.
12
+ # If tags or attributes are not set, Loofah's behavior will be used.
13
+ # If you override +allowed_node?+ and no tags are set, it will not be called.
14
+ # Instead Loofahs behavior will be used.
15
+ # Likewise for +scrub_attribute?+ and attributes respectively.
16
+ #
17
+ # Text and CDATA nodes are skipped by default.
18
+ # Unallowed elements will be stripped, i.e. element is removed but its subtree kept.
19
+ # Supplied tags and attributes should be Enumerables.
20
+ #
21
+ # +tags=+
22
+ # If set, elements excluded will be stripped.
23
+ # If not, elements are stripped based on Loofahs +HTML5::Scrub.allowed_element?+.
24
+ #
25
+ # +attributes=+
26
+ # If set, attributes excluded will be removed.
27
+ # If not, attributes are removed based on Loofahs +HTML5::Scrub.scrub_attributes+.
28
+ #
29
+ # class CommentScrubber < Html::PermitScrubber
30
+ # def allowed_node?(node)
31
+ # !%w(form script comment blockquote).include?(node.name)
32
+ # end
33
+ #
34
+ # def skip_node?(node)
35
+ # node.text?
36
+ # end
37
+ #
38
+ # def scrub_attribute?(name)
39
+ # name == "style"
40
+ # end
41
+ # end
42
+ #
43
+ # See the documentation for Nokogiri::XML::Node to understand what's possible
44
+ # with nodes: http://nokogiri.org/Nokogiri/XML/Node.html
45
+ class PermitScrubber < Loofah::Scrubber
46
+ attr_reader :tags, :attributes
47
+
48
+ def initialize
49
+ @direction = :bottom_up
50
+ @tags, @attributes = nil, nil
51
+ end
52
+
53
+ def tags=(tags)
54
+ @tags = validate!(tags, :tags)
55
+ end
56
+
57
+ def attributes=(attributes)
58
+ @attributes = validate!(attributes, :attributes)
59
+ end
60
+
61
+ def scrub(node)
62
+ return CONTINUE if skip_node?(node)
63
+
64
+ unless keep_node?(node)
65
+ return STOP if scrub_node(node) == STOP
66
+ end
67
+
68
+ scrub_attributes(node)
69
+ end
70
+
71
+ protected
72
+
73
+ def allowed_node?(node)
74
+ @tags.include?(node.name)
75
+ end
76
+
77
+ def skip_node?(node)
78
+ node.text? || node.cdata?
79
+ end
80
+
81
+ def scrub_attribute?(name)
82
+ !@attributes.include?(name)
83
+ end
84
+
85
+ def keep_node?(node)
86
+ if @tags
87
+ allowed_node?(node)
88
+ else
89
+ Loofah::HTML5::Scrub.allowed_element?(node.name)
90
+ end
91
+ end
92
+
93
+ def scrub_node(node)
94
+ node.before(node.children) # strip
95
+ node.remove
96
+ end
97
+
98
+ def scrub_attributes(node)
99
+ if @attributes
100
+ node.attribute_nodes.each do |attr|
101
+ attr.remove if scrub_attribute?(attr.name)
102
+ end
103
+
104
+ scrub_css_attribute(node)
105
+ else
106
+ Loofah::HTML5::Scrub.scrub_attributes(node)
107
+ end
108
+ end
109
+
110
+ def scrub_css_attribute(node)
111
+ if Loofah::HTML5::Scrub.respond_to?(:scrub_css_attribute)
112
+ Loofah::HTML5::Scrub.scrub_css_attribute(node)
113
+ else
114
+ style = node.attributes['style']
115
+ style.value = Loofah::HTML5::Scrub.scrub_css(style.value) if style
116
+ end
117
+ end
118
+
119
+ def validate!(var, name)
120
+ if var && !var.is_a?(Enumerable)
121
+ raise ArgumentError, "You should pass :#{name} as an Enumerable"
122
+ end
123
+ var
124
+ end
125
+ end
126
+
127
+ # === Html::TargetScrubber
128
+ #
129
+ # Where Html::PermitScrubber picks out tags and attributes to permit in
130
+ # sanitization, Html::TargetScrubber targets them for removal.
131
+ #
132
+ # +tags=+
133
+ # If set, elements included will be stripped.
134
+ #
135
+ # +attributes=+
136
+ # If set, attributes included will be removed.
137
+ class TargetScrubber < PermitScrubber
138
+ def allowed_node?(node)
139
+ !@tags.include?(node.name)
140
+ end
141
+
142
+ def scrub_attribute?(name)
143
+ @attributes.include?(name)
144
+ end
145
+ end
146
+ end
@@ -0,0 +1,5 @@
1
+ module Html
2
+ class Sanitizer
3
+ VERSION = "0.0.1"
4
+ end
5
+ end
@@ -0,0 +1,489 @@
1
+ require "minitest/autorun"
2
+ require "sanitizer"
3
+ require "rails/dom/testing/assertions/dom_assertions"
4
+
5
+ class SanitizersTest < Minitest::Test
6
+ include Rails::Dom::Testing::Assertions::DomAssertions
7
+
8
+ def test_sanitizer_sanitize_raises_not_implemented_error
9
+ assert_raises NotImplementedError do
10
+ Html::Sanitizer.new.sanitize('')
11
+ end
12
+ end
13
+
14
+ class XpathRemovalTestSanitizer < Html::Sanitizer
15
+ def sanitize(html, options = {})
16
+ fragment = Loofah.fragment(html)
17
+ remove_xpaths(fragment, options[:xpaths]).to_s
18
+ end
19
+ end
20
+
21
+ def test_remove_xpaths_removes_an_xpath
22
+ html = %(<h1>hello <script>code!</script></h1>)
23
+ assert_equal %(<h1>hello </h1>), xpath_sanitize(html, xpaths: %w(.//script))
24
+ end
25
+
26
+ def test_remove_xpaths_removes_all_occurences_of_xpath
27
+ html = %(<section><header><script>code!</script></header><p>hello <script>code!</script></p></section>)
28
+ assert_equal %(<section><header></header><p>hello </p></section>), xpath_sanitize(html, xpaths: %w(.//script))
29
+ end
30
+
31
+ def test_remove_xpaths_called_with_faulty_xpath
32
+ assert_raises Nokogiri::XML::XPath::SyntaxError do
33
+ xpath_sanitize('<h1>hello<h1>', xpaths: %w(..faulty_xpath))
34
+ end
35
+ end
36
+
37
+ def test_remove_xpaths_called_with_xpath_string
38
+ assert_equal '', xpath_sanitize('<a></a>', xpaths: './/a')
39
+ end
40
+
41
+ def test_remove_xpaths_called_with_enumerable_xpaths
42
+ assert_equal '', xpath_sanitize('<a><span></span></a>', xpaths: %w(.//a .//span))
43
+ end
44
+
45
+ def test_strip_tags_with_quote
46
+ input = '<" <img src="trollface.gif" onload="alert(1)"> hi'
47
+ assert_equal ' hi', full_sanitize(input)
48
+ end
49
+
50
+ def test_strip_invalid_html
51
+ assert_equal "", full_sanitize("<<<bad html")
52
+ end
53
+
54
+ def test_strip_nested_tags
55
+ expected = "Weia onclick='alert(document.cookie);'/&gt;rdos"
56
+ input = "Wei<<a>a onclick='alert(document.cookie);'</a>/>rdos"
57
+ assert_equal expected, full_sanitize(input)
58
+ end
59
+
60
+ def test_strip_tags_multiline
61
+ expected = %{This is a test.\n\n\n\nIt no longer contains any HTML.\n}
62
+ input = %{<title>This is <b>a <a href="" target="_blank">test</a></b>.</title>\n\n<!-- it has a comment -->\n\n<p>It no <b>longer <strong>contains <em>any <strike>HTML</strike></em>.</strong></b></p>\n}
63
+
64
+ assert_equal expected, full_sanitize(input)
65
+ end
66
+
67
+ def test_strip_comments
68
+ assert_equal "This is ", full_sanitize("This is <-- not\n a comment here.")
69
+ end
70
+
71
+ def test_strip_cdata
72
+ assert_equal "This has a ]]&gt; here.", full_sanitize("This has a <![CDATA[<section>]]> here.")
73
+ end
74
+
75
+ def test_strip_unclosed_cdata
76
+ assert_equal "This has an unclosed ]] here...", full_sanitize("This has an unclosed <![CDATA[<section>]] here...")
77
+ end
78
+
79
+ def test_strip_blank_string
80
+ [nil, '', ' '].each { |blank| assert_equal blank, full_sanitize(blank) }
81
+ end
82
+
83
+ def test_strip_tags_with_plaintext
84
+ assert_equal "Dont touch me", full_sanitize("Dont touch me")
85
+ end
86
+
87
+ def test_strip_tags_with_tags
88
+ assert_equal "This is a test.", full_sanitize("<p>This <u>is<u> a <a href='test.html'><strong>test</strong></a>.</p>")
89
+ end
90
+
91
+ def test_strip_tags_with_many_open_quotes
92
+ assert_equal "", full_sanitize("<<<bad html>")
93
+ end
94
+
95
+ def test_strip_tags_with_sentence
96
+ assert_equal "This is a test.", full_sanitize("This is a test.")
97
+ end
98
+
99
+ def test_strip_tags_with_comment
100
+ assert_equal "This has a here.", full_sanitize("This has a <!-- comment --> here.")
101
+ end
102
+
103
+ def test_strip_tags_with_frozen_string
104
+ assert_equal "Frozen string with no tags", full_sanitize("Frozen string with no tags".freeze)
105
+ end
106
+
107
+ def test_strip_links_with_tags_in_tags
108
+ expected = "a href='hello'&gt;all <b>day</b> long/a&gt;"
109
+ input = "<<a>a href='hello'>all <b>day</b> long<</A>/a>"
110
+ assert_equal expected, link_sanitize(input)
111
+ end
112
+
113
+ def test_strip_links_with_unclosed_tags
114
+ assert_equal "", link_sanitize("<a<a")
115
+ end
116
+
117
+ def test_strip_links_with_plaintext
118
+ assert_equal "Dont touch me", link_sanitize("Dont touch me")
119
+ end
120
+
121
+ def test_strip_links_with_line_feed_and_uppercase_tag
122
+ assert_equal "on my mind\nall day long", link_sanitize("<a href='almost'>on my mind</a>\n<A href='almost'>all day long</A>")
123
+ end
124
+
125
+ def test_strip_links_leaves_nonlink_tags
126
+ assert_equal "My mind\nall <b>day</b> long", link_sanitize("<a href='almost'>My mind</a>\n<A href='almost'>all <b>day</b> long</A>")
127
+ end
128
+
129
+ def test_strip_links_with_links
130
+ assert_equal "0wn3d", link_sanitize("<a href='http://www.rubyonrails.com/'><a href='http://www.rubyonrails.com/' onlclick='steal()'>0wn3d</a></a>")
131
+ end
132
+
133
+ def test_strip_links_with_linkception
134
+ assert_equal "Magic", link_sanitize("<a href='http://www.rubyonrails.com/'>Mag<a href='http://www.ruby-lang.org/'>ic")
135
+ end
136
+
137
+ def test_strip_links_with_a_tag_in_href
138
+ assert_equal "FrrFox", link_sanitize("<href onlclick='steal()'>FrrFox</a></href>")
139
+ end
140
+
141
+ def test_sanitize_form
142
+ assert_sanitized "<form action=\"/foo/bar\" method=\"post\"><input></form>", ''
143
+ end
144
+
145
+ def test_sanitize_plaintext
146
+ assert_sanitized "<plaintext><span>foo</span></plaintext>", "<span>foo</span>"
147
+ end
148
+
149
+ def test_sanitize_script
150
+ assert_sanitized "a b c<script language=\"Javascript\">blah blah blah</script>d e f", "a b cd e f"
151
+ end
152
+
153
+ def test_sanitize_js_handlers
154
+ raw = %{onthis="do that" <a href="#" onclick="hello" name="foo" onbogus="remove me">hello</a>}
155
+ assert_sanitized raw, %{onthis="do that" <a href="#" name="foo">hello</a>}
156
+ end
157
+
158
+ def test_sanitize_javascript_href
159
+ raw = %{href="javascript:bang" <a href="javascript:bang" name="hello">foo</a>, <span href="javascript:bang">bar</span>}
160
+ assert_sanitized raw, %{href="javascript:bang" <a name="hello">foo</a>, <span>bar</span>}
161
+ end
162
+
163
+ def test_sanitize_image_src
164
+ raw = %{src="javascript:bang" <img src="javascript:bang" width="5">foo</img>, <span src="javascript:bang">bar</span>}
165
+ assert_sanitized raw, %{src="javascript:bang" <img width="5">foo</img>, <span>bar</span>}
166
+ end
167
+
168
+ tags = Loofah::HTML5::WhiteList::ALLOWED_ELEMENTS - %w(script form)
169
+ tags.each do |tag_name|
170
+ define_method "test_should_allow_#{tag_name}_tag" do
171
+ assert_sanitized "start <#{tag_name} title=\"1\" onclick=\"foo\">foo <bad>bar</bad> baz</#{tag_name}> end", %(start <#{tag_name} title="1">foo bar baz</#{tag_name}> end)
172
+ end
173
+ end
174
+
175
+ def test_should_allow_anchors
176
+ assert_sanitized %(<a href="foo" onclick="bar"><script>baz</script></a>), %(<a href=\"foo\"></a>)
177
+ end
178
+
179
+ def test_video_poster_sanitization
180
+ assert_sanitized %(<video src="videofile.ogg" autoplay poster="posterimage.jpg"></video>), %(<video src="videofile.ogg" poster="posterimage.jpg"></video>)
181
+ assert_sanitized %(<video src="videofile.ogg" poster=javascript:alert(1)></video>), %(<video src="videofile.ogg"></video>)
182
+ end
183
+
184
+ # RFC 3986, sec 4.2
185
+ def test_allow_colons_in_path_component
186
+ assert_sanitized "<a href=\"./this:that\">foo</a>"
187
+ end
188
+
189
+ %w(src width height alt).each do |img_attr|
190
+ define_method "test_should_allow_image_#{img_attr}_attribute" do
191
+ assert_sanitized %(<img #{img_attr}="foo" onclick="bar" />), %(<img #{img_attr}="foo" />)
192
+ end
193
+ end
194
+
195
+ def test_should_handle_non_html
196
+ assert_sanitized 'abc'
197
+ end
198
+
199
+ def test_should_handle_blank_text
200
+ [nil, '', ' '].each { |blank| assert_sanitized blank }
201
+ end
202
+
203
+ def test_setting_allowed_tags_affects_sanitization
204
+ scope_allowed_tags %w(u) do |sanitizer|
205
+ assert_equal '<u></u>', sanitizer.sanitize('<a><u></u></a>')
206
+ end
207
+ end
208
+
209
+ def test_setting_allowed_attributes_affects_sanitization
210
+ scope_allowed_attributes %w(foo) do |sanitizer|
211
+ input = '<a foo="hello" bar="world"></a>'
212
+ assert_equal '<a foo="hello"></a>', sanitizer.sanitize(input)
213
+ end
214
+ end
215
+
216
+ def test_custom_tags_overrides_allowed_tags
217
+ scope_allowed_tags %(u) do |sanitizer|
218
+ input = '<a><u></u></a>'
219
+ assert_equal '<a></a>', sanitizer.sanitize(input, tags: %w(a))
220
+ end
221
+ end
222
+
223
+ def test_custom_attributes_overrides_allowed_attributes
224
+ scope_allowed_attributes %(foo) do |sanitizer|
225
+ input = '<a foo="hello" bar="world"></a>'
226
+ assert_equal '<a bar="world"></a>', sanitizer.sanitize(input, attributes: %w(bar))
227
+ end
228
+ end
229
+
230
+ def test_should_allow_custom_tags
231
+ text = "<u>foo</u>"
232
+ assert_equal text, white_list_sanitize(text, tags: %w(u))
233
+ end
234
+
235
+ def test_should_allow_only_custom_tags
236
+ text = "<u>foo</u> with <i>bar</i>"
237
+ assert_equal "<u>foo</u> with bar", white_list_sanitize(text, tags: %w(u))
238
+ end
239
+
240
+ def test_should_allow_custom_tags_with_attributes
241
+ text = %(<blockquote cite="http://example.com/">foo</blockquote>)
242
+ assert_equal text, white_list_sanitize(text)
243
+ end
244
+
245
+ def test_should_allow_custom_tags_with_custom_attributes
246
+ text = %(<blockquote foo="bar">Lorem ipsum</blockquote>)
247
+ assert_equal text, white_list_sanitize(text, attributes: ['foo'])
248
+ end
249
+
250
+ def test_scrub_style_if_style_attribute_option_is_passed
251
+ input = '<p style="color: #000; background-image: url(http://www.ragingplatypus.com/i/cam-full.jpg);"></p>'
252
+ assert_equal '<p style="color: #000;"></p>', white_list_sanitize(input, attributes: %w(style))
253
+ end
254
+
255
+ def test_should_raise_argument_error_if_tags_is_not_enumerable
256
+ assert_raises ArgumentError do
257
+ white_list_sanitize('<a>some html</a>', tags: 'foo')
258
+ end
259
+ end
260
+
261
+ def test_should_raise_argument_error_if_attributes_is_not_enumerable
262
+ assert_raises ArgumentError do
263
+ white_list_sanitize('<a>some html</a>', attributes: 'foo')
264
+ end
265
+ end
266
+
267
+ def test_should_not_accept_non_loofah_inheriting_scrubber
268
+ scrubber = Object.new
269
+ def scrubber.scrub(node); node.name = 'h1'; end
270
+
271
+ assert_raises Loofah::ScrubberNotFound do
272
+ white_list_sanitize('<a>some html</a>', scrubber: scrubber)
273
+ end
274
+ end
275
+
276
+ def test_should_accept_loofah_inheriting_scrubber
277
+ scrubber = Loofah::Scrubber.new
278
+ def scrubber.scrub(node); node.name = 'h1'; end
279
+
280
+ html = "<script>hello!</script>"
281
+ assert_equal "<h1>hello!</h1>", white_list_sanitize(html, scrubber: scrubber)
282
+ end
283
+
284
+ def test_should_accept_loofah_scrubber_that_wraps_a_block
285
+ scrubber = Loofah::Scrubber.new { |node| node.name = 'h1' }
286
+ html = "<script>hello!</script>"
287
+ assert_equal "<h1>hello!</h1>", white_list_sanitize(html, scrubber: scrubber)
288
+ end
289
+
290
+ def test_custom_scrubber_takes_precedence_over_other_options
291
+ scrubber = Loofah::Scrubber.new { |node| node.name = 'h1' }
292
+ html = "<script>hello!</script>"
293
+ assert_equal "<h1>hello!</h1>", white_list_sanitize(html, scrubber: scrubber, tags: ['foo'])
294
+ end
295
+
296
+ [%w(img src), %w(a href)].each do |(tag, attr)|
297
+ define_method "test_should_strip_#{attr}_attribute_in_#{tag}_with_bad_protocols" do
298
+ assert_sanitized %(<#{tag} #{attr}="javascript:bang" title="1">boo</#{tag}>), %(<#{tag} title="1">boo</#{tag}>)
299
+ end
300
+ end
301
+
302
+ def test_should_block_script_tag
303
+ assert_sanitized %(<SCRIPT\nSRC=http://ha.ckers.org/xss.js></SCRIPT>), ""
304
+ end
305
+
306
+ def test_should_not_fall_for_xss_image_hack_with_uppercase_tags
307
+ assert_sanitized %(<IMG """><SCRIPT>alert("XSS")</SCRIPT>">), "<img>\"&gt;"
308
+ end
309
+
310
+ [%(<IMG SRC="javascript:alert('XSS');">),
311
+ %(<IMG SRC=javascript:alert('XSS')>),
312
+ %(<IMG SRC=JaVaScRiPt:alert('XSS')>),
313
+ %(<IMG SRC=javascript:alert(&quot;XSS&quot;)>),
314
+ %(<IMG SRC=javascript:alert(String.fromCharCode(88,83,83))>),
315
+ %(<IMG SRC=&#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;&#58;&#97;&#108;&#101;&#114;&#116;&#40;&#39;&#88;&#83;&#83;&#39;&#41;>),
316
+ %(<IMG SRC=&#0000106&#0000097&#0000118&#0000097&#0000115&#0000099&#0000114&#0000105&#0000112&#0000116&#0000058&#0000097&#0000108&#0000101&#0000114&#0000116&#0000040&#0000039&#0000088&#0000083&#0000083&#0000039&#0000041>),
317
+ %(<IMG SRC=&#x6A&#x61&#x76&#x61&#x73&#x63&#x72&#x69&#x70&#x74&#x3A&#x61&#x6C&#x65&#x72&#x74&#x28&#x27&#x58&#x53&#x53&#x27&#x29>),
318
+ %(<IMG SRC="jav\tascript:alert('XSS');">),
319
+ %(<IMG SRC="jav&#x09;ascript:alert('XSS');">),
320
+ %(<IMG SRC="jav&#x0A;ascript:alert('XSS');">),
321
+ %(<IMG SRC="jav&#x0D;ascript:alert('XSS');">),
322
+ %(<IMG SRC=" &#14; javascript:alert('XSS');">),
323
+ %(<IMG SRC="javascript&#x3a;alert('XSS');">),
324
+ %(<IMG SRC=`javascript:alert("RSnake says, 'XSS'")`>)].each_with_index do |img_hack, i|
325
+ define_method "test_should_not_fall_for_xss_image_hack_#{i+1}" do
326
+ assert_sanitized img_hack, "<img>"
327
+ end
328
+ end
329
+
330
+ def test_should_sanitize_tag_broken_up_by_null
331
+ assert_sanitized %(<SCR\0IPT>alert(\"XSS\")</SCR\0IPT>), ""
332
+ end
333
+
334
+ def test_should_sanitize_invalid_script_tag
335
+ assert_sanitized %(<SCRIPT/XSS SRC="http://ha.ckers.org/xss.js"></SCRIPT>), ""
336
+ end
337
+
338
+ def test_should_sanitize_script_tag_with_multiple_open_brackets
339
+ assert_sanitized %(<<SCRIPT>alert("XSS");//<</SCRIPT>), "alert(\"XSS\");//"
340
+ assert_sanitized %(<iframe src=http://ha.ckers.org/scriptlet.html\n<a), ""
341
+ end
342
+
343
+ def test_should_sanitize_unclosed_script
344
+ assert_sanitized %(<SCRIPT SRC=http://ha.ckers.org/xss.js?<B>), ""
345
+ end
346
+
347
+ def test_should_sanitize_half_open_scripts
348
+ assert_sanitized %(<IMG SRC="javascript:alert('XSS')"), "<img>"
349
+ end
350
+
351
+ def test_should_not_fall_for_ridiculous_hack
352
+ img_hack = %(<IMG\nSRC\n=\n"\nj\na\nv\na\ns\nc\nr\ni\np\nt\n:\na\nl\ne\nr\nt\n(\n'\nX\nS\nS\n'\n)\n"\n>)
353
+ assert_sanitized img_hack, "<img>"
354
+ end
355
+
356
+ def test_should_sanitize_attributes
357
+ assert_sanitized %(<SPAN title="'><script>alert()</script>">blah</SPAN>), %(<span title="#{CGI.escapeHTML "'><script>alert()</script>"}">blah</span>)
358
+ end
359
+
360
+ def test_should_sanitize_illegal_style_properties
361
+ raw = %(display:block; position:absolute; left:0; top:0; width:100%; height:100%; z-index:1; background-color:black; background-image:url(http://www.ragingplatypus.com/i/cam-full.jpg); background-x:center; background-y:center; background-repeat:repeat;)
362
+ expected = %(display: block; width: 100%; height: 100%; background-color: black; background-x: center; background-y: center;)
363
+ assert_equal expected, sanitize_css(raw)
364
+ end
365
+
366
+ def test_should_sanitize_with_trailing_space
367
+ raw = "display:block; "
368
+ expected = "display: block;"
369
+ assert_equal expected, sanitize_css(raw)
370
+ end
371
+
372
+ def test_should_sanitize_xul_style_attributes
373
+ raw = %(-moz-binding:url('http://ha.ckers.org/xssmoz.xml#xss'))
374
+ assert_equal '', sanitize_css(raw)
375
+ end
376
+
377
+ def test_should_sanitize_invalid_tag_names
378
+ assert_sanitized(%(a b c<script/XSS src="http://ha.ckers.org/xss.js"></script>d e f), "a b cd e f")
379
+ end
380
+
381
+ def test_should_sanitize_non_alpha_and_non_digit_characters_in_tags
382
+ assert_sanitized('<a onclick!#$%&()*~+-_.,:;?@[/|\]^`=alert("XSS")>foo</a>', "<a>foo</a>")
383
+ end
384
+
385
+ def test_should_sanitize_invalid_tag_names_in_single_tags
386
+ assert_sanitized('<img/src="http://ha.ckers.org/xss.js"/>', "<img />")
387
+ end
388
+
389
+ def test_should_sanitize_img_dynsrc_lowsrc
390
+ assert_sanitized(%(<img lowsrc="javascript:alert('XSS')" />), "<img />")
391
+ end
392
+
393
+ def test_should_sanitize_div_background_image_unicode_encoded
394
+ raw = %(background-image:\0075\0072\006C\0028'\006a\0061\0076\0061\0073\0063\0072\0069\0070\0074\003a\0061\006c\0065\0072\0074\0028.1027\0058.1053\0053\0027\0029'\0029)
395
+ assert_equal '', sanitize_css(raw)
396
+ end
397
+
398
+ def test_should_sanitize_div_style_expression
399
+ raw = %(width: expression(alert('XSS'));)
400
+ assert_equal '', sanitize_css(raw)
401
+ end
402
+
403
+ def test_should_sanitize_across_newlines
404
+ raw = %(\nwidth:\nexpression(alert('XSS'));\n)
405
+ assert_equal '', sanitize_css(raw)
406
+ end
407
+
408
+ def test_should_sanitize_img_vbscript
409
+ assert_sanitized %(<img src='vbscript:msgbox("XSS")' />), '<img />'
410
+ end
411
+
412
+ def test_should_sanitize_cdata_section
413
+ assert_sanitized "<![CDATA[<span>section</span>]]>", "section]]&gt;"
414
+ end
415
+
416
+ def test_should_sanitize_unterminated_cdata_section
417
+ assert_sanitized "<![CDATA[<span>neverending...", "neverending..."
418
+ end
419
+
420
+ def test_should_not_mangle_urls_with_ampersand
421
+ assert_sanitized %{<a href=\"http://www.domain.com?var1=1&amp;var2=2\">my link</a>}
422
+ end
423
+
424
+ def test_should_sanitize_neverending_attribute
425
+ assert_sanitized "<span class=\"\\", "<span class=\"\\\">"
426
+ end
427
+
428
+ [
429
+ %(<a href="javascript&#x3a;alert('XSS');">),
430
+ %(<a href="javascript&#x003a;alert('XSS');">),
431
+ %(<a href="javascript&#x3A;alert('XSS');">),
432
+ %(<a href="javascript&#x003A;alert('XSS');">)
433
+ ].each_with_index do |enc_hack, i|
434
+ define_method "test_x03a_handling_#{i+1}" do
435
+ assert_sanitized enc_hack, "<a>"
436
+ end
437
+ end
438
+
439
+ def test_x03a_legitimate
440
+ assert_sanitized %(<a href="http&#x3a;//legit">), %(<a href="http://legit">)
441
+ assert_sanitized %(<a href="http&#x3A;//legit">), %(<a href="http://legit">)
442
+ end
443
+
444
+ protected
445
+
446
+ def xpath_sanitize(input, options = {})
447
+ XpathRemovalTestSanitizer.new.sanitize(input, options)
448
+ end
449
+
450
+ def full_sanitize(input, options = {})
451
+ Html::FullSanitizer.new.sanitize(input, options)
452
+ end
453
+
454
+ def link_sanitize(input, options = {})
455
+ Html::LinkSanitizer.new.sanitize(input, options)
456
+ end
457
+
458
+ def white_list_sanitize(input, options = {})
459
+ Html::WhiteListSanitizer.new.sanitize(input, options)
460
+ end
461
+
462
+ def assert_sanitized(input, expected = nil)
463
+ if input
464
+ assert_dom_equal expected || input, white_list_sanitize(input)
465
+ else
466
+ assert_nil white_list_sanitize(input)
467
+ end
468
+ end
469
+
470
+ def sanitize_css(input)
471
+ Html::WhiteListSanitizer.new.sanitize_css(input)
472
+ end
473
+
474
+ def scope_allowed_tags(tags)
475
+ Html::WhiteListSanitizer.allowed_tags = %w(u)
476
+ yield Html::WhiteListSanitizer.new
477
+
478
+ ensure
479
+ Html::WhiteListSanitizer.allowed_tags = nil
480
+ end
481
+
482
+ def scope_allowed_attributes(attributes)
483
+ Html::WhiteListSanitizer.allowed_attributes = attributes
484
+ yield Html::WhiteListSanitizer.new
485
+
486
+ ensure
487
+ Html::WhiteListSanitizer.allowed_attributes = nil
488
+ end
489
+ end
@@ -0,0 +1,160 @@
1
+ require "minitest/autorun"
2
+ require "sanitizer"
3
+
4
+ class ScrubberTest < Minitest::Test
5
+ protected
6
+
7
+ def assert_scrubbed(html, expected = html)
8
+ output = Loofah.scrub_fragment(html, @scrubber).to_s
9
+ assert_equal expected, output
10
+ end
11
+
12
+ def to_node(text)
13
+ Loofah.fragment(text).children.first
14
+ end
15
+
16
+ def assert_node_skipped(text)
17
+ assert_scrub_returns(Loofah::Scrubber::CONTINUE, text)
18
+ end
19
+
20
+ def assert_scrub_stopped(text)
21
+ assert_scrub_returns(Loofah::Scrubber::STOP, text)
22
+ end
23
+
24
+ def assert_scrub_returns(return_value, text)
25
+ node = to_node(text)
26
+ assert_equal return_value, @scrubber.scrub(node)
27
+ end
28
+ end
29
+
30
+ class PermitScrubberTest < ScrubberTest
31
+
32
+ def setup
33
+ @scrubber = Html::PermitScrubber.new
34
+ end
35
+
36
+ def test_responds_to_scrub
37
+ assert @scrubber.respond_to?(:scrub)
38
+ end
39
+
40
+ def test_default_scrub_behavior
41
+ assert_scrubbed '<tag>hello</tag>', 'hello'
42
+ end
43
+
44
+ def test_default_attributes_removal_behavior
45
+ assert_scrubbed '<p cooler="hello">hello</p>', '<p>hello</p>'
46
+ end
47
+
48
+ def test_leaves_supplied_tags
49
+ @scrubber.tags = %w(a)
50
+ assert_scrubbed '<a>hello</a>'
51
+ end
52
+
53
+ def test_leaves_only_supplied_tags
54
+ html = '<tag>leave me <span>now</span></tag>'
55
+ @scrubber.tags = %w(tag)
56
+ assert_scrubbed html, '<tag>leave me now</tag>'
57
+ end
58
+
59
+ def test_leaves_only_supplied_tags_nested
60
+ html = '<tag>leave <em>me <span>now</span></em></tag>'
61
+ @scrubber.tags = %w(tag)
62
+ assert_scrubbed html, '<tag>leave me now</tag>'
63
+ end
64
+
65
+ def test_leaves_supplied_attributes
66
+ @scrubber.attributes = %w(cooler)
67
+ assert_scrubbed '<a cooler="hello"></a>'
68
+ end
69
+
70
+ def test_leaves_only_supplied_attributes
71
+ @scrubber.attributes = %w(cooler)
72
+ assert_scrubbed '<a cooler="hello" b="c" d="e"></a>', '<a cooler="hello"></a>'
73
+ end
74
+
75
+ def test_leaves_supplied_tags_and_attributes
76
+ @scrubber.tags = %w(tag)
77
+ @scrubber.attributes = %w(cooler)
78
+ assert_scrubbed '<tag cooler="hello"></tag>'
79
+ end
80
+
81
+ def test_leaves_only_supplied_tags_and_attributes
82
+ @scrubber.tags = %w(tag)
83
+ @scrubber.attributes = %w(cooler)
84
+ html = '<a></a><tag href=""></tag><tag cooler=""></tag>'
85
+ assert_scrubbed html, '<tag></tag><tag cooler=""></tag>'
86
+ end
87
+
88
+ def test_leaves_text
89
+ assert_scrubbed('some text')
90
+ end
91
+
92
+ def test_skips_text_nodes
93
+ assert_node_skipped('some text')
94
+ end
95
+
96
+ def test_tags_accessor_validation
97
+ e = assert_raises(ArgumentError) do
98
+ @scrubber.tags = 'tag'
99
+ end
100
+
101
+ assert_equal "You should pass :tags as an Enumerable", e.message
102
+ assert_nil @scrubber.tags, "Tags should be nil when validation fails"
103
+ end
104
+
105
+ def test_attributes_accessor_validation
106
+ e = assert_raises(ArgumentError) do
107
+ @scrubber.attributes = 'cooler'
108
+ end
109
+
110
+ assert_equal "You should pass :attributes as an Enumerable", e.message
111
+ assert_nil @scrubber.attributes, "Attributes should be nil when validation fails"
112
+ end
113
+ end
114
+
115
+ class TargetScrubberTest < ScrubberTest
116
+ def setup
117
+ @scrubber = Html::TargetScrubber.new
118
+ end
119
+
120
+ def test_targeting_tags_removes_only_them
121
+ @scrubber.tags = %w(a h1)
122
+ html = '<script></script><a></a><h1></h1>'
123
+ assert_scrubbed html, '<script></script>'
124
+ end
125
+
126
+ def test_targeting_tags_removes_only_them_nested
127
+ @scrubber.tags = %w(a)
128
+ html = '<tag><a><tag><a></a></tag></a></tag>'
129
+ assert_scrubbed html, '<tag><tag></tag></tag>'
130
+ end
131
+
132
+ def test_targeting_attributes_removes_only_them
133
+ @scrubber.attributes = %w(class id)
134
+ html = '<a class="a" id="b" onclick="c"></a>'
135
+ assert_scrubbed html, '<a onclick="c"></a>'
136
+ end
137
+
138
+ def test_targeting_tags_and_attributes_removes_only_them
139
+ @scrubber.tags = %w(tag)
140
+ @scrubber.attributes = %w(remove)
141
+ html = '<tag remove="" other=""></tag><a remove="" other=""></a>'
142
+ assert_scrubbed html, '<a other=""></a>'
143
+ end
144
+ end
145
+
146
+ class ReturningStopFromScrubNodeTest < ScrubberTest
147
+ class ScrubStopper < Html::PermitScrubber
148
+ def scrub_node(node)
149
+ Loofah::Scrubber::STOP
150
+ end
151
+ end
152
+
153
+ def setup
154
+ @scrubber = ScrubStopper.new
155
+ end
156
+
157
+ def test_returns_stop_from_scrub_if_scrub_node_does
158
+ assert_scrub_stopped '<script>remove me</script>'
159
+ end
160
+ end
metadata ADDED
@@ -0,0 +1,127 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: html-sanitizer
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Rafael Mendonça França
8
+ - Kasper Timm Hansen
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2014-12-19 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '2.0'
20
+ name: loofah
21
+ prerelease: false
22
+ type: :runtime
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ~>
26
+ - !ruby/object:Gem::Version
27
+ version: '2.0'
28
+ - !ruby/object:Gem::Dependency
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '1.3'
34
+ name: bundler
35
+ prerelease: false
36
+ type: :development
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ~>
40
+ - !ruby/object:Gem::Version
41
+ version: '1.3'
42
+ - !ruby/object:Gem::Dependency
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ name: rake
49
+ prerelease: false
50
+ type: :development
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - '>='
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ - !ruby/object:Gem::Dependency
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ name: minitest
63
+ prerelease: false
64
+ type: :development
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ - !ruby/object:Gem::Dependency
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ name: rails-dom-testing
77
+ prerelease: false
78
+ type: :development
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - '>='
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ description: HTML sanitization
85
+ email:
86
+ - dieter.pisarewski@gmail.com
87
+ - rafaelmfranca@gmail.com
88
+ - kaspth@gmail.com
89
+ executables: []
90
+ extensions: []
91
+ extra_rdoc_files: []
92
+ files:
93
+ - LICENSE.txt
94
+ - README.md
95
+ - lib/html/sanitizer.rb
96
+ - lib/html/sanitizer/sanitizer.rb
97
+ - lib/html/sanitizer/scrubbers.rb
98
+ - lib/html/sanitizer/version.rb
99
+ - test/sanitizer_test.rb
100
+ - test/scrubbers_test.rb
101
+ homepage: https://github.com/dpisarewski/html-sanitizer
102
+ licenses:
103
+ - MIT
104
+ metadata: {}
105
+ post_install_message:
106
+ rdoc_options: []
107
+ require_paths:
108
+ - lib
109
+ required_ruby_version: !ruby/object:Gem::Requirement
110
+ requirements:
111
+ - - '>='
112
+ - !ruby/object:Gem::Version
113
+ version: '0'
114
+ required_rubygems_version: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - '>='
117
+ - !ruby/object:Gem::Version
118
+ version: '0'
119
+ requirements: []
120
+ rubyforge_project:
121
+ rubygems_version: 2.2.2
122
+ signing_key:
123
+ specification_version: 4
124
+ summary: This gem is responsible to sanitize HTML fragments.
125
+ test_files:
126
+ - test/sanitizer_test.rb
127
+ - test/scrubbers_test.rb