loofah 2.6.0 → 2.19.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -7,23 +7,26 @@ module Loofah
7
7
  module Scrub
8
8
  CONTROL_CHARACTERS = /[`\u0000-\u0020\u007f\u0080-\u0101]/
9
9
  CSS_KEYWORDISH = /\A(#[0-9a-fA-F]+|rgb\(\d+%?,\d*%?,?\d*%?\)?|-?\d{0,3}\.?\d{0,10}(ch|cm|r?em|ex|in|lh|mm|pc|pt|px|Q|vmax|vmin|vw|vh|%|,|\))?)\z/
10
- CRASS_SEMICOLON = { :node => :semicolon, :raw => ";" }
10
+ CRASS_SEMICOLON = { node: :semicolon, raw: ";" }
11
+ CSS_IMPORTANT = '!important'
12
+ CSS_PROPERTY_STRING_WITHOUT_EMBEDDED_QUOTES = /\A(["'])?[^"']+\1\z/
13
+ DATA_ATTRIBUTE_NAME = /\Adata-[\w-]+\z/
11
14
 
12
15
  class << self
13
16
  def allowed_element?(element_name)
14
- ::Loofah::HTML5::SafeList::ALLOWED_ELEMENTS_WITH_LIBXML2.include? element_name
17
+ ::Loofah::HTML5::SafeList::ALLOWED_ELEMENTS_WITH_LIBXML2.include?(element_name)
15
18
  end
16
19
 
17
20
  # alternative implementation of the html5lib attribute scrubbing algorithm
18
21
  def scrub_attributes(node)
19
22
  node.attribute_nodes.each do |attr_node|
20
23
  attr_name = if attr_node.namespace
21
- "#{attr_node.namespace.prefix}:#{attr_node.node_name}"
22
- else
23
- attr_node.node_name
24
- end
24
+ "#{attr_node.namespace.prefix}:#{attr_node.node_name}"
25
+ else
26
+ attr_node.node_name
27
+ end
25
28
 
26
- if attr_name =~ /\Adata-[\w-]+\z/
29
+ if attr_name =~ DATA_ATTRIBUTE_NAME
27
30
  next
28
31
  end
29
32
 
@@ -33,37 +36,28 @@ module Loofah
33
36
  end
34
37
 
35
38
  if SafeList::ATTR_VAL_IS_URI.include?(attr_name)
36
- # this block lifted nearly verbatim from HTML5 sanitization
37
- val_unescaped = CGI.unescapeHTML(attr_node.value).gsub(CONTROL_CHARACTERS, "").downcase
38
- if val_unescaped =~ /^[a-z0-9][-+.a-z0-9]*:/ && !SafeList::ALLOWED_PROTOCOLS.include?(val_unescaped.split(SafeList::PROTOCOL_SEPARATOR)[0])
39
- attr_node.remove
40
- next
41
- elsif val_unescaped.split(SafeList::PROTOCOL_SEPARATOR)[0] == "data"
42
- # permit only allowed data mediatypes
43
- mediatype = val_unescaped.split(SafeList::PROTOCOL_SEPARATOR)[1]
44
- mediatype, _ = mediatype.split(";")[0..1] if mediatype
45
- if mediatype && !SafeList::ALLOWED_URI_DATA_MEDIATYPES.include?(mediatype)
46
- attr_node.remove
47
- next
48
- end
49
- end
39
+ next if scrub_uri_attribute(attr_node)
50
40
  end
41
+
51
42
  if SafeList::SVG_ATTR_VAL_ALLOWS_REF.include?(attr_name)
52
- attr_node.value = attr_node.value.gsub(/url\s*\(\s*[^#\s][^)]+?\)/m, " ") if attr_node.value
43
+ scrub_attribute_that_allows_local_ref(attr_node)
53
44
  end
45
+
54
46
  if SafeList::SVG_ALLOW_LOCAL_HREF.include?(node.name) && attr_name == "xlink:href" && attr_node.value =~ /^\s*[^#\s].*/m
55
47
  attr_node.remove
56
48
  next
57
49
  end
58
50
  end
59
51
 
60
- scrub_css_attribute node
52
+ scrub_css_attribute(node)
61
53
 
62
54
  node.attribute_nodes.each do |attr_node|
63
- node.remove_attribute(attr_node.name) if attr_node.value !~ /[^[:space:]]/
55
+ if attr_node.value !~ /[^[:space:]]/ && attr_node.name !~ DATA_ATTRIBUTE_NAME
56
+ node.remove_attribute(attr_node.name)
57
+ end
64
58
  end
65
59
 
66
- force_correct_attribute_escaping! node
60
+ force_correct_attribute_escaping!(node)
67
61
  end
68
62
 
69
63
  def scrub_css_attribute(node)
@@ -72,32 +66,95 @@ module Loofah
72
66
  end
73
67
 
74
68
  def scrub_css(style)
75
- style_tree = Crass.parse_properties style
69
+ style_tree = Crass.parse_properties(style)
76
70
  sanitized_tree = []
77
71
 
78
72
  style_tree.each do |node|
79
73
  next unless node[:node] == :property
80
74
  next if node[:children].any? do |child|
81
- [:url, :bad_url].include?(child[:node]) || (child[:node] == :function && !SafeList::ALLOWED_CSS_FUNCTIONS.include?(child[:name].downcase))
75
+ [:url, :bad_url].include?(child[:node])
82
76
  end
77
+
83
78
  name = node[:name].downcase
84
- if SafeList::ALLOWED_CSS_PROPERTIES.include?(name) || SafeList::ALLOWED_SVG_PROPERTIES.include?(name)
85
- sanitized_tree << node << CRASS_SEMICOLON
86
- elsif SafeList::SHORTHAND_CSS_PROPERTIES.include?(name.split("-").first)
87
- value = node[:value].split.map do |keyword|
88
- if SafeList::ALLOWED_CSS_KEYWORDS.include?(keyword) || keyword =~ CSS_KEYWORDISH
79
+ next unless SafeList::ALLOWED_CSS_PROPERTIES.include?(name) ||
80
+ SafeList::ALLOWED_SVG_PROPERTIES.include?(name) ||
81
+ SafeList::SHORTHAND_CSS_PROPERTIES.include?(name.split("-").first)
82
+
83
+ value = node[:children].map do |child|
84
+ case child[:node]
85
+ when :whitespace
86
+ nil
87
+ when :string
88
+ if child[:raw] =~ CSS_PROPERTY_STRING_WITHOUT_EMBEDDED_QUOTES
89
+ Crass::Parser.stringify(child)
90
+ else
91
+ nil
92
+ end
93
+ when :function
94
+ if SafeList::ALLOWED_CSS_FUNCTIONS.include?(child[:name].downcase)
95
+ Crass::Parser.stringify(child)
96
+ end
97
+ when :ident
98
+ keyword = child[:value]
99
+ if !SafeList::SHORTHAND_CSS_PROPERTIES.include?(name.split("-").first) ||
100
+ SafeList::ALLOWED_CSS_KEYWORDS.include?(keyword) ||
101
+ (keyword =~ CSS_KEYWORDISH)
89
102
  keyword
90
103
  end
91
- end.compact
92
- unless value.empty?
93
- propstring = sprintf "%s:%s", name, value.join(" ")
94
- sanitized_node = Crass.parse_properties(propstring).first
95
- sanitized_tree << sanitized_node << CRASS_SEMICOLON
104
+ else
105
+ child[:raw]
96
106
  end
97
- end
107
+ end.compact
108
+
109
+ next if value.empty?
110
+ value << CSS_IMPORTANT if node[:important]
111
+ propstring = format("%s:%s", name, value.join(" "))
112
+ sanitized_node = Crass.parse_properties(propstring).first
113
+ sanitized_tree << sanitized_node << CRASS_SEMICOLON
98
114
  end
99
115
 
100
- Crass::Parser.stringify sanitized_tree
116
+ Crass::Parser.stringify(sanitized_tree)
117
+ end
118
+
119
+ def scrub_attribute_that_allows_local_ref(attr_node)
120
+ return unless attr_node.value
121
+
122
+ nodes = Crass::Parser.new(attr_node.value).parse_component_values
123
+
124
+ values = nodes.map do |node|
125
+ case node[:node]
126
+ when :url
127
+ if node[:value].start_with?("#")
128
+ node[:raw]
129
+ else
130
+ nil
131
+ end
132
+ when :hash, :ident, :string
133
+ node[:raw]
134
+ else
135
+ nil
136
+ end
137
+ end.compact
138
+
139
+ attr_node.value = values.join(" ")
140
+ end
141
+
142
+ def scrub_uri_attribute(attr_node)
143
+ # this block lifted nearly verbatim from HTML5 sanitization
144
+ val_unescaped = CGI.unescapeHTML(attr_node.value).gsub(CONTROL_CHARACTERS, "").downcase
145
+ if val_unescaped =~ /^[a-z0-9][-+.a-z0-9]*:/ && !SafeList::ALLOWED_PROTOCOLS.include?(val_unescaped.split(SafeList::PROTOCOL_SEPARATOR)[0])
146
+ attr_node.remove
147
+ return true
148
+ elsif val_unescaped.split(SafeList::PROTOCOL_SEPARATOR)[0] == "data"
149
+ # permit only allowed data mediatypes
150
+ mediatype = val_unescaped.split(SafeList::PROTOCOL_SEPARATOR)[1]
151
+ mediatype, _ = mediatype.split(";")[0..1] if mediatype
152
+ if mediatype && !SafeList::ALLOWED_URI_DATA_MEDIATYPES.include?(mediatype)
153
+ attr_node.remove
154
+ return true
155
+ end
156
+ end
157
+ false
101
158
  end
102
159
 
103
160
  #
@@ -125,6 +182,46 @@ module Loofah
125
182
  end.force_encoding(encoding)
126
183
  end
127
184
  end
185
+
186
+ def cdata_needs_escaping?(node)
187
+ # Nokogiri's HTML4 parser on JRuby doesn't flag the child of a `style` or `script` tag as cdata, but it acts that way
188
+ node.cdata? || (Nokogiri.jruby? && node.text? && (node.parent.name == "style" || node.parent.name == "script"))
189
+ end
190
+
191
+ def cdata_escape(node)
192
+ escaped_text = escape_tags(node.text)
193
+ if Nokogiri.jruby?
194
+ node.document.create_text_node(escaped_text)
195
+ else
196
+ node.document.create_cdata(escaped_text)
197
+ end
198
+ end
199
+
200
+ TABLE_FOR_ESCAPE_HTML__ = {
201
+ '<' => '&lt;',
202
+ '>' => '&gt;',
203
+ '&' => '&amp;',
204
+ }
205
+
206
+ def escape_tags(string)
207
+ # modified version of CGI.escapeHTML from ruby 3.1
208
+ enc = string.encoding
209
+ unless enc.ascii_compatible?
210
+ if enc.dummy?
211
+ origenc = enc
212
+ enc = Encoding::Converter.asciicompat_encoding(enc)
213
+ string = enc ? string.encode(enc) : string.b
214
+ end
215
+ table = Hash[TABLE_FOR_ESCAPE_HTML__.map {|pair|pair.map {|s|s.encode(enc)}}]
216
+ string = string.gsub(/#{"[<>&]".encode(enc)}/, table)
217
+ string.encode!(origenc) if origenc
218
+ string
219
+ else
220
+ string = string.b
221
+ string.gsub!(/[<>&]/, TABLE_FOR_ESCAPE_HTML__)
222
+ string.force_encoding(enc)
223
+ end
224
+ end
128
225
  end
129
226
  end
130
227
  end
@@ -93,7 +93,11 @@ module Loofah
93
93
  # frag.text(:encode_special_chars => false) # => "<script>alert('EVIL');</script>"
94
94
  #
95
95
  def text(options = {})
96
- result = serialize_root.children.inner_text rescue ""
96
+ result = if serialize_root
97
+ serialize_root.children.reject(&:comment?).map(&:inner_text).join("")
98
+ else
99
+ ""
100
+ end
97
101
  if options[:encode_special_chars] == false
98
102
  result # possibly dangerous if rendered in a browser
99
103
  else
@@ -108,11 +112,11 @@ module Loofah
108
112
  # Returns a plain-text version of the markup contained by the
109
113
  # fragment, with HTML entities encoded.
110
114
  #
111
- # This method is slower than #to_text, but is clever about
112
- # whitespace around block elements.
115
+ # This method is slower than #text, but is clever about
116
+ # whitespace around block elements and line break elements.
113
117
  #
114
- # Loofah.document("<h1>Title</h1><div>Content</div>").to_text
115
- # # => "\nTitle\n\nContent\n"
118
+ # Loofah.document("<h1>Title</h1><div>Content<br>Next line</div>").to_text
119
+ # # => "\nTitle\n\nContent\nNext line\n"
116
120
  #
117
121
  def to_text(options = {})
118
122
  Loofah.remove_extraneous_whitespace self.dup.scrub!(:newline_block_elements).text(options)
@@ -108,6 +108,10 @@ module Loofah
108
108
  return Scrubber::CONTINUE
109
109
  end
110
110
  when Nokogiri::XML::Node::TEXT_NODE, Nokogiri::XML::Node::CDATA_SECTION_NODE
111
+ if HTML5::Scrub.cdata_needs_escaping?(node)
112
+ node.before(HTML5::Scrub.cdata_escape(node))
113
+ return Scrubber::STOP
114
+ end
111
115
  return Scrubber::CONTINUE
112
116
  end
113
117
  Scrubber::STOP
@@ -100,13 +100,9 @@ module Loofah
100
100
 
101
101
  def scrub(node)
102
102
  return CONTINUE if html5lib_sanitize(node) == CONTINUE
103
- if node.children.length == 1 && node.children.first.cdata?
104
- sanitized_text = Loofah.fragment(node.children.first.to_html).scrub!(:strip).to_html
105
- node.before Nokogiri::XML::Text.new(sanitized_text, node.document)
106
- else
107
- node.before node.children
108
- end
103
+ node.before(node.children)
109
104
  node.remove
105
+ return STOP
110
106
  end
111
107
  end
112
108
 
@@ -240,8 +236,13 @@ module Loofah
240
236
  end
241
237
 
242
238
  def scrub(node)
243
- return CONTINUE unless Loofah::Elements::BLOCK_LEVEL.include?(node.name)
244
- node.add_next_sibling Nokogiri::XML::Text.new("\n#{node.content}\n", node.document)
239
+ return CONTINUE unless Loofah::Elements::LINEBREAKERS.include?(node.name)
240
+ replacement = if Loofah::Elements::INLINE_LINE_BREAK.include?(node.name)
241
+ "\n"
242
+ else
243
+ "\n#{node.content}\n"
244
+ end
245
+ node.add_next_sibling Nokogiri::XML::Text.new(replacement, node.document)
245
246
  node.remove
246
247
  end
247
248
  end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+ module Loofah
3
+ # The version of Loofah you are using
4
+ VERSION = "2.19.1"
5
+ end
data/lib/loofah.rb CHANGED
@@ -3,21 +3,22 @@ $LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__))) unless $LOAD_PATH.i
3
3
 
4
4
  require "nokogiri"
5
5
 
6
- require "loofah/metahelpers"
7
- require "loofah/elements"
6
+ require_relative "loofah/version"
7
+ require_relative "loofah/metahelpers"
8
+ require_relative "loofah/elements"
8
9
 
9
- require "loofah/html5/safelist"
10
- require "loofah/html5/libxml2_workarounds"
11
- require "loofah/html5/scrub"
10
+ require_relative "loofah/html5/safelist"
11
+ require_relative "loofah/html5/libxml2_workarounds"
12
+ require_relative "loofah/html5/scrub"
12
13
 
13
- require "loofah/scrubber"
14
- require "loofah/scrubbers"
14
+ require_relative "loofah/scrubber"
15
+ require_relative "loofah/scrubbers"
15
16
 
16
- require "loofah/instance_methods"
17
- require "loofah/xml/document"
18
- require "loofah/xml/document_fragment"
19
- require "loofah/html/document"
20
- require "loofah/html/document_fragment"
17
+ require_relative "loofah/instance_methods"
18
+ require_relative "loofah/xml/document"
19
+ require_relative "loofah/xml/document_fragment"
20
+ require_relative "loofah/html/document"
21
+ require_relative "loofah/html/document_fragment"
21
22
 
22
23
  # == Strings and IO Objects as Input
23
24
  #
@@ -28,9 +29,6 @@ require "loofah/html/document_fragment"
28
29
  # quantities of docs.
29
30
  #
30
31
  module Loofah
31
- # The version of Loofah you are using
32
- VERSION = "2.6.0"
33
-
34
32
  class << self
35
33
  # Shortcut for Loofah::HTML::Document.parse
36
34
  # This method accepts the same parameters as Nokogiri::HTML::Document.parse
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.6.0
4
+ version: 2.19.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Dalessio
@@ -9,22 +9,8 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2020-06-16 00:00:00.000000000 Z
12
+ date: 2022-12-12 00:00:00.000000000 Z
13
13
  dependencies:
14
- - !ruby/object:Gem::Dependency
15
- name: nokogiri
16
- requirement: !ruby/object:Gem::Requirement
17
- requirements:
18
- - - ">="
19
- - !ruby/object:Gem::Version
20
- version: 1.5.9
21
- type: :runtime
22
- prerelease: false
23
- version_requirements: !ruby/object:Gem::Requirement
24
- requirements:
25
- - - ">="
26
- - !ruby/object:Gem::Version
27
- version: 1.5.9
28
14
  - !ruby/object:Gem::Dependency
29
15
  name: crass
30
16
  requirement: !ruby/object:Gem::Requirement
@@ -40,193 +26,123 @@ dependencies:
40
26
  - !ruby/object:Gem::Version
41
27
  version: 1.0.2
42
28
  - !ruby/object:Gem::Dependency
43
- name: rake
44
- requirement: !ruby/object:Gem::Requirement
45
- requirements:
46
- - - "~>"
47
- - !ruby/object:Gem::Version
48
- version: '12.3'
49
- type: :development
50
- prerelease: false
51
- version_requirements: !ruby/object:Gem::Requirement
52
- requirements:
53
- - - "~>"
54
- - !ruby/object:Gem::Version
55
- version: '12.3'
56
- - !ruby/object:Gem::Dependency
57
- name: minitest
29
+ name: nokogiri
58
30
  requirement: !ruby/object:Gem::Requirement
59
31
  requirements:
60
- - - "~>"
32
+ - - ">="
61
33
  - !ruby/object:Gem::Version
62
- version: '2.2'
63
- type: :development
34
+ version: 1.5.9
35
+ type: :runtime
64
36
  prerelease: false
65
37
  version_requirements: !ruby/object:Gem::Requirement
66
38
  requirements:
67
- - - "~>"
39
+ - - ">="
68
40
  - !ruby/object:Gem::Version
69
- version: '2.2'
41
+ version: 1.5.9
70
42
  - !ruby/object:Gem::Dependency
71
- name: rr
43
+ name: hoe-markdown
72
44
  requirement: !ruby/object:Gem::Requirement
73
45
  requirements:
74
46
  - - "~>"
75
47
  - !ruby/object:Gem::Version
76
- version: 1.2.0
48
+ version: '1.3'
77
49
  type: :development
78
50
  prerelease: false
79
51
  version_requirements: !ruby/object:Gem::Requirement
80
52
  requirements:
81
53
  - - "~>"
82
54
  - !ruby/object:Gem::Version
83
- version: 1.2.0
55
+ version: '1.3'
84
56
  - !ruby/object:Gem::Dependency
85
57
  name: json
86
58
  requirement: !ruby/object:Gem::Requirement
87
59
  requirements:
88
60
  - - "~>"
89
61
  - !ruby/object:Gem::Version
90
- version: 2.2.0
62
+ version: '2.2'
91
63
  type: :development
92
64
  prerelease: false
93
65
  version_requirements: !ruby/object:Gem::Requirement
94
66
  requirements:
95
67
  - - "~>"
96
68
  - !ruby/object:Gem::Version
97
- version: 2.2.0
69
+ version: '2.2'
98
70
  - !ruby/object:Gem::Dependency
99
- name: hoe-gemspec
71
+ name: minitest
100
72
  requirement: !ruby/object:Gem::Requirement
101
73
  requirements:
102
74
  - - "~>"
103
75
  - !ruby/object:Gem::Version
104
- version: '1.0'
76
+ version: '5.14'
105
77
  type: :development
106
78
  prerelease: false
107
79
  version_requirements: !ruby/object:Gem::Requirement
108
80
  requirements:
109
81
  - - "~>"
110
82
  - !ruby/object:Gem::Version
111
- version: '1.0'
83
+ version: '5.14'
112
84
  - !ruby/object:Gem::Dependency
113
- name: hoe-debugging
85
+ name: rake
114
86
  requirement: !ruby/object:Gem::Requirement
115
87
  requirements:
116
88
  - - "~>"
117
89
  - !ruby/object:Gem::Version
118
- version: '2.0'
90
+ version: '13.0'
119
91
  type: :development
120
92
  prerelease: false
121
93
  version_requirements: !ruby/object:Gem::Requirement
122
94
  requirements:
123
95
  - - "~>"
124
96
  - !ruby/object:Gem::Version
125
- version: '2.0'
97
+ version: '13.0'
126
98
  - !ruby/object:Gem::Dependency
127
- name: hoe-bundler
99
+ name: rdoc
128
100
  requirement: !ruby/object:Gem::Requirement
129
101
  requirements:
130
- - - "~>"
131
- - !ruby/object:Gem::Version
132
- version: '1.5'
133
- type: :development
134
- prerelease: false
135
- version_requirements: !ruby/object:Gem::Requirement
136
- requirements:
137
- - - "~>"
102
+ - - ">="
138
103
  - !ruby/object:Gem::Version
139
- version: '1.5'
140
- - !ruby/object:Gem::Dependency
141
- name: hoe-git
142
- requirement: !ruby/object:Gem::Requirement
143
- requirements:
144
- - - "~>"
104
+ version: '4.0'
105
+ - - "<"
145
106
  - !ruby/object:Gem::Version
146
- version: '1.6'
107
+ version: '7'
147
108
  type: :development
148
109
  prerelease: false
149
110
  version_requirements: !ruby/object:Gem::Requirement
150
111
  requirements:
151
- - - "~>"
112
+ - - ">="
113
+ - !ruby/object:Gem::Version
114
+ version: '4.0'
115
+ - - "<"
152
116
  - !ruby/object:Gem::Version
153
- version: '1.6'
117
+ version: '7'
154
118
  - !ruby/object:Gem::Dependency
155
- name: hoe-markdown
119
+ name: rr
156
120
  requirement: !ruby/object:Gem::Requirement
157
121
  requirements:
158
122
  - - "~>"
159
123
  - !ruby/object:Gem::Version
160
- version: '1.2'
124
+ version: 1.2.0
161
125
  type: :development
162
126
  prerelease: false
163
127
  version_requirements: !ruby/object:Gem::Requirement
164
128
  requirements:
165
129
  - - "~>"
166
130
  - !ruby/object:Gem::Version
167
- version: '1.2'
168
- - !ruby/object:Gem::Dependency
169
- name: concourse
170
- requirement: !ruby/object:Gem::Requirement
171
- requirements:
172
- - - ">="
173
- - !ruby/object:Gem::Version
174
- version: 0.26.0
175
- type: :development
176
- prerelease: false
177
- version_requirements: !ruby/object:Gem::Requirement
178
- requirements:
179
- - - ">="
180
- - !ruby/object:Gem::Version
181
- version: 0.26.0
131
+ version: 1.2.0
182
132
  - !ruby/object:Gem::Dependency
183
133
  name: rubocop
184
- requirement: !ruby/object:Gem::Requirement
185
- requirements:
186
- - - ">="
187
- - !ruby/object:Gem::Version
188
- version: 0.76.0
189
- type: :development
190
- prerelease: false
191
- version_requirements: !ruby/object:Gem::Requirement
192
- requirements:
193
- - - ">="
194
- - !ruby/object:Gem::Version
195
- version: 0.76.0
196
- - !ruby/object:Gem::Dependency
197
- name: rdoc
198
- requirement: !ruby/object:Gem::Requirement
199
- requirements:
200
- - - ">="
201
- - !ruby/object:Gem::Version
202
- version: '4.0'
203
- - - "<"
204
- - !ruby/object:Gem::Version
205
- version: '7'
206
- type: :development
207
- prerelease: false
208
- version_requirements: !ruby/object:Gem::Requirement
209
- requirements:
210
- - - ">="
211
- - !ruby/object:Gem::Version
212
- version: '4.0'
213
- - - "<"
214
- - !ruby/object:Gem::Version
215
- version: '7'
216
- - !ruby/object:Gem::Dependency
217
- name: hoe
218
134
  requirement: !ruby/object:Gem::Requirement
219
135
  requirements:
220
136
  - - "~>"
221
137
  - !ruby/object:Gem::Version
222
- version: '3.22'
138
+ version: '1.1'
223
139
  type: :development
224
140
  prerelease: false
225
141
  version_requirements: !ruby/object:Gem::Requirement
226
142
  requirements:
227
143
  - - "~>"
228
144
  - !ruby/object:Gem::Version
229
- version: '3.22'
145
+ version: '1.1'
230
146
  description: |-
231
147
  Loofah is a general library for manipulating and transforming HTML/XML documents and fragments, built on top of Nokogiri.
232
148
 
@@ -238,24 +154,12 @@ email:
238
154
  - bryan@brynary.com
239
155
  executables: []
240
156
  extensions: []
241
- extra_rdoc_files:
242
- - CHANGELOG.md
243
- - MIT-LICENSE.txt
244
- - Manifest.txt
245
- - README.md
246
- - SECURITY.md
157
+ extra_rdoc_files: []
247
158
  files:
248
159
  - CHANGELOG.md
249
- - Gemfile
250
160
  - MIT-LICENSE.txt
251
- - Manifest.txt
252
161
  - README.md
253
- - Rakefile
254
162
  - SECURITY.md
255
- - benchmark/benchmark.rb
256
- - benchmark/fragment.html
257
- - benchmark/helper.rb
258
- - benchmark/www.slashdot.com.html
259
163
  - lib/loofah.rb
260
164
  - lib/loofah/elements.rb
261
165
  - lib/loofah/helpers.rb
@@ -268,6 +172,7 @@ files:
268
172
  - lib/loofah/metahelpers.rb
269
173
  - lib/loofah/scrubber.rb
270
174
  - lib/loofah/scrubbers.rb
175
+ - lib/loofah/version.rb
271
176
  - lib/loofah/xml/document.rb
272
177
  - lib/loofah/xml/document_fragment.rb
273
178
  homepage: https://github.com/flavorjones/loofah
@@ -275,14 +180,12 @@ licenses:
275
180
  - MIT
276
181
  metadata:
277
182
  homepage_uri: https://github.com/flavorjones/loofah
183
+ source_code_uri: https://github.com/flavorjones/loofah
278
184
  bug_tracker_uri: https://github.com/flavorjones/loofah/issues
185
+ changelog_uri: https://github.com/flavorjones/loofah/blob/main/CHANGELOG.md
279
186
  documentation_uri: https://www.rubydoc.info/gems/loofah/
280
- changelog_uri: https://github.com/flavorjones/loofah/blob/master/CHANGELOG.md
281
- source_code_uri: https://github.com/flavorjones/loofah
282
187
  post_install_message:
283
- rdoc_options:
284
- - "--main"
285
- - README.md
188
+ rdoc_options: []
286
189
  require_paths:
287
190
  - lib
288
191
  required_ruby_version: !ruby/object:Gem::Requirement
@@ -296,7 +199,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
296
199
  - !ruby/object:Gem::Version
297
200
  version: '0'
298
201
  requirements: []
299
- rubygems_version: 3.1.2
202
+ rubygems_version: 3.3.7
300
203
  signing_key:
301
204
  specification_version: 4
302
205
  summary: Loofah is a general library for manipulating and transforming HTML/XML documents