loofah 0.4.2 → 2.25.0
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 +7 -0
- data/CHANGELOG.md +604 -0
- data/MIT-LICENSE.txt +3 -1
- data/README.md +410 -0
- data/SECURITY.md +18 -0
- data/lib/loofah/concerns.rb +207 -0
- data/lib/loofah/elements.rb +98 -0
- data/lib/loofah/helpers.rb +91 -4
- data/lib/loofah/html4/document.rb +17 -0
- data/lib/loofah/html4/document_fragment.rb +15 -0
- data/lib/loofah/html5/document.rb +17 -0
- data/lib/loofah/html5/document_fragment.rb +15 -0
- data/lib/loofah/html5/libxml2_workarounds.rb +28 -0
- data/lib/loofah/html5/safelist.rb +1058 -0
- data/lib/loofah/html5/scrub.rb +211 -40
- data/lib/loofah/metahelpers.rb +18 -0
- data/lib/loofah/scrubber.rb +31 -13
- data/lib/loofah/scrubbers.rb +262 -31
- data/lib/loofah/version.rb +6 -0
- data/lib/loofah/xml/document.rb +2 -0
- data/lib/loofah/xml/document_fragment.rb +6 -9
- data/lib/loofah.rb +131 -52
- metadata +79 -158
- data/CHANGELOG.rdoc +0 -92
- data/DEPRECATED.rdoc +0 -12
- data/Manifest.txt +0 -34
- data/README.rdoc +0 -330
- data/Rakefile +0 -61
- data/TODO.rdoc +0 -4
- data/benchmark/benchmark.rb +0 -149
- data/benchmark/fragment.html +0 -96
- data/benchmark/helper.rb +0 -73
- data/benchmark/www.slashdot.com.html +0 -2560
- data/init.rb +0 -1
- data/lib/loofah/active_record.rb +0 -62
- data/lib/loofah/html/document.rb +0 -22
- data/lib/loofah/html/document_fragment.rb +0 -46
- data/lib/loofah/html5/whitelist.rb +0 -174
- data/lib/loofah/instance_methods.rb +0 -77
- data/lib/loofah/xss_foliate.rb +0 -212
- data/test/helper.rb +0 -8
- data/test/html5/test_sanitizer.rb +0 -248
- data/test/test_active_record.rb +0 -146
- data/test/test_ad_hoc.rb +0 -272
- data/test/test_api.rb +0 -128
- data/test/test_helpers.rb +0 -28
- data/test/test_scrubber.rb +0 -227
- data/test/test_scrubbers.rb +0 -144
- data/test/test_xss_foliate.rb +0 -171
- data.tar.gz.sig +0 -0
- metadata.gz.sig +0 -2
data/init.rb
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
require "loofah"
|
data/lib/loofah/active_record.rb
DELETED
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
module Loofah
|
|
2
|
-
#
|
|
3
|
-
# Loofah can scrub ActiveRecord attributes in a before_validation callback:
|
|
4
|
-
#
|
|
5
|
-
# # in environment.rb
|
|
6
|
-
# Rails::Initializer.run do |config|
|
|
7
|
-
# config.gem 'loofah'
|
|
8
|
-
# end
|
|
9
|
-
#
|
|
10
|
-
# # db/schema.rb
|
|
11
|
-
# create_table "posts" do |t|
|
|
12
|
-
# t.string "title"
|
|
13
|
-
# t.string "body"
|
|
14
|
-
# end
|
|
15
|
-
#
|
|
16
|
-
# # app/model/post.rb
|
|
17
|
-
# class Post < ActiveRecord::Base
|
|
18
|
-
# html_fragment :body, :scrub => :prune # scrubs 'body' in a before_validation
|
|
19
|
-
# end
|
|
20
|
-
#
|
|
21
|
-
module ActiveRecordExtension
|
|
22
|
-
#
|
|
23
|
-
# :call-seq:
|
|
24
|
-
# html_fragment(attribute, :scrub => scrubber_specification)
|
|
25
|
-
#
|
|
26
|
-
# Scrub an ActiveRecord attribute +attribute+ as an HTML *fragment*
|
|
27
|
-
# using the method specified by +scrubber_specification+.
|
|
28
|
-
#
|
|
29
|
-
# +scrubber_specification+ must be an argument acceptable to Loofah::ScrubBehavior.scrub!, namely:
|
|
30
|
-
#
|
|
31
|
-
# * a symbol for one of the built-in scrubbers (see Loofah::Scrubbers for a full list)
|
|
32
|
-
# * or a Scrubber instance. (see Loofah::Scrubber for help on implementing a custom scrubber)
|
|
33
|
-
#
|
|
34
|
-
def html_fragment(attr, options={})
|
|
35
|
-
raise ArgumentError, "html_fragment requires :scrub option" unless method = options[:scrub]
|
|
36
|
-
before_validation do |record|
|
|
37
|
-
record[attr] = Loofah.scrub_fragment(record[attr], method).to_s
|
|
38
|
-
end
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
#
|
|
42
|
-
# :call-seq:
|
|
43
|
-
# model.html_document(attribute, :scrub => scrubber_specification)
|
|
44
|
-
#
|
|
45
|
-
# Scrub an ActiveRecord attribute +attribute+ as an HTML *document*
|
|
46
|
-
# using the method specified by +scrubber_specification+.
|
|
47
|
-
#
|
|
48
|
-
# +scrubber_specification+ must be an argument acceptable to Loofah::ScrubBehavior.scrub!, namely:
|
|
49
|
-
#
|
|
50
|
-
# * a symbol for one of the built-in scrubbers (see Loofah::Scrubbers for a full list)
|
|
51
|
-
# * or a Scrubber instance.
|
|
52
|
-
#
|
|
53
|
-
def html_document(attr, options={})
|
|
54
|
-
raise ArgumentError, "html_document requires :scrub option" unless method = options[:scrub]
|
|
55
|
-
before_validation do |record|
|
|
56
|
-
record[attr] = Loofah.scrub_document(record[attr], method).to_s
|
|
57
|
-
end
|
|
58
|
-
end
|
|
59
|
-
end
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
ActiveRecord::Base.extend(Loofah::ActiveRecordExtension)
|
data/lib/loofah/html/document.rb
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
module Loofah
|
|
2
|
-
module HTML # :nodoc:
|
|
3
|
-
#
|
|
4
|
-
# Subclass of Nokogiri::HTML::Document.
|
|
5
|
-
#
|
|
6
|
-
# See Loofah::ScrubBehavior and Loofah::DocumentDecorator for additional methods.
|
|
7
|
-
#
|
|
8
|
-
class Document < Nokogiri::HTML::Document
|
|
9
|
-
include Loofah::ScrubBehavior::Node
|
|
10
|
-
include Loofah::DocumentDecorator
|
|
11
|
-
|
|
12
|
-
#
|
|
13
|
-
# Returns a plain-text version of the markup contained by the document
|
|
14
|
-
#
|
|
15
|
-
def text
|
|
16
|
-
xpath("/html/body").inner_text
|
|
17
|
-
end
|
|
18
|
-
alias :inner_text :text
|
|
19
|
-
alias :to_str :text
|
|
20
|
-
end
|
|
21
|
-
end
|
|
22
|
-
end
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
module Loofah
|
|
2
|
-
module HTML # :nodoc:
|
|
3
|
-
#
|
|
4
|
-
# Subclass of Nokogiri::HTML::DocumentFragment.
|
|
5
|
-
#
|
|
6
|
-
# See Loofah::ScrubBehavior for additional methods.
|
|
7
|
-
#
|
|
8
|
-
class DocumentFragment < Nokogiri::HTML::DocumentFragment
|
|
9
|
-
include Loofah::ScrubBehavior::Node
|
|
10
|
-
|
|
11
|
-
class << self
|
|
12
|
-
#
|
|
13
|
-
# Overridden Nokogiri::HTML::DocumentFragment
|
|
14
|
-
# constructor. Applications should use Loofah.fragment to
|
|
15
|
-
# parse a fragment.
|
|
16
|
-
#
|
|
17
|
-
def parse tags
|
|
18
|
-
self.new(Loofah::HTML::Document.new, tags)
|
|
19
|
-
end
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
#
|
|
23
|
-
# Returns the HTML markup contained by the fragment
|
|
24
|
-
#
|
|
25
|
-
def to_s
|
|
26
|
-
serialize_roots.children.to_s
|
|
27
|
-
end
|
|
28
|
-
alias :serialize :to_s
|
|
29
|
-
|
|
30
|
-
#
|
|
31
|
-
# Returns a plain-text version of the markup contained by the fragment
|
|
32
|
-
#
|
|
33
|
-
def text
|
|
34
|
-
serialize_roots.children.inner_text
|
|
35
|
-
end
|
|
36
|
-
alias :inner_text :text
|
|
37
|
-
alias :to_str :text
|
|
38
|
-
|
|
39
|
-
private
|
|
40
|
-
|
|
41
|
-
def serialize_roots # :nodoc:
|
|
42
|
-
xpath("./body").first || self
|
|
43
|
-
end
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
end
|
|
@@ -1,174 +0,0 @@
|
|
|
1
|
-
module Loofah
|
|
2
|
-
module HTML5 # :nodoc:
|
|
3
|
-
#
|
|
4
|
-
# HTML whitelist lifted from HTML5lib sanitizer code:
|
|
5
|
-
#
|
|
6
|
-
# http://code.google.com/p/html5lib/
|
|
7
|
-
#
|
|
8
|
-
# <html5_license>
|
|
9
|
-
#
|
|
10
|
-
# Copyright (c) 2006-2008 The Authors
|
|
11
|
-
#
|
|
12
|
-
# Contributors:
|
|
13
|
-
# James Graham - jg307@cam.ac.uk
|
|
14
|
-
# Anne van Kesteren - annevankesteren@gmail.com
|
|
15
|
-
# Lachlan Hunt - lachlan.hunt@lachy.id.au
|
|
16
|
-
# Matt McDonald - kanashii@kanashii.ca
|
|
17
|
-
# Sam Ruby - rubys@intertwingly.net
|
|
18
|
-
# Ian Hickson (Google) - ian@hixie.ch
|
|
19
|
-
# Thomas Broyer - t.broyer@ltgt.net
|
|
20
|
-
# Jacques Distler - distler@golem.ph.utexas.edu
|
|
21
|
-
# Henri Sivonen - hsivonen@iki.fi
|
|
22
|
-
# The Mozilla Foundation (contributions from Henri Sivonen since 2008)
|
|
23
|
-
#
|
|
24
|
-
# Permission is hereby granted, free of charge, to any person
|
|
25
|
-
# obtaining a copy of this software and associated documentation
|
|
26
|
-
# files (the "Software"), to deal in the Software without
|
|
27
|
-
# restriction, including without limitation the rights to use, copy,
|
|
28
|
-
# modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
29
|
-
# of the Software, and to permit persons to whom the Software is
|
|
30
|
-
# furnished to do so, subject to the following conditions:
|
|
31
|
-
#
|
|
32
|
-
# The above copyright notice and this permission notice shall be
|
|
33
|
-
# included in all copies or substantial portions of the Software.
|
|
34
|
-
#
|
|
35
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
36
|
-
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
37
|
-
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
38
|
-
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
39
|
-
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
40
|
-
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
41
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
42
|
-
# DEALINGS IN THE SOFTWARE.
|
|
43
|
-
#
|
|
44
|
-
# </html5_license>
|
|
45
|
-
module WhiteList
|
|
46
|
-
ACCEPTABLE_ELEMENTS = %w[a abbr acronym address area b big blockquote br
|
|
47
|
-
button caption center cite code col colgroup dd del dfn dir div dl dt
|
|
48
|
-
em fieldset font form h1 h2 h3 h4 h5 h6 hr i img input ins kbd label
|
|
49
|
-
legend li map menu ol optgroup option p pre q s samp select small span
|
|
50
|
-
strike strong sub sup table tbody td textarea tfoot th thead tr tt u
|
|
51
|
-
ul var]
|
|
52
|
-
|
|
53
|
-
MATHML_ELEMENTS = %w[annotation annotation-xml maction math merror mfrac
|
|
54
|
-
mfenced mi mmultiscripts mn mo mover mpadded mphantom mprescripts mroot mrow
|
|
55
|
-
mspace msqrt mstyle msub msubsup msup mtable mtd mtext mtr munder
|
|
56
|
-
munderover none semantics]
|
|
57
|
-
|
|
58
|
-
SVG_ELEMENTS = %w[a animate animateColor animateMotion animateTransform
|
|
59
|
-
circle defs desc ellipse font-face font-face-name font-face-src foreignObject
|
|
60
|
-
g glyph hkern linearGradient line marker metadata missing-glyph
|
|
61
|
-
mpath path polygon polyline radialGradient rect set stop svg switch
|
|
62
|
-
text title tspan use]
|
|
63
|
-
|
|
64
|
-
ACCEPTABLE_ATTRIBUTES = %w[abbr accept accept-charset accesskey action
|
|
65
|
-
align alt axis border cellpadding cellspacing char charoff charset
|
|
66
|
-
checked cite class clear cols colspan color compact coords datetime
|
|
67
|
-
dir disabled enctype for frame headers height href hreflang hspace id
|
|
68
|
-
ismap label lang longdesc maxlength media method multiple name nohref
|
|
69
|
-
noshade nowrap prompt readonly rel rev rows rowspan rules scope
|
|
70
|
-
selected shape size span src start style summary tabindex target title
|
|
71
|
-
type usemap valign value vspace width xml:lang]
|
|
72
|
-
|
|
73
|
-
MATHML_ATTRIBUTES = %w[actiontype align close columnalign columnalign
|
|
74
|
-
columnalign columnlines columnspacing columnspan depth display
|
|
75
|
-
displaystyle encoding equalcolumns equalrows fence fontstyle fontweight
|
|
76
|
-
frame height linethickness lspace mathbackground mathcolor mathvariant
|
|
77
|
-
mathvariant maxsize minsize open other rowalign rowalign rowalign rowlines
|
|
78
|
-
rowspacing rowspan rspace scriptlevel selection separator separators
|
|
79
|
-
stretchy width width xlink:href xlink:show xlink:type xmlns xmlns:xlink]
|
|
80
|
-
|
|
81
|
-
SVG_ATTRIBUTES = %w[accent-height accumulate additive alphabetic
|
|
82
|
-
arabic-form ascent attributeName attributeType baseProfile bbox begin
|
|
83
|
-
by calcMode cap-height class color color-rendering content cx cy d dx
|
|
84
|
-
dy descent display dur end fill fill-opacity fill-rule font-family
|
|
85
|
-
font-size font-stretch font-style font-variant font-weight from fx fy g1
|
|
86
|
-
g2 glyph-name gradientUnits hanging height horiz-adv-x horiz-origin-x id
|
|
87
|
-
ideographic k keyPoints keySplines keyTimes lang marker-end
|
|
88
|
-
marker-mid marker-start markerHeight markerUnits markerWidth
|
|
89
|
-
mathematical max min name offset opacity orient origin
|
|
90
|
-
overline-position overline-thickness panose-1 path pathLength points
|
|
91
|
-
preserveAspectRatio r refX refY repeatCount repeatDur
|
|
92
|
-
requiredExtensions requiredFeatures restart rotate rx ry slope stemh
|
|
93
|
-
stemv stop-color stop-opacity strikethrough-position
|
|
94
|
-
strikethrough-thickness stroke stroke-dasharray stroke-dashoffset
|
|
95
|
-
stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity
|
|
96
|
-
stroke-width systemLanguage target text-anchor to transform type u1
|
|
97
|
-
u2 underline-position underline-thickness unicode unicode-range
|
|
98
|
-
units-per-em values version viewBox visibility width widths x
|
|
99
|
-
x-height x1 x2 xlink:actuate xlink:arcrole xlink:href xlink:role
|
|
100
|
-
xlink:show xlink:title xlink:type xml:base xml:lang xml:space xmlns
|
|
101
|
-
xmlns:xlink y y1 y2 zoomAndPan]
|
|
102
|
-
|
|
103
|
-
ATTR_VAL_IS_URI = %w[href src cite action longdesc xlink:href xml:base]
|
|
104
|
-
|
|
105
|
-
SVG_ATTR_VAL_ALLOWS_REF = %w[clip-path color-profile cursor fill
|
|
106
|
-
filter marker marker-start marker-mid marker-end mask stroke]
|
|
107
|
-
|
|
108
|
-
SVG_ALLOW_LOCAL_HREF = %w[altGlyph animate animateColor animateMotion
|
|
109
|
-
animateTransform cursor feImage filter linearGradient pattern
|
|
110
|
-
radialGradient textpath tref set use]
|
|
111
|
-
|
|
112
|
-
ACCEPTABLE_CSS_PROPERTIES = %w[azimuth background-color
|
|
113
|
-
border-bottom-color border-collapse border-color border-left-color
|
|
114
|
-
border-right-color border-top-color clear color cursor direction
|
|
115
|
-
display elevation float font font-family font-size font-style
|
|
116
|
-
font-variant font-weight height letter-spacing line-height overflow
|
|
117
|
-
pause pause-after pause-before pitch pitch-range richness speak
|
|
118
|
-
speak-header speak-numeral speak-punctuation speech-rate stress
|
|
119
|
-
text-align text-decoration text-indent unicode-bidi vertical-align
|
|
120
|
-
voice-family volume white-space width]
|
|
121
|
-
|
|
122
|
-
ACCEPTABLE_CSS_KEYWORDS = %w[auto aqua black block blue bold both bottom
|
|
123
|
-
brown center collapse dashed dotted fuchsia gray green !important
|
|
124
|
-
italic left lime maroon medium none navy normal nowrap olive pointer
|
|
125
|
-
purple red right solid silver teal top transparent underline white
|
|
126
|
-
yellow]
|
|
127
|
-
|
|
128
|
-
ACCEPTABLE_SVG_PROPERTIES = %w[fill fill-opacity fill-rule stroke
|
|
129
|
-
stroke-width stroke-linecap stroke-linejoin stroke-opacity]
|
|
130
|
-
|
|
131
|
-
ACCEPTABLE_PROTOCOLS = %w[ed2k ftp http https irc mailto news gopher nntp
|
|
132
|
-
telnet webcal xmpp callto feed urn aim rsync tag ssh sftp rtsp afs]
|
|
133
|
-
|
|
134
|
-
# subclasses may define their own versions of these constants
|
|
135
|
-
ALLOWED_ELEMENTS = ACCEPTABLE_ELEMENTS + MATHML_ELEMENTS + SVG_ELEMENTS
|
|
136
|
-
ALLOWED_ATTRIBUTES = ACCEPTABLE_ATTRIBUTES + MATHML_ATTRIBUTES + SVG_ATTRIBUTES
|
|
137
|
-
ALLOWED_CSS_PROPERTIES = ACCEPTABLE_CSS_PROPERTIES
|
|
138
|
-
ALLOWED_CSS_KEYWORDS = ACCEPTABLE_CSS_KEYWORDS
|
|
139
|
-
ALLOWED_SVG_PROPERTIES = ACCEPTABLE_SVG_PROPERTIES
|
|
140
|
-
ALLOWED_PROTOCOLS = ACCEPTABLE_PROTOCOLS
|
|
141
|
-
|
|
142
|
-
VOID_ELEMENTS = %w[
|
|
143
|
-
base
|
|
144
|
-
link
|
|
145
|
-
meta
|
|
146
|
-
hr
|
|
147
|
-
br
|
|
148
|
-
img
|
|
149
|
-
embed
|
|
150
|
-
param
|
|
151
|
-
area
|
|
152
|
-
col
|
|
153
|
-
input
|
|
154
|
-
]
|
|
155
|
-
|
|
156
|
-
# additional tags we should consider safe since we have libxml2 fixing up our documents.
|
|
157
|
-
TAGS_SAFE_WITH_LIBXML2 = %w[html head body]
|
|
158
|
-
ALLOWED_ELEMENTS_WITH_LIBXML2 = ALLOWED_ELEMENTS + TAGS_SAFE_WITH_LIBXML2
|
|
159
|
-
end
|
|
160
|
-
|
|
161
|
-
#
|
|
162
|
-
# The HTML5lib whitelist arrays, transformed into hashes for faster lookup.
|
|
163
|
-
#
|
|
164
|
-
module HashedWhiteList
|
|
165
|
-
WhiteList.constants.each do |constant|
|
|
166
|
-
next unless WhiteList.module_eval("#{constant}").is_a?(Array)
|
|
167
|
-
module_eval <<-CODE
|
|
168
|
-
#{constant} = {}
|
|
169
|
-
WhiteList::#{constant}.each { |c| #{constant}[c] = true ; #{constant}[c.downcase] = true }
|
|
170
|
-
CODE
|
|
171
|
-
end
|
|
172
|
-
end
|
|
173
|
-
end
|
|
174
|
-
end
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
module Loofah
|
|
2
|
-
#
|
|
3
|
-
# Mixes +scrub!+ into Document, DocumentFragment, Node and NodeSet.
|
|
4
|
-
#
|
|
5
|
-
# Traverse the document or fragment, invoking the +scrubber+ on
|
|
6
|
-
# each node.
|
|
7
|
-
#
|
|
8
|
-
# +scrubber+ must either be one of the symbols representing the
|
|
9
|
-
# built-in scrubbers (see Scrubbers), or a Scrubber instance.
|
|
10
|
-
#
|
|
11
|
-
# span2div = Loofah::Scrubber.new do |node|
|
|
12
|
-
# node.name = "div" if node.name == "span"
|
|
13
|
-
# end
|
|
14
|
-
# Loofah.fragment("<span>foo</span><p>bar</p>").scrub!(span2div).to_s
|
|
15
|
-
# # => "<div>foo</div><p>bar</p>"
|
|
16
|
-
#
|
|
17
|
-
# or
|
|
18
|
-
#
|
|
19
|
-
# unsafe_html = "ohai! <div>div is safe</div> <script>but script is not</script>"
|
|
20
|
-
# Loofah.fragment(unsafe_html).scrub!(:strip).to_s
|
|
21
|
-
# # => "ohai! <div>div is safe</div> "
|
|
22
|
-
#
|
|
23
|
-
# Note that this method is called implicitly from
|
|
24
|
-
# Loofah.scrub_fragment and Loofah.scrub_document.
|
|
25
|
-
#
|
|
26
|
-
# Please see Scrubber for more information on implementation and traversal, and
|
|
27
|
-
# README.rdoc for more example usage.
|
|
28
|
-
#
|
|
29
|
-
module ScrubBehavior
|
|
30
|
-
# see Loofah::ScrubBehavior
|
|
31
|
-
module Node
|
|
32
|
-
def scrub!(scrubber)
|
|
33
|
-
#
|
|
34
|
-
# yes. this should be three separate methods. but nokogiri
|
|
35
|
-
# decorates (or not) based on whether the module name has
|
|
36
|
-
# already been included. and since documents get decorated
|
|
37
|
-
# just like their constituent nodes, we need to jam all the
|
|
38
|
-
# logic into a single module.
|
|
39
|
-
#
|
|
40
|
-
scrubber = ScrubBehavior.resolve_scrubber(scrubber)
|
|
41
|
-
case self
|
|
42
|
-
when Nokogiri::XML::Document
|
|
43
|
-
scrubber.traverse(root) if root
|
|
44
|
-
when Nokogiri::XML::DocumentFragment
|
|
45
|
-
children.each { |node| node.scrub!(scrubber) } # TODO: children.scrub! once Nokogiri 1.4.2 is out
|
|
46
|
-
else
|
|
47
|
-
scrubber.traverse(self)
|
|
48
|
-
end
|
|
49
|
-
self
|
|
50
|
-
end
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
# see Loofah::ScrubBehavior
|
|
54
|
-
module NodeSet
|
|
55
|
-
def scrub!(scrubber)
|
|
56
|
-
each { |node| node.scrub!(scrubber) }
|
|
57
|
-
self
|
|
58
|
-
end
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
def ScrubBehavior.resolve_scrubber(scrubber) # :nodoc:
|
|
62
|
-
scrubber = Scrubbers::MAP[scrubber].new if Scrubbers::MAP[scrubber]
|
|
63
|
-
unless scrubber.is_a?(Loofah::Scrubber)
|
|
64
|
-
raise Loofah::ScrubberNotFound, "not a Scrubber or a scrubber name: #{scrubber.inspect}"
|
|
65
|
-
end
|
|
66
|
-
scrubber
|
|
67
|
-
end
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
module DocumentDecorator # :nodoc:
|
|
71
|
-
def initialize(*args, &block)
|
|
72
|
-
super
|
|
73
|
-
self.decorators(Nokogiri::XML::Node) << ScrubBehavior::Node
|
|
74
|
-
self.decorators(Nokogiri::XML::NodeSet) << ScrubBehavior::NodeSet
|
|
75
|
-
end
|
|
76
|
-
end
|
|
77
|
-
end
|
data/lib/loofah/xss_foliate.rb
DELETED
|
@@ -1,212 +0,0 @@
|
|
|
1
|
-
module Loofah
|
|
2
|
-
#
|
|
3
|
-
# A replacement for
|
|
4
|
-
# XssTerminate[http://github.com/look/xss_terminate/tree/master],
|
|
5
|
-
# XssFoliate will strip all tags from your ActiveRecord models'
|
|
6
|
-
# string and text attributes.
|
|
7
|
-
#
|
|
8
|
-
# Please read the Loofah documentation for an explanation of the
|
|
9
|
-
# different scrubbing methods, and
|
|
10
|
-
# Loofah::XssFoliate::ClassMethods for more information on the
|
|
11
|
-
# methods.
|
|
12
|
-
#
|
|
13
|
-
# If you'd like to scrub all fields in all your models (and perhaps *opt-out* in specific models):
|
|
14
|
-
#
|
|
15
|
-
# # config/environment
|
|
16
|
-
# LOOFAH_XSS_FOLIATE_ALL_MODELS = true
|
|
17
|
-
# Rails::Initializer.run do |config|
|
|
18
|
-
# config.gem "loofah"
|
|
19
|
-
# end
|
|
20
|
-
#
|
|
21
|
-
# # db/schema.rb
|
|
22
|
-
# create_table "posts" do |t|
|
|
23
|
-
# t.string "title"
|
|
24
|
-
# t.text "body"
|
|
25
|
-
# t.string "author"
|
|
26
|
-
# end
|
|
27
|
-
#
|
|
28
|
-
# # app/model/post.rb
|
|
29
|
-
# class Post < ActiveRecord::Base
|
|
30
|
-
# # by default, title, body and author will all be scrubbed down to their inner text
|
|
31
|
-
# end
|
|
32
|
-
#
|
|
33
|
-
# OR
|
|
34
|
-
#
|
|
35
|
-
# # app/model/post.rb
|
|
36
|
-
# class Post < ActiveRecord::Base
|
|
37
|
-
# xss_foliate :except => :author # opt-out of sanitizing author
|
|
38
|
-
# end
|
|
39
|
-
#
|
|
40
|
-
# OR
|
|
41
|
-
#
|
|
42
|
-
# xss_foliate :strip => [:title, body] # strip unsafe tags from both title and body
|
|
43
|
-
#
|
|
44
|
-
# OR
|
|
45
|
-
#
|
|
46
|
-
# xss_foliate :except => :title # scrub body and author but not title
|
|
47
|
-
#
|
|
48
|
-
# OR
|
|
49
|
-
#
|
|
50
|
-
# # remove all tags from title, remove unsafe tags from body
|
|
51
|
-
# xss_foliate :sanitize => :title, :scrub => :body
|
|
52
|
-
#
|
|
53
|
-
# OR
|
|
54
|
-
#
|
|
55
|
-
# # old xss_terminate code will work if you s/_terminate/_foliate/
|
|
56
|
-
# # was: xss_terminate :except => [:title], :sanitize => [:body]
|
|
57
|
-
# xss_foliate :except => [:title], :sanitize => [:body]
|
|
58
|
-
#
|
|
59
|
-
# Alternatively, if you would like to *opt-in* to the models and attributes that are sanitized:
|
|
60
|
-
#
|
|
61
|
-
# # config/environment.rb
|
|
62
|
-
# LOOFAH_XSS_FOLIATE_ALL_MODELS = false # default, this line could be omitted
|
|
63
|
-
# Rails::Initializer.run do |config|
|
|
64
|
-
# config.gem "loofah"
|
|
65
|
-
# end
|
|
66
|
-
#
|
|
67
|
-
# # db/schema.rb
|
|
68
|
-
# create_table "posts" do |t|
|
|
69
|
-
# t.string "title"
|
|
70
|
-
# t.text "body"
|
|
71
|
-
# t.string "author"
|
|
72
|
-
# end
|
|
73
|
-
#
|
|
74
|
-
# # app/model/post.rb
|
|
75
|
-
# class Post < ActiveRecord::Base
|
|
76
|
-
# xss_foliate # scrub title, body and author down to their inner text
|
|
77
|
-
# end
|
|
78
|
-
#
|
|
79
|
-
module XssFoliate
|
|
80
|
-
#
|
|
81
|
-
# A replacement for
|
|
82
|
-
# XssTerminate[http://github.com/look/xss_terminate/tree/master],
|
|
83
|
-
# XssFoliate will strip all tags from your ActiveRecord models'
|
|
84
|
-
# string and text attributes.
|
|
85
|
-
#
|
|
86
|
-
# See Loofah::XssFoliate for more example usage.
|
|
87
|
-
#
|
|
88
|
-
module ClassMethods
|
|
89
|
-
# :stopdoc:
|
|
90
|
-
VALID_OPTIONS = [:except, :strip, :escape, :prune, :text, :html5lib_sanitize, :sanitize]
|
|
91
|
-
ALIASED_OPTIONS = {:html5lib_sanitize => :escape, :sanitize => :strip}
|
|
92
|
-
REAL_OPTIONS = VALID_OPTIONS - ALIASED_OPTIONS.keys
|
|
93
|
-
# :startdoc:
|
|
94
|
-
|
|
95
|
-
#
|
|
96
|
-
# Annotate your model with this method to specify which fields
|
|
97
|
-
# you want scrubbed, and how you want them scrubbed. XssFoliate
|
|
98
|
-
# assumes all character fields are HTML fragments (as opposed to
|
|
99
|
-
# full documents, see the Loofah[http://loofah.rubyforge.org/]
|
|
100
|
-
# documentation for a full explanation of the difference).
|
|
101
|
-
#
|
|
102
|
-
# Example call:
|
|
103
|
-
#
|
|
104
|
-
# xss_foliate :except => :author, :strip => :body, :prune => [:title, :description]
|
|
105
|
-
#
|
|
106
|
-
# *Note* that the values in the options hash can be either an
|
|
107
|
-
# array of attributes or a single attribute.
|
|
108
|
-
#
|
|
109
|
-
# Options:
|
|
110
|
-
#
|
|
111
|
-
# :except => [fields] # don't scrub these fields
|
|
112
|
-
# :strip => [fields] # strip unsafe tags from these fields
|
|
113
|
-
# :escape => [fields] # escape unsafe tags from these fields
|
|
114
|
-
# :prune => [fields] # prune unsafe tags and subtrees from these fields
|
|
115
|
-
# :text => [fields] # remove everything except the inner text from these fields
|
|
116
|
-
#
|
|
117
|
-
# XssTerminate compatibility options (note that the default
|
|
118
|
-
# behavior in XssTerminate corresponds to :text)
|
|
119
|
-
#
|
|
120
|
-
# :html5lib_sanitize => [fields] # same as :escape
|
|
121
|
-
# :sanitize => [fields] # same as :strip
|
|
122
|
-
#
|
|
123
|
-
# The default is :text for all fields unless otherwise specified.
|
|
124
|
-
#
|
|
125
|
-
def xss_foliate(options = {})
|
|
126
|
-
callback_already_declared = \
|
|
127
|
-
if respond_to?(:before_validation_callback_chain)
|
|
128
|
-
# Rails 2.1 and later
|
|
129
|
-
before_validation_callback_chain.any? {|cb| cb.method == :xss_foliate_fields}
|
|
130
|
-
else
|
|
131
|
-
# Rails 2.0
|
|
132
|
-
cbs = read_inheritable_attribute(:before_validation)
|
|
133
|
-
(! cbs.nil?) && cbs.any? {|cb| cb == :xss_foliate_fields}
|
|
134
|
-
end
|
|
135
|
-
|
|
136
|
-
unless callback_already_declared
|
|
137
|
-
before_validation :xss_foliate_fields
|
|
138
|
-
class_inheritable_reader :xss_foliate_options
|
|
139
|
-
include XssFoliate::InstanceMethods
|
|
140
|
-
end
|
|
141
|
-
|
|
142
|
-
options.keys.each do |option|
|
|
143
|
-
raise ArgumentError, "unknown xss_foliate option #{option}" unless VALID_OPTIONS.include?(option)
|
|
144
|
-
end
|
|
145
|
-
|
|
146
|
-
REAL_OPTIONS.each do |option|
|
|
147
|
-
options[option] = Array(options[option]).collect { |val| val.to_sym }
|
|
148
|
-
end
|
|
149
|
-
|
|
150
|
-
ALIASED_OPTIONS.each do |option, real|
|
|
151
|
-
options[real] += Array(options.delete(option)).collect { |val| val.to_sym } if options[option]
|
|
152
|
-
end
|
|
153
|
-
|
|
154
|
-
write_inheritable_attribute(:xss_foliate_options, options)
|
|
155
|
-
end
|
|
156
|
-
|
|
157
|
-
#
|
|
158
|
-
# Class method to determine whether or not this model is applying
|
|
159
|
-
# xss_foliation to its attributes. Could be useful in test suites.
|
|
160
|
-
#
|
|
161
|
-
def xss_foliated?
|
|
162
|
-
options = read_inheritable_attribute(:xss_foliate_options)
|
|
163
|
-
! (options.nil? || options.empty?)
|
|
164
|
-
end
|
|
165
|
-
end
|
|
166
|
-
|
|
167
|
-
module InstanceMethods
|
|
168
|
-
|
|
169
|
-
def xss_foliate_fields # :nodoc:
|
|
170
|
-
# fix a bug with Rails internal AR::Base models that get loaded before
|
|
171
|
-
# the plugin, like CGI::Sessions::ActiveRecordStore::Session
|
|
172
|
-
return if xss_foliate_options.nil?
|
|
173
|
-
|
|
174
|
-
self.class.columns.each do |column|
|
|
175
|
-
next unless (column.type == :string || column.type == :text)
|
|
176
|
-
|
|
177
|
-
field = column.name.to_sym
|
|
178
|
-
value = self[field]
|
|
179
|
-
|
|
180
|
-
next if value.nil? || !value.is_a?(String)
|
|
181
|
-
|
|
182
|
-
if xss_foliate_options[:except].include?(field)
|
|
183
|
-
next
|
|
184
|
-
|
|
185
|
-
elsif xss_foliate_options[:strip].include?(field)
|
|
186
|
-
fragment = Loofah.scrub_fragment(value, :strip)
|
|
187
|
-
self[field] = fragment.nil? ? "" : fragment.to_s
|
|
188
|
-
|
|
189
|
-
elsif xss_foliate_options[:prune].include?(field)
|
|
190
|
-
fragment = Loofah.scrub_fragment(value, :prune)
|
|
191
|
-
self[field] = fragment.nil? ? "" : fragment.to_s
|
|
192
|
-
|
|
193
|
-
elsif xss_foliate_options[:escape].include?(field)
|
|
194
|
-
fragment = Loofah.scrub_fragment(value, :escape)
|
|
195
|
-
self[field] = fragment.nil? ? "" : fragment.to_s
|
|
196
|
-
|
|
197
|
-
else # :text
|
|
198
|
-
fragment = Loofah.scrub_fragment(value, :strip)
|
|
199
|
-
self[field] = fragment.nil? ? "" : fragment.text
|
|
200
|
-
end
|
|
201
|
-
end
|
|
202
|
-
|
|
203
|
-
end
|
|
204
|
-
end
|
|
205
|
-
end
|
|
206
|
-
end
|
|
207
|
-
|
|
208
|
-
ActiveRecord::Base.extend(Loofah::XssFoliate::ClassMethods)
|
|
209
|
-
|
|
210
|
-
if defined?(LOOFAH_XSS_FOLIATE_ALL_MODELS) && LOOFAH_XSS_FOLIATE_ALL_MODELS
|
|
211
|
-
ActiveRecord::Base.xss_foliate
|
|
212
|
-
end
|
data/test/helper.rb
DELETED