loofah 2.0.3 → 2.1.0.rc1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of loofah might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1ede2fa4b15b118b6040d43ec57d90782e6a8234
4
- data.tar.gz: e0e4ed5ebb391793549d27245834bb67189e83c3
3
+ metadata.gz: a709ec5b5b8064cd96fd216b5ac5ece3db3c2099
4
+ data.tar.gz: 212f9cb43700926714c873d2dd6ee661bcdb832a
5
5
  SHA512:
6
- metadata.gz: ca75adb9b1dad4f99f7182767518a4a935bc960ec81db86eb848f30bb918089f570ab29bfa9f2973e0bd3608876cd47c8af1fcb01a6596e5e845307b21caffd9
7
- data.tar.gz: 42fea8ec3d59389976f2613d4dd763f9f7c7260069f113d7044d55daeb83850750f2d5803354b0d431f2fef25e7a65c0e5cbe2b916d1e26072c6ccd531183d6a
6
+ metadata.gz: 31120a6cb665a25b264707c6a85aff7a14beab7269e20a3d4403a72ae0b2bf625b6942df6178e92e419b1859c7e48255f19c407003f031773426cf158a953d14
7
+ data.tar.gz: 21386a195c02a5faa3d52ff14f82534a087da91f009260d215bc07c8a46976803f424b2ddf4969756e7f63dec40ee0a270aac6d0549d9362fb87756da13b532d
data/CHANGELOG.rdoc CHANGED
@@ -1,5 +1,16 @@
1
1
  = Changelog
2
2
 
3
+ == 2.1.0.rc1 / 2015-08-17
4
+
5
+ Notes:
6
+
7
+ * Re-implemented CSS parsing and sanitization using the {crass}[https://github.com/rgrove/crass] library. #91
8
+
9
+ Bug fixes:
10
+
11
+ * Allow negative values in CSS properties. Restores functionality that was reverted in v2.0.3. #91
12
+
13
+
3
14
  == 2.0.3 / 2015-08-17
4
15
 
5
16
  Bug fixes:
data/Gemfile CHANGED
@@ -5,6 +5,7 @@
5
5
  source "https://rubygems.org/"
6
6
 
7
7
  gem "nokogiri", ">=1.5.9"
8
+ gem "crass", "~>1.0.2"
8
9
 
9
10
  gem "rdoc", "~>4.0", :group => [:development, :test]
10
11
  gem "rake", ">=0.8", :group => [:development, :test]
@@ -15,6 +16,6 @@ gem "hoe-gemspec", ">=0", :group => [:development, :test]
15
16
  gem "hoe-debugging", ">=0", :group => [:development, :test]
16
17
  gem "hoe-bundler", ">=0", :group => [:development, :test]
17
18
  gem "hoe-git", ">=0", :group => [:development, :test]
18
- gem "hoe", "~>3.6", :group => [:development, :test]
19
+ gem "hoe", "~>3.13", :group => [:development, :test]
19
20
 
20
21
  # vim: syntax=ruby
data/Rakefile CHANGED
@@ -17,6 +17,7 @@ Hoe.spec "loofah" do
17
17
  self.license "MIT"
18
18
 
19
19
  extra_deps << ["nokogiri", ">=1.5.9"]
20
+ extra_deps << ["crass", "~> 1.0.2"]
20
21
 
21
22
  extra_dev_deps << ["rake", ">=0.8"]
22
23
  extra_dev_deps << ["minitest", "~>2.2"]
data/lib/loofah.rb CHANGED
@@ -27,7 +27,7 @@ require 'loofah/html/document_fragment'
27
27
  #
28
28
  module Loofah
29
29
  # The version of Loofah you are using
30
- VERSION = '2.0.3'
30
+ VERSION = '2.1.0.rc1'
31
31
 
32
32
  class << self
33
33
  # Shortcut for Loofah::HTML::Document.parse
@@ -1,12 +1,15 @@
1
1
  #encoding: US-ASCII
2
2
 
3
3
  require 'cgi'
4
+ require 'crass'
4
5
 
5
6
  module Loofah
6
7
  module HTML5 # :nodoc:
7
8
  module Scrub
8
9
 
9
10
  CONTROL_CHARACTERS = /[`\u0000-\u0020\u007f\u0080-\u0101]/
11
+ CSS_KEYWORDISH = /\A(#[0-9a-f]+|rgb\(\d+%?,\d*%?,?\d*%?\)?|-?\d{0,2}\.?\d{0,2}(cm|em|ex|in|mm|pc|pt|px|%|,|\))?)\z/
12
+ CRASS_SEMICOLON = {:node => :semicolon, :raw => ";"}
10
13
 
11
14
  class << self
12
15
 
@@ -61,36 +64,35 @@ module Loofah
61
64
  style.value = scrub_css(style.value) if style
62
65
  end
63
66
 
64
- # lifted nearly verbatim from html5lib
65
67
  def scrub_css style
66
- # disallow urls
67
- style = style.to_s.gsub(/url\s*\(\s*[^\s)]+?\s*\)\s*/, ' ')
68
+ style_tree = Crass.parse_properties style
69
+ sanitized_tree = []
68
70
 
69
- # gauntlet
70
- return '' unless style =~ /\A([:,;#%.\sa-zA-Z0-9!]|\w-\w|\'[\s\w]+\'|\"[\s\w]+\"|\([\d,\s]+\))*\z/
71
- return '' unless style =~ /\A\s*([-\w]+\s*:[^:;]*(;\s*|$))*\z/
72
-
73
- clean = []
74
- style.scan(/([-\w]+)\s*:\s*([^:;]*)/) do |prop, val|
75
- next if val.empty?
76
- prop.downcase!
77
- if WhiteList::ALLOWED_CSS_PROPERTIES.include?(prop)
78
- clean << "#{prop}: #{val};"
79
- elsif WhiteList::SHORTHAND_CSS_PROPERTIES.include?(prop.split('-')[0])
80
- clean << "#{prop}: #{val};" unless val.split().any? do |keyword|
81
- !WhiteList::ALLOWED_CSS_KEYWORDS.include?(keyword) &&
82
- keyword !~ /\A(#[0-9a-f]+|rgb\(\d+%?,\d*%?,?\d*%?\)?|-?\d{0,2}\.?\d{0,2}(cm|em|ex|in|mm|pc|pt|px|%|,|\))?)\z/
71
+ style_tree.each do |node|
72
+ next unless node[:node] == :property
73
+ next if node[:children].any? do |child|
74
+ [:url, :bad_url, :function].include? child[:node]
75
+ end
76
+ name = node[:name].downcase
77
+ if WhiteList::ALLOWED_CSS_PROPERTIES.include?(name) || WhiteList::ALLOWED_SVG_PROPERTIES.include?(name)
78
+ sanitized_tree << node << CRASS_SEMICOLON
79
+ elsif WhiteList::SHORTHAND_CSS_PROPERTIES.include?(name.split('-').first)
80
+ value = node[:value].split.map do |keyword|
81
+ if WhiteList::ALLOWED_CSS_KEYWORDS.include?(keyword) || keyword =~ CSS_KEYWORDISH
82
+ keyword
83
+ end
84
+ end.compact
85
+ unless value.empty?
86
+ propstring = sprintf "%s:%s", name, value.join(" ")
87
+ sanitized_node = Crass.parse_properties(propstring).first
88
+ sanitized_tree << sanitized_node << CRASS_SEMICOLON
83
89
  end
84
- elsif WhiteList::ALLOWED_SVG_PROPERTIES.include?(prop)
85
- clean << "#{prop}: #{val};"
86
90
  end
87
91
  end
88
92
 
89
- style = clean.join(' ')
93
+ Crass::Parser.stringify sanitized_tree
90
94
  end
91
-
92
95
  end
93
-
94
96
  end
95
97
  end
96
98
  end
@@ -152,7 +152,7 @@
152
152
  {
153
153
  "name": "platypus",
154
154
  "input": "<a href=\"http://www.ragingplatypus.com/\" style=\"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;\">never trust your upstream platypus</a>",
155
- "output": "<a href='http://www.ragingplatypus.com/' style='display: block; width: 100%; height: 100%; background-color: black; background-x: center; background-y: center;'>never trust your upstream platypus</a>"
155
+ "output": "<a href='http://www.ragingplatypus.com/' style='display:block;width:100%;height:100%;background-color:black;background-x:center;background-y:center;'>never trust your upstream platypus</a>"
156
156
  },
157
157
 
158
158
  {
@@ -229,14 +229,12 @@ class Html5TestSanitizer < Loofah::TestCase
229
229
  end
230
230
 
231
231
  def test_css_negative_value_sanitization
232
- skip "pending better CSS parsing, see https://github.com/flavorjones/loofah/issues/90"
233
232
  html = "<span style=\"letter-spacing:-0.03em;\">"
234
233
  sane = Nokogiri::HTML(Loofah.scrub_fragment(html, :escape).to_xml)
235
234
  assert_match %r/-0.03em/, sane.inner_html
236
235
  end
237
236
 
238
237
  def test_css_negative_value_sanitization_shorthand_css_properties
239
- skip "pending better CSS parsing, see https://github.com/flavorjones/loofah/issues/90"
240
238
  html = "<span style=\"margin-left:-0.05em;\">"
241
239
  sane = Nokogiri::HTML(Loofah.scrub_fragment(html, :escape).to_xml)
242
240
  assert_match %r/-0.05em/, sane.inner_html
@@ -246,9 +244,34 @@ class Html5TestSanitizer < Loofah::TestCase
246
244
  html = %q{<span style="background: url('data:image/svg&#43;xml;charset=utf-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2232%22%20height%3D%2232%22%20viewBox%3D%220%200%2032%2032%22%3E%3Cpath%20fill%3D%22%23D4C8AE%22%20d%3D%22M0%200h32v32h-32z%22%2F%3E%3Cpath%20fill%3D%22%2383604B%22%20d%3D%22M0%200h31.99v11.75h-31.99z%22%2F%3E%3Cpath%20fill%3D%22%233D2319%22%20d%3D%22M0%2011.5h32v.5h-32z%22%2F%3E%3Cpath%20fill%3D%22%23F83651%22%20d%3D%22M5%200h1v10.5h-1z%22%2F%3E%3Cpath%20fill%3D%22%23FCD050%22%20d%3D%22M6%200h1v10.5h-1z%22%2F%3E%3Cpath%20fill%3D%22%2371C797%22%20d%3D%22M7%200h1v10.5h-1z%22%2F%3E%3Cpath%20fill%3D%22%23509CF9%22%20d%3D%22M8%200h1v10.5h-1z%22%2F%3E%3ClinearGradient%20id%3D%22a%22%20gradientUnits%3D%22userSpaceOnUse%22%20x1%3D%2224.996%22%20y1%3D%2210.5%22%20x2%3D%2224.996%22%20y2%3D%224.5%22%3E%3Cstop%20offset%3D%220%22%20stop-color%3D%22%23796055%22%2F%3E%3Cstop%20offset%3D%22.434%22%20stop-color%3D%22%23614C43%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%233D2D28%22%2F%3E%3C%2FlinearGradient%3E%3Cpath%20fill%3D%22url(%23a)%22%20d%3D%22M28%208.5c0%201.1-.9%202-2%202h-2c-1.1%200-2-.9-2-2v-2c0-1.1.9-2%202-2h2c1.1%200%202%20.9%202%202v2z%22%2F%3E%3Cpath%20fill%3D%22%235F402E%22%20d%3D%22M28%208c0%201.1-.9%202-2%202h-2c-1.1%200-2-.9-2-2v-2c0-1.1.9-2%202-2h2c1.1%200%202%20.9%202%202v2z%22%2F%3E%3C');"></span>}
247
245
 
248
246
  assert_completes_in_reasonable_time {
249
- sane = Nokogiri::HTML(Loofah.scrub_fragment(html, :strip).to_html)
247
+ Nokogiri::HTML(Loofah.scrub_fragment(html, :strip).to_html)
250
248
  }
251
249
  end
250
+
251
+ def test_upper_case_css_property
252
+ html = "<div style=\"COLOR: BLUE; NOTAPROPERTY: RED;\">asdf</div>"
253
+ sane = Nokogiri::HTML(Loofah.scrub_fragment(html, :strip).to_xml)
254
+ assert_match /COLOR:\s*BLUE/i, sane.at_css("div")["style"]
255
+ refute_match /NOTAPROPERTY/i, sane.at_css("div")["style"]
256
+ end
257
+
258
+ def test_many_properties_some_allowed
259
+ html = "<div style=\"background: bold notaproperty center alsonotaproperty 10px;\">asdf</div>"
260
+ sane = Nokogiri::HTML(Loofah.scrub_fragment(html, :strip).to_xml)
261
+ assert_match /bold\s+center\s+10px/, sane.at_css("div")["style"]
262
+ end
263
+
264
+ def test_many_properties_non_allowed
265
+ html = "<div style=\"background: notaproperty alsonotaproperty;\">asdf</div>"
266
+ sane = Nokogiri::HTML(Loofah.scrub_fragment(html, :strip).to_xml)
267
+ assert_nil sane.at_css("div")["style"]
268
+ end
269
+
270
+ def test_svg_properties
271
+ html = "<line style='stroke-width: 10px;'></line>"
272
+ sane = Nokogiri::HTML(Loofah.scrub_fragment(html, :strip).to_xml)
273
+ assert_match /stroke-width:\s*10px/, sane.at_css("line")["style"]
274
+ end
252
275
  end
253
276
 
254
277
  # <html5_license>
@@ -37,7 +37,7 @@ class IntegrationTestHelpers < Loofah::TestCase
37
37
 
38
38
  context ".sanitize_css" do
39
39
  it "removes unsafe css properties" do
40
- assert_equal "display: block; background-color: blue;", Loofah::Helpers.sanitize_css("display:block;background-image:url(http://www.ragingplatypus.com/i/cam-full.jpg);background-color:blue")
40
+ assert_match /display:\s*block;\s*background-color:\s*blue;/, Loofah::Helpers.sanitize_css("display:block;background-image:url(http://www.ragingplatypus.com/i/cam-full.jpg);background-color:blue")
41
41
  end
42
42
  end
43
43
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: loofah
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.3
4
+ version: 2.1.0.rc1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Dalessio
@@ -25,6 +25,20 @@ dependencies:
25
25
  - - ">="
26
26
  - !ruby/object:Gem::Version
27
27
  version: 1.5.9
28
+ - !ruby/object:Gem::Dependency
29
+ name: crass
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - "~>"
33
+ - !ruby/object:Gem::Version
34
+ version: 1.0.2
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "~>"
40
+ - !ruby/object:Gem::Version
41
+ version: 1.0.2
28
42
  - !ruby/object:Gem::Dependency
29
43
  name: rdoc
30
44
  requirement: !ruby/object:Gem::Requirement
@@ -243,9 +257,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
243
257
  version: '0'
244
258
  required_rubygems_version: !ruby/object:Gem::Requirement
245
259
  requirements:
246
- - - ">="
260
+ - - ">"
247
261
  - !ruby/object:Gem::Version
248
- version: '0'
262
+ version: 1.3.1
249
263
  requirements: []
250
264
  rubyforge_project:
251
265
  rubygems_version: 2.4.6