loofah 2.23.1 → 2.25.2
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 +4 -4
- data/CHANGELOG.md +43 -0
- data/README.md +9 -6
- data/SECURITY.md +1 -1
- data/lib/loofah/html5/safelist.rb +6 -2
- data/lib/loofah/html5/scrub.rb +104 -16
- data/lib/loofah/scrubbers.rb +55 -1
- data/lib/loofah/version.rb +1 -1
- metadata +4 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4a721138b6b152897d72edddfb80cdb0f35200c39a8f37a2024b503e6cfacc95
|
|
4
|
+
data.tar.gz: b342436a5a4e544b504d3e4234935ecd09dd87eddb55be893a1105cfd6a627f6
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e8ffd17d4b47d19bbff8070fcfe0d111530e7f146abc3501deaed1eb3198481f5ae16ee597e2a0d033eeea8bda27a038d1832c7237e24067a36e724e037e06a9
|
|
7
|
+
data.tar.gz: 71f741d1fbcf65fc137b25906c183cf767c091b203210e06d59dbb8e209c12274c77415b03406b021eb16dd149e2f9822f70124cec0947494f955d3fd1e458ee
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,48 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 2.25.2 / 2026-07-15
|
|
4
|
+
|
|
5
|
+
### Security
|
|
6
|
+
|
|
7
|
+
* Ensure `Loofah::HTML5::Scrub.allowed_uri?` recognizes numeric character references without semicolons (e.g. `javascript:alert(1)`), which browsers decode and execute, and rejects schemes split by them. See [GHSA-5qhf-9phg-95m2](https://github.com/flavorjones/loofah/security/advisories/GHSA-5qhf-9phg-95m2). @flavorjones
|
|
8
|
+
* Ensure `Loofah::HTML5::Scrub.allowed_uri?` recognizes the named character references `	` and `
`, which `CGI.unescapeHTML` does not decode and browsers strip from URIs, and rejects schemes split by them (e.g. `java	script:alert(1)`). See [GHSA-8whx-365g-h9vv](https://github.com/flavorjones/loofah/security/advisories/GHSA-8whx-365g-h9vv). @flavorjones
|
|
9
|
+
* Ensure that both `href` and `xlink:href` attributes on SVG elements like `use` are restricted to local (same-document) references. Previously only `xlink:href` was restricted, allowing the SVG 2 `href` attribute to reference external documents. See [GHSA-9wjq-cp2p-hrgf](https://github.com/flavorjones/loofah/security/advisories/GHSA-9wjq-cp2p-hrgf). @flavorjones
|
|
10
|
+
|
|
11
|
+
### Improved
|
|
12
|
+
|
|
13
|
+
* Harden `data:` URI mediatype parsing in `Loofah::HTML5::Scrub.allowed_uri?`. The mediatype is now parsed following the [WHATWG data: URL spec](https://fetch.spec.whatwg.org/#data-urls) and [RFC 2397](https://www.rfc-editor.org/rfc/rfc2397) instead of simply being split on a colon. A `data:` URI with an omitted or malformed mediatype is now treated as `text/plain` and allowed, and one without the required comma is now rejected. #305 @flavorjones
|
|
14
|
+
* Remove `feed` from the default set of allowed protocols. The [feed URI scheme](https://en.wikipedia.org/wiki/Feed_URI_scheme) was never accepted as a standard protocol, and no major browser supports it. Removing it reduces the attack surface particularly for non-browser contexts. #304 @flavorjones
|
|
15
|
+
* Remove a vestigial `p` alternative from `Loofah::HTML5::SafeList::PROTOCOL_SEPARATOR`. This appears to be an ancient typo dating back to pre-extraction Rails circa 2007. #305 @flavorjones
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
## 2.25.1 / 2026-03-17
|
|
19
|
+
|
|
20
|
+
* Ensure `Loofah::HTML5::Scrub.allowed_uri?` recognizes unescaped whitespace entities and rejects schemas containing them. See [GHSA-46fp-8f5p-pf2m](https://github.com/flavorjones/loofah/security/advisories/GHSA-46fp-8f5p-pf2m). #302 @flavorjones
|
|
21
|
+
|
|
22
|
+
## 2.25.0 / 2025-12-15
|
|
23
|
+
|
|
24
|
+
* Extract `Loofah::HTML5::Scrub.allowed_uri?` which operates on a string. Previously this logic was coupled to the parsed tree in `.scrub_uri_attribute`. #300 @flavorjones
|
|
25
|
+
* Tightened up how entities and control characters are handled when detecting allowed URIs. #301 @flavorjones
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
## 2.24.1 / 2025-05-12
|
|
29
|
+
|
|
30
|
+
### Ruby support
|
|
31
|
+
|
|
32
|
+
* Import only what's needed from `cgi` for support for Ruby 3.5 #296 @Earlopain
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
## 2.24.0 / 2024-12-24
|
|
36
|
+
|
|
37
|
+
### Added
|
|
38
|
+
|
|
39
|
+
* Built-in scrubber `:double_breakpoint` which sees `<br><br>` and wraps the surrounding content in `<p>` tags. #279, #284 @josecolella @torihuang
|
|
40
|
+
|
|
41
|
+
### Improved
|
|
42
|
+
|
|
43
|
+
* Built-in scrubber `:targetblank` now skips `a` tags whose `href` attribute is an anchor link. Previously, all `a` tags were modified to have `target='_blank'`. #291 @fnando
|
|
44
|
+
|
|
45
|
+
|
|
3
46
|
## 2.23.1 / 2024-10-25
|
|
4
47
|
|
|
5
48
|
### Added
|
data/README.md
CHANGED
|
@@ -31,6 +31,8 @@ Active Record extensions for HTML sanitization are available in the [`loofah-act
|
|
|
31
31
|
* Add the _nofollow_ attribute to all hyperlinks.
|
|
32
32
|
* Add the _target=\_blank_ attribute to all hyperlinks.
|
|
33
33
|
* Remove _unprintable_ characters from text nodes.
|
|
34
|
+
* Some specialized HTML transformations are also built-in:
|
|
35
|
+
* Where `<br><br>` exists inside a `p` tag, close the `p` and open a new one.
|
|
34
36
|
* Format markup as plain text, with (or without) sensible whitespace handling around block elements.
|
|
35
37
|
* Replace Rails's `strip_tags` and `sanitize` view helper methods.
|
|
36
38
|
|
|
@@ -227,14 +229,15 @@ doc.scrub!(:whitewash) # removes unknown/unsafe/namespaced tags and their chi
|
|
|
227
229
|
# and strips all node attributes
|
|
228
230
|
```
|
|
229
231
|
|
|
230
|
-
Loofah also comes with some common transformation tasks:
|
|
232
|
+
Loofah also comes with built-in scrubers for some common transformation tasks:
|
|
231
233
|
|
|
232
234
|
``` ruby
|
|
233
|
-
doc.scrub!(:nofollow)
|
|
234
|
-
doc.scrub!(:noopener)
|
|
235
|
-
doc.scrub!(:noreferrer)
|
|
236
|
-
doc.scrub!(:unprintable)
|
|
237
|
-
doc.scrub!(:targetblank)
|
|
235
|
+
doc.scrub!(:nofollow) # adds rel="nofollow" attribute to links
|
|
236
|
+
doc.scrub!(:noopener) # adds rel="noopener" attribute to links
|
|
237
|
+
doc.scrub!(:noreferrer) # adds rel="noreferrer" attribute to links
|
|
238
|
+
doc.scrub!(:unprintable) # removes unprintable characters from text nodes
|
|
239
|
+
doc.scrub!(:targetblank) # adds target="_blank" attribute to links
|
|
240
|
+
doc.scrub!(:double_breakpoint) # where `<br><br>` appears in a `p` tag, close the `p` and open a new one
|
|
238
241
|
```
|
|
239
242
|
|
|
240
243
|
See `Loofah::Scrubbers` for more details and example usage.
|
data/SECURITY.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
The Loofah core contributors take security very seriously and investigate all reported vulnerabilities.
|
|
4
4
|
|
|
5
|
-
If you would like to report a vulnerablity or have a security concern regarding Loofah, please [report it via
|
|
5
|
+
If you would like to report a vulnerablity or have a security concern regarding Loofah, please [report it via Github](https://github.com/flavorjones/loofah/security).
|
|
6
6
|
|
|
7
7
|
Your report will be acknowledged within 24 hours, and you'll receive a more detailed response within 72 hours indicating next steps in handling your report.
|
|
8
8
|
|
|
@@ -605,6 +605,11 @@ module Loofah
|
|
|
605
605
|
"stroke",
|
|
606
606
|
])
|
|
607
607
|
|
|
608
|
+
SVG_HREF_ATTRIBUTES = Set.new([
|
|
609
|
+
"xlink:href",
|
|
610
|
+
"href",
|
|
611
|
+
])
|
|
612
|
+
|
|
608
613
|
SVG_ALLOW_LOCAL_HREF = Set.new([
|
|
609
614
|
"altGlyph",
|
|
610
615
|
"animate",
|
|
@@ -978,7 +983,7 @@ module Loofah
|
|
|
978
983
|
"stroke-opacity",
|
|
979
984
|
])
|
|
980
985
|
|
|
981
|
-
PROTOCOL_SEPARATOR = /:|(�*58)|(&#
|
|
986
|
+
PROTOCOL_SEPARATOR = /:|(�*58)|(�*3a)|(%|%)3A/i
|
|
982
987
|
|
|
983
988
|
ACCEPTABLE_PROTOCOLS = Set.new([
|
|
984
989
|
"afs",
|
|
@@ -987,7 +992,6 @@ module Loofah
|
|
|
987
992
|
"data",
|
|
988
993
|
"ed2k",
|
|
989
994
|
"fax",
|
|
990
|
-
"feed",
|
|
991
995
|
"ftp",
|
|
992
996
|
"gopher",
|
|
993
997
|
"http",
|
data/lib/loofah/html5/scrub.rb
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "cgi"
|
|
3
|
+
require "cgi/escape"
|
|
4
|
+
require "cgi/util" if RUBY_VERSION < "3.5"
|
|
4
5
|
require "crass"
|
|
5
6
|
|
|
6
7
|
module Loofah
|
|
@@ -14,6 +15,43 @@ module Loofah
|
|
|
14
15
|
CSS_PROPERTY_STRING_WITHOUT_EMBEDDED_QUOTES = /\A(["'])?[^"']+\1\z/
|
|
15
16
|
DATA_ATTRIBUTE_NAME = /\Adata-[\w-]+\z/
|
|
16
17
|
|
|
18
|
+
# Decimal (`:`) or hexadecimal (`:`) form, with or without the trailing semicolon that
|
|
19
|
+
# CGI.unescapeHTML requires but browsers do not.
|
|
20
|
+
NUMERIC_CHARACTER_REFERENCE = /&#(x[0-9a-f]+|[0-9]+);?/i
|
|
21
|
+
|
|
22
|
+
# A scheme (RFC 3986) followed by a protocol separator. The separator must recognize the same
|
|
23
|
+
# encoded-colon forms as PROTOCOL_SEPARATOR, otherwise a scheme split by an encoded colon (for
|
|
24
|
+
# example "javascript:alert(1)") would not be recognized as having a scheme and would skip
|
|
25
|
+
# protocol validation.
|
|
26
|
+
URI_PROTOCOL_REGEX = /\A[a-z][a-z0-9+\-.]*#{SafeList::PROTOCOL_SEPARATOR}/
|
|
27
|
+
|
|
28
|
+
# Matches a valid MIME type "essence" (type "/" subtype, no parameters), used to
|
|
29
|
+
# decide whether a data: URI mediatype is well-formed; a non-match is not a valid
|
|
30
|
+
# MIME type, which the data: URL processor treats as text/plain. Specs:
|
|
31
|
+
#
|
|
32
|
+
# https://mimesniff.spec.whatwg.org/#valid-mime-type
|
|
33
|
+
# https://mimesniff.spec.whatwg.org/#mime-type-essence
|
|
34
|
+
# https://mimesniff.spec.whatwg.org/#http-token-code-point
|
|
35
|
+
#
|
|
36
|
+
# The character class below is the HTTP token set (tchar) from RFC 9110 section
|
|
37
|
+
# 5.6.2, https://www.rfc-editor.org/rfc/rfc9110#name-tokens :
|
|
38
|
+
#
|
|
39
|
+
# tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "." / "^"
|
|
40
|
+
# / "_" / "`" / "|" / "~" / DIGIT / ALPHA
|
|
41
|
+
#
|
|
42
|
+
# ALPHA is written a-z, not a-zA-Z, because allowed_uri? downcases the input first.
|
|
43
|
+
DATA_URI_MEDIATYPE = %r{
|
|
44
|
+
\A
|
|
45
|
+
[a-z0-9!\#$%&'*+\-.^_`|~]+ # type: 1*tchar
|
|
46
|
+
/ # "/" is not a tchar, so it is the sole delimiter
|
|
47
|
+
[a-z0-9!\#$%&'*+\-.^_`|~]+ # subtype: 1*tchar
|
|
48
|
+
\z
|
|
49
|
+
}x
|
|
50
|
+
|
|
51
|
+
# HTML5 named character references for whitespace that browsers strip from
|
|
52
|
+
# URIs. CGI.unescapeHTML does not decode these, so they are handled explicitly.
|
|
53
|
+
WHITESPACE_CHARACTER_REFERENCES = /&(Tab|NewLine);/
|
|
54
|
+
|
|
17
55
|
class << self
|
|
18
56
|
def allowed_element?(element_name)
|
|
19
57
|
::Loofah::HTML5::SafeList::ALLOWED_ELEMENTS_WITH_LIBXML2.include?(element_name)
|
|
@@ -46,7 +84,7 @@ module Loofah
|
|
|
46
84
|
end
|
|
47
85
|
|
|
48
86
|
next unless SafeList::SVG_ALLOW_LOCAL_HREF.include?(node.name) &&
|
|
49
|
-
attr_name
|
|
87
|
+
SafeList::SVG_HREF_ATTRIBUTES.include?(attr_name) &&
|
|
50
88
|
attr_node.value =~ /^\s*[^#\s].*/m
|
|
51
89
|
|
|
52
90
|
attr_node.remove
|
|
@@ -139,23 +177,59 @@ module Loofah
|
|
|
139
177
|
attr_node.value = values.join(" ")
|
|
140
178
|
end
|
|
141
179
|
|
|
180
|
+
# Returns true if the given URI string is safe, false otherwise. This method can be used to
|
|
181
|
+
# validate URI attribute values without requiring a Nokogiri DOM node.
|
|
182
|
+
def allowed_uri?(uri_string)
|
|
183
|
+
# CGI.unescapeHTML decodes numeric references only when they carry a trailing semicolon, so
|
|
184
|
+
# also decode the semicolon-less ones, which browsers still decode and execute. Normalizing
|
|
185
|
+
# more aggressively than a browser only rejects more, which is safe. Control characters are
|
|
186
|
+
# stripped both before and after decoding, since decoding can produce them. That strip must
|
|
187
|
+
# precede WHITESPACE_CHARACTER_REFERENCES: removing a control character can reveal a named
|
|
188
|
+
# whitespace reference.
|
|
189
|
+
uri_string = decode_numeric_character_references(CGI.unescapeHTML(uri_string.gsub(CONTROL_CHARACTERS, "")))
|
|
190
|
+
uri_string.gsub!(CONTROL_CHARACTERS, "")
|
|
191
|
+
uri_string.gsub!(WHITESPACE_CHARACTER_REFERENCES, "")
|
|
192
|
+
uri_string.gsub!(":", ":")
|
|
193
|
+
uri_string.downcase!
|
|
194
|
+
if URI_PROTOCOL_REGEX.match?(uri_string)
|
|
195
|
+
protocol = uri_string.split(SafeList::PROTOCOL_SEPARATOR)[0]
|
|
196
|
+
return false unless SafeList::ALLOWED_PROTOCOLS.include?(protocol)
|
|
197
|
+
|
|
198
|
+
if protocol == "data"
|
|
199
|
+
# permit only allowed data mediatypes
|
|
200
|
+
return false unless SafeList::ALLOWED_URI_DATA_MEDIATYPES.include?(data_uri_mediatype(uri_string))
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
true
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
def decode_numeric_character_references(string)
|
|
207
|
+
string.gsub(NUMERIC_CHARACTER_REFERENCE) do |reference|
|
|
208
|
+
digits = ::Regexp.last_match(1)
|
|
209
|
+
hexadecimal = digits.start_with?("x", "X")
|
|
210
|
+
digits = digits[1..-1] if hexadecimal
|
|
211
|
+
significant_digits = digits.sub(/\A0+/, "")
|
|
212
|
+
|
|
213
|
+
# The largest code point is U+10FFFF: 7 decimal or 6 hexadecimal significant digits.
|
|
214
|
+
# Anything longer is out of range; skip it without building a large integer from it.
|
|
215
|
+
next reference if significant_digits.length > (hexadecimal ? 6 : 7)
|
|
216
|
+
|
|
217
|
+
codepoint = significant_digits.to_i(hexadecimal ? 16 : 10)
|
|
218
|
+
begin
|
|
219
|
+
codepoint.chr(Encoding::UTF_8)
|
|
220
|
+
rescue RangeError
|
|
221
|
+
reference
|
|
222
|
+
end
|
|
223
|
+
end
|
|
224
|
+
end
|
|
225
|
+
|
|
142
226
|
def scrub_uri_attribute(attr_node)
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
!SafeList::ALLOWED_PROTOCOLS.include?(val_unescaped.split(SafeList::PROTOCOL_SEPARATOR)[0])
|
|
227
|
+
if allowed_uri?(attr_node.value)
|
|
228
|
+
false
|
|
229
|
+
else
|
|
147
230
|
attr_node.remove
|
|
148
|
-
|
|
149
|
-
elsif val_unescaped.split(SafeList::PROTOCOL_SEPARATOR)[0] == "data"
|
|
150
|
-
# permit only allowed data mediatypes
|
|
151
|
-
mediatype = val_unescaped.split(SafeList::PROTOCOL_SEPARATOR)[1]
|
|
152
|
-
mediatype, _ = mediatype.split(";")[0..1] if mediatype
|
|
153
|
-
if mediatype && !SafeList::ALLOWED_URI_DATA_MEDIATYPES.include?(mediatype)
|
|
154
|
-
attr_node.remove
|
|
155
|
-
return true
|
|
156
|
-
end
|
|
231
|
+
true
|
|
157
232
|
end
|
|
158
|
-
false
|
|
159
233
|
end
|
|
160
234
|
|
|
161
235
|
#
|
|
@@ -223,6 +297,20 @@ module Loofah
|
|
|
223
297
|
string
|
|
224
298
|
end
|
|
225
299
|
end
|
|
300
|
+
|
|
301
|
+
private
|
|
302
|
+
|
|
303
|
+
# Returns the mediatype of a data: URI per RFC 2397, or nil when the
|
|
304
|
+
# required comma is absent. allowed_uri? entity-decodes, downcases, and
|
|
305
|
+
# strips control characters before calling this. An omitted or malformed
|
|
306
|
+
# mediatype resolves to "text/plain", matching the WHATWG data: URL processor.
|
|
307
|
+
def data_uri_mediatype(uri_string)
|
|
308
|
+
metadata, comma, _data = uri_string.delete_prefix("data:").partition(",")
|
|
309
|
+
return nil if comma.empty?
|
|
310
|
+
|
|
311
|
+
mediatype = metadata.delete_suffix(";base64").split(";", 2).first.to_s.strip
|
|
312
|
+
mediatype.match?(DATA_URI_MEDIATYPE) ? mediatype : "text/plain"
|
|
313
|
+
end
|
|
226
314
|
end
|
|
227
315
|
end
|
|
228
316
|
end
|
data/lib/loofah/scrubbers.rb
CHANGED
|
@@ -251,7 +251,9 @@ module Loofah
|
|
|
251
251
|
def scrub(node)
|
|
252
252
|
return CONTINUE unless (node.type == Nokogiri::XML::Node::ELEMENT_NODE) && (node.name == "a")
|
|
253
253
|
|
|
254
|
-
node
|
|
254
|
+
href = node["href"]
|
|
255
|
+
|
|
256
|
+
node.set_attribute("target", "_blank") if href && href[0] != "#"
|
|
255
257
|
|
|
256
258
|
STOP
|
|
257
259
|
end
|
|
@@ -348,6 +350,57 @@ module Loofah
|
|
|
348
350
|
end
|
|
349
351
|
end
|
|
350
352
|
|
|
353
|
+
#
|
|
354
|
+
# === scrub!(:double_breakpoint)
|
|
355
|
+
#
|
|
356
|
+
# +:double_breakpoint+ replaces double-break tags with closing/opening paragraph tags.
|
|
357
|
+
#
|
|
358
|
+
# markup = "<p>Some text here in a logical paragraph.<br><br>Some more text, apparently a second paragraph.</p>"
|
|
359
|
+
# Loofah.html5_fragment(markup).scrub!(:double_breakpoint)
|
|
360
|
+
# => "<p>Some text here in a logical paragraph.</p><p>Some more text, apparently a second paragraph.</p>"
|
|
361
|
+
#
|
|
362
|
+
class DoubleBreakpoint < Scrubber
|
|
363
|
+
def initialize # rubocop:disable Lint/MissingSuper
|
|
364
|
+
@direction = :top_down
|
|
365
|
+
end
|
|
366
|
+
|
|
367
|
+
def scrub(node)
|
|
368
|
+
return CONTINUE unless (node.type == Nokogiri::XML::Node::ELEMENT_NODE) && (node.name == "p")
|
|
369
|
+
|
|
370
|
+
paragraph_with_break_point_nodes = node.xpath("//p[br[following-sibling::br]]")
|
|
371
|
+
|
|
372
|
+
paragraph_with_break_point_nodes.each do |paragraph_node|
|
|
373
|
+
new_paragraph = paragraph_node.add_previous_sibling("<p>").first
|
|
374
|
+
|
|
375
|
+
paragraph_node.children.each do |child|
|
|
376
|
+
remove_blank_text_nodes(child)
|
|
377
|
+
end
|
|
378
|
+
|
|
379
|
+
paragraph_node.children.each do |child|
|
|
380
|
+
# already unlinked
|
|
381
|
+
next if child.parent.nil?
|
|
382
|
+
|
|
383
|
+
if child.name == "br" && child.next_sibling.name == "br"
|
|
384
|
+
new_paragraph = paragraph_node.add_previous_sibling("<p>").first
|
|
385
|
+
child.next_sibling.unlink
|
|
386
|
+
child.unlink
|
|
387
|
+
else
|
|
388
|
+
child.parent = new_paragraph
|
|
389
|
+
end
|
|
390
|
+
end
|
|
391
|
+
|
|
392
|
+
paragraph_node.unlink
|
|
393
|
+
end
|
|
394
|
+
|
|
395
|
+
CONTINUE
|
|
396
|
+
end
|
|
397
|
+
|
|
398
|
+
private
|
|
399
|
+
|
|
400
|
+
def remove_blank_text_nodes(node)
|
|
401
|
+
node.unlink if node.text? && node.blank?
|
|
402
|
+
end
|
|
403
|
+
end
|
|
351
404
|
#
|
|
352
405
|
# A hash that maps a symbol (like +:prune+) to the appropriate Scrubber (Loofah::Scrubbers::Prune).
|
|
353
406
|
#
|
|
@@ -362,6 +415,7 @@ module Loofah
|
|
|
362
415
|
targetblank: TargetBlank,
|
|
363
416
|
newline_block_elements: NewlineBlockElements,
|
|
364
417
|
unprintable: Unprintable,
|
|
418
|
+
double_breakpoint: DoubleBreakpoint,
|
|
365
419
|
}
|
|
366
420
|
|
|
367
421
|
class << self
|
data/lib/loofah/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: loofah
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.25.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Mike Dalessio
|
|
8
8
|
- Bryan Helmkamp
|
|
9
|
-
autorequire:
|
|
10
9
|
bindir: bin
|
|
11
10
|
cert_chain: []
|
|
12
|
-
date:
|
|
11
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
13
12
|
dependencies:
|
|
14
13
|
- !ruby/object:Gem::Dependency
|
|
15
14
|
name: crass
|
|
@@ -82,7 +81,7 @@ metadata:
|
|
|
82
81
|
bug_tracker_uri: https://github.com/flavorjones/loofah/issues
|
|
83
82
|
changelog_uri: https://github.com/flavorjones/loofah/blob/main/CHANGELOG.md
|
|
84
83
|
documentation_uri: https://www.rubydoc.info/gems/loofah/
|
|
85
|
-
|
|
84
|
+
funding_uri: https://github.com/sponsors/flavorjones
|
|
86
85
|
rdoc_options: []
|
|
87
86
|
require_paths:
|
|
88
87
|
- lib
|
|
@@ -97,8 +96,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
97
96
|
- !ruby/object:Gem::Version
|
|
98
97
|
version: '0'
|
|
99
98
|
requirements: []
|
|
100
|
-
rubygems_version:
|
|
101
|
-
signing_key:
|
|
99
|
+
rubygems_version: 4.0.10
|
|
102
100
|
specification_version: 4
|
|
103
101
|
summary: Loofah is a general library for manipulating and transforming HTML/XML documents
|
|
104
102
|
and fragments, built on top of Nokogiri.
|