rails-html-sanitizer 1.5.0 → 1.6.0.rc1
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 +58 -0
- data/MIT-LICENSE +1 -1
- data/README.md +95 -48
- data/lib/rails/html/sanitizer/version.rb +4 -2
- data/lib/rails/html/sanitizer.rb +367 -104
- data/lib/rails/html/scrubbers.rb +70 -69
- data/lib/rails-html-sanitizer.rb +7 -23
- data/test/rails_api_test.rb +74 -0
- data/test/sanitizer_test.rb +900 -590
- data/test/scrubbers_test.rb +49 -36
- metadata +21 -65
data/lib/rails/html/scrubbers.rb
CHANGED
@@ -1,10 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Rails
|
2
|
-
module
|
3
|
-
# === Rails::
|
4
|
+
module HTML
|
5
|
+
# === Rails::HTML::PermitScrubber
|
4
6
|
#
|
5
|
-
# +Rails::
|
7
|
+
# +Rails::HTML::PermitScrubber+ allows you to permit only your own tags and/or attributes.
|
6
8
|
#
|
7
|
-
# +Rails::
|
9
|
+
# +Rails::HTML::PermitScrubber+ can be subclassed to determine:
|
8
10
|
# - When a node should be skipped via +skip_node?+.
|
9
11
|
# - When a node is allowed via +allowed_node?+.
|
10
12
|
# - When an attribute should be scrubbed via +scrub_attribute?+.
|
@@ -27,7 +29,7 @@ module Rails
|
|
27
29
|
# If set, attributes excluded will be removed.
|
28
30
|
# If not, attributes are removed based on Loofahs +HTML5::Scrub.scrub_attributes+.
|
29
31
|
#
|
30
|
-
# class CommentScrubber <
|
32
|
+
# class CommentScrubber < Rails::HTML::PermitScrubber
|
31
33
|
# def initialize
|
32
34
|
# super
|
33
35
|
# self.tags = %w(form script comment blockquote)
|
@@ -77,90 +79,89 @@ module Rails
|
|
77
79
|
end
|
78
80
|
|
79
81
|
protected
|
82
|
+
def allowed_node?(node)
|
83
|
+
@tags.include?(node.name)
|
84
|
+
end
|
80
85
|
|
81
|
-
|
82
|
-
|
83
|
-
|
86
|
+
def skip_node?(node)
|
87
|
+
node.text?
|
88
|
+
end
|
84
89
|
|
85
|
-
|
86
|
-
|
87
|
-
|
90
|
+
def scrub_attribute?(name)
|
91
|
+
!@attributes.include?(name)
|
92
|
+
end
|
88
93
|
|
89
|
-
|
90
|
-
|
91
|
-
|
94
|
+
def keep_node?(node)
|
95
|
+
if @tags
|
96
|
+
allowed_node?(node)
|
97
|
+
else
|
98
|
+
Loofah::HTML5::Scrub.allowed_element?(node.name)
|
99
|
+
end
|
100
|
+
end
|
92
101
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
else
|
97
|
-
Loofah::HTML5::Scrub.allowed_element?(node.name)
|
102
|
+
def scrub_node(node)
|
103
|
+
node.before(node.children) unless prune # strip
|
104
|
+
node.remove
|
98
105
|
end
|
99
|
-
end
|
100
106
|
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
107
|
+
def scrub_attributes(node)
|
108
|
+
if @attributes
|
109
|
+
node.attribute_nodes.each do |attr|
|
110
|
+
attr.remove if scrub_attribute?(attr.name)
|
111
|
+
scrub_attribute(node, attr)
|
112
|
+
end
|
105
113
|
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
attr.remove if scrub_attribute?(attr.name)
|
110
|
-
scrub_attribute(node, attr)
|
114
|
+
scrub_css_attribute(node)
|
115
|
+
else
|
116
|
+
Loofah::HTML5::Scrub.scrub_attributes(node)
|
111
117
|
end
|
112
|
-
|
113
|
-
scrub_css_attribute(node)
|
114
|
-
else
|
115
|
-
Loofah::HTML5::Scrub.scrub_attributes(node)
|
116
118
|
end
|
117
|
-
end
|
118
119
|
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
120
|
+
def scrub_css_attribute(node)
|
121
|
+
if Loofah::HTML5::Scrub.respond_to?(:scrub_css_attribute)
|
122
|
+
Loofah::HTML5::Scrub.scrub_css_attribute(node)
|
123
|
+
else
|
124
|
+
style = node.attributes["style"]
|
125
|
+
style.value = Loofah::HTML5::Scrub.scrub_css(style.value) if style
|
126
|
+
end
|
125
127
|
end
|
126
|
-
end
|
127
128
|
|
128
|
-
|
129
|
-
|
130
|
-
|
129
|
+
def validate!(var, name)
|
130
|
+
if var && !var.is_a?(Enumerable)
|
131
|
+
raise ArgumentError, "You should pass :#{name} as an Enumerable"
|
132
|
+
end
|
133
|
+
var
|
131
134
|
end
|
132
|
-
var
|
133
|
-
end
|
134
135
|
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
136
|
+
def scrub_attribute(node, attr_node)
|
137
|
+
attr_name = if attr_node.namespace
|
138
|
+
"#{attr_node.namespace.prefix}:#{attr_node.node_name}"
|
139
|
+
else
|
140
|
+
attr_node.node_name
|
141
|
+
end
|
141
142
|
|
142
|
-
|
143
|
-
|
144
|
-
|
143
|
+
if Loofah::HTML5::SafeList::ATTR_VAL_IS_URI.include?(attr_name)
|
144
|
+
return if Loofah::HTML5::Scrub.scrub_uri_attribute(attr_node)
|
145
|
+
end
|
145
146
|
|
146
|
-
|
147
|
-
|
148
|
-
|
147
|
+
if Loofah::HTML5::SafeList::SVG_ATTR_VAL_ALLOWS_REF.include?(attr_name)
|
148
|
+
Loofah::HTML5::Scrub.scrub_attribute_that_allows_local_ref(attr_node)
|
149
|
+
end
|
149
150
|
|
150
|
-
|
151
|
-
|
152
|
-
|
151
|
+
if Loofah::HTML5::SafeList::SVG_ALLOW_LOCAL_HREF.include?(node.name) && attr_name == "xlink:href" && attr_node.value =~ /^\s*[^#\s].*/m
|
152
|
+
attr_node.remove
|
153
|
+
end
|
153
154
|
|
154
|
-
|
155
|
+
node.remove_attribute(attr_node.name) if attr_name == "src" && attr_node.value !~ /[^[:space:]]/
|
155
156
|
|
156
|
-
|
157
|
-
|
157
|
+
Loofah::HTML5::Scrub.force_correct_attribute_escaping! node
|
158
|
+
end
|
158
159
|
end
|
159
160
|
|
160
|
-
# === Rails::
|
161
|
+
# === Rails::HTML::TargetScrubber
|
161
162
|
#
|
162
|
-
# Where +Rails::
|
163
|
-
# sanitization, +Rails::
|
163
|
+
# Where +Rails::HTML::PermitScrubber+ picks out tags and attributes to permit in
|
164
|
+
# sanitization, +Rails::HTML::TargetScrubber+ targets them for removal.
|
164
165
|
#
|
165
166
|
# +tags=+
|
166
167
|
# If set, elements included will be stripped.
|
@@ -177,9 +178,9 @@ module Rails
|
|
177
178
|
end
|
178
179
|
end
|
179
180
|
|
180
|
-
# === Rails::
|
181
|
+
# === Rails::HTML::TextOnlyScrubber
|
181
182
|
#
|
182
|
-
# +Rails::
|
183
|
+
# +Rails::HTML::TextOnlyScrubber+ allows you to permit text nodes.
|
183
184
|
#
|
184
185
|
# Unallowed elements will be stripped, i.e. element is removed but its subtree kept.
|
185
186
|
class TextOnlyScrubber < Loofah::Scrubber
|
data/lib/rails-html-sanitizer.rb
CHANGED
@@ -1,30 +1,14 @@
|
|
1
|
-
|
2
|
-
require "loofah"
|
3
|
-
require "rails/html/scrubbers"
|
4
|
-
require "rails/html/sanitizer"
|
1
|
+
# frozen_string_literal: true
|
5
2
|
|
6
|
-
|
7
|
-
module Html
|
8
|
-
class Sanitizer
|
9
|
-
class << self
|
10
|
-
def full_sanitizer
|
11
|
-
Html::FullSanitizer
|
12
|
-
end
|
3
|
+
require_relative "rails/html/sanitizer/version"
|
13
4
|
|
14
|
-
|
15
|
-
Html::LinkSanitizer
|
16
|
-
end
|
5
|
+
require "loofah"
|
17
6
|
|
18
|
-
|
19
|
-
|
20
|
-
end
|
7
|
+
require_relative "rails/html/scrubbers"
|
8
|
+
require_relative "rails/html/sanitizer"
|
21
9
|
|
22
|
-
|
23
|
-
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
10
|
+
module Rails
|
11
|
+
Html = HTML # :nodoc:
|
28
12
|
end
|
29
13
|
|
30
14
|
module ActionView
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "minitest/autorun"
|
4
|
+
require "rails-html-sanitizer"
|
5
|
+
|
6
|
+
class RailsApiTest < Minitest::Test
|
7
|
+
def test_html_module_name_alias
|
8
|
+
assert_equal(Rails::Html, Rails::HTML)
|
9
|
+
assert_equal("Rails::HTML", Rails::Html.name)
|
10
|
+
assert_equal("Rails::HTML", Rails::HTML.name)
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_html_scrubber_class_names
|
14
|
+
assert(Rails::Html::PermitScrubber)
|
15
|
+
assert(Rails::Html::TargetScrubber)
|
16
|
+
assert(Rails::Html::TextOnlyScrubber)
|
17
|
+
assert(Rails::Html::Sanitizer)
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_html4_sanitizer_alias_full
|
21
|
+
assert_equal(Rails::HTML4::FullSanitizer, Rails::HTML::FullSanitizer)
|
22
|
+
assert_equal("Rails::HTML4::FullSanitizer", Rails::HTML::FullSanitizer.name)
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_html4_sanitizer_alias_link
|
26
|
+
assert_equal(Rails::HTML4::LinkSanitizer, Rails::HTML::LinkSanitizer)
|
27
|
+
assert_equal("Rails::HTML4::LinkSanitizer", Rails::HTML::LinkSanitizer.name)
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_html4_sanitizer_alias_safe_list
|
31
|
+
assert_equal(Rails::HTML4::SafeListSanitizer, Rails::HTML::SafeListSanitizer)
|
32
|
+
assert_equal("Rails::HTML4::SafeListSanitizer", Rails::HTML::SafeListSanitizer.name)
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_html4_full_sanitizer
|
36
|
+
assert_equal(Rails::HTML4::FullSanitizer, Rails::HTML::Sanitizer.full_sanitizer)
|
37
|
+
assert_equal(Rails::HTML4::FullSanitizer, Rails::HTML4::Sanitizer.full_sanitizer)
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_html4_link_sanitizer
|
41
|
+
assert_equal(Rails::HTML4::LinkSanitizer, Rails::HTML::Sanitizer.link_sanitizer)
|
42
|
+
assert_equal(Rails::HTML4::LinkSanitizer, Rails::HTML4::Sanitizer.link_sanitizer)
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_html4_safe_list_sanitizer
|
46
|
+
assert_equal(Rails::HTML4::SafeListSanitizer, Rails::HTML::Sanitizer.safe_list_sanitizer)
|
47
|
+
assert_equal(Rails::HTML4::SafeListSanitizer, Rails::HTML4::Sanitizer.safe_list_sanitizer)
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_html4_white_list_sanitizer
|
51
|
+
assert_equal(Rails::HTML4::SafeListSanitizer, Rails::HTML::Sanitizer.white_list_sanitizer)
|
52
|
+
assert_equal(Rails::HTML4::SafeListSanitizer, Rails::HTML4::Sanitizer.white_list_sanitizer)
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_html5_full_sanitizer
|
56
|
+
skip("no HTML5 support on this platform") unless Rails::HTML::Sanitizer.html5_support?
|
57
|
+
assert_equal(Rails::HTML5::FullSanitizer, Rails::HTML5::Sanitizer.full_sanitizer)
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_html5_link_sanitizer
|
61
|
+
skip("no HTML5 support on this platform") unless Rails::HTML::Sanitizer.html5_support?
|
62
|
+
assert_equal(Rails::HTML5::LinkSanitizer, Rails::HTML5::Sanitizer.link_sanitizer)
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_html5_safe_list_sanitizer
|
66
|
+
skip("no HTML5 support on this platform") unless Rails::HTML::Sanitizer.html5_support?
|
67
|
+
assert_equal(Rails::HTML5::SafeListSanitizer, Rails::HTML5::Sanitizer.safe_list_sanitizer)
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_html5_white_list_sanitizer
|
71
|
+
skip("no HTML5 support on this platform") unless Rails::HTML::Sanitizer.html5_support?
|
72
|
+
assert_equal(Rails::HTML5::SafeListSanitizer, Rails::HTML5::Sanitizer.white_list_sanitizer)
|
73
|
+
end
|
74
|
+
end
|