better_html 1.0.1 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (26) hide show
  1. checksums.yaml +4 -4
  2. data/lib/better_html/ast/iterator.rb +3 -3
  3. data/lib/better_html/ast/node.rb +6 -2
  4. data/lib/better_html/errors.rb +2 -11
  5. data/lib/better_html/test_helper/ruby_node.rb +103 -0
  6. data/lib/better_html/test_helper/safe_erb/allowed_script_type.rb +29 -0
  7. data/lib/better_html/test_helper/safe_erb/base.rb +56 -0
  8. data/lib/better_html/test_helper/safe_erb/no_javascript_tag_helper.rb +34 -0
  9. data/lib/better_html/test_helper/safe_erb/no_statements.rb +40 -0
  10. data/lib/better_html/test_helper/safe_erb/script_interpolation.rb +65 -0
  11. data/lib/better_html/test_helper/safe_erb/tag_interpolation.rb +163 -0
  12. data/lib/better_html/test_helper/safe_erb_tester.rb +32 -285
  13. data/lib/better_html/tokenizer/location.rb +1 -1
  14. data/lib/better_html/version.rb +1 -1
  15. data/test/better_html/errors_test.rb +13 -0
  16. data/test/better_html/test_helper/ruby_node_test.rb +288 -0
  17. data/test/better_html/test_helper/safe_erb/allowed_script_type_test.rb +45 -0
  18. data/test/better_html/test_helper/safe_erb/no_javascript_tag_helper_test.rb +37 -0
  19. data/test/better_html/test_helper/safe_erb/no_statements_test.rb +128 -0
  20. data/test/better_html/test_helper/safe_erb/script_interpolation_test.rb +149 -0
  21. data/test/better_html/test_helper/safe_erb/tag_interpolation_test.rb +295 -0
  22. data/test/test_helper.rb +1 -0
  23. metadata +23 -7
  24. data/lib/better_html/test_helper/ruby_expr.rb +0 -117
  25. data/test/better_html/test_helper/ruby_expr_test.rb +0 -283
  26. data/test/better_html/test_helper/safe_erb_tester_test.rb +0 -450
@@ -0,0 +1,45 @@
1
+ require 'test_helper'
2
+ require 'better_html/test_helper/safe_erb/allowed_script_type'
3
+
4
+ module BetterHtml
5
+ module TestHelper
6
+ module SafeErb
7
+ class AllowedScriptTypeTest < ActiveSupport::TestCase
8
+ setup do
9
+ @config = BetterHtml::Config.new(
10
+ javascript_safe_methods: ['j', 'escape_javascript', 'to_json'],
11
+ javascript_attribute_names: [/\Aon/i, 'data-eval'],
12
+ )
13
+ end
14
+
15
+ test "allowed script type" do
16
+ errors = validate(<<-EOF).errors
17
+ <script type="text/javascript">
18
+ </script>
19
+ EOF
20
+
21
+ assert_predicate errors, :empty?
22
+ end
23
+
24
+ test "disallowed script types" do
25
+ errors = validate(<<-EOF).errors
26
+ <script type="text/bogus">
27
+ </script>
28
+ EOF
29
+
30
+ assert_equal 1, errors.size
31
+ assert_equal 'type="text/bogus"', errors.first.location.source
32
+ assert_equal "text/bogus is not a valid type, valid types are text/javascript, text/template, text/html", errors.first.message
33
+ end
34
+
35
+ private
36
+ def validate(data, template_language: :html)
37
+ parser = BetterHtml::Parser.new(data, template_language: template_language)
38
+ tester = BetterHtml::TestHelper::SafeErb::AllowedScriptType.new(parser, config: @config)
39
+ tester.validate
40
+ tester
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,37 @@
1
+ require 'test_helper'
2
+ require 'better_html/test_helper/safe_erb/no_javascript_tag_helper'
3
+
4
+ module BetterHtml
5
+ module TestHelper
6
+ module SafeErb
7
+ class NoJavascriptTagHelperTest < ActiveSupport::TestCase
8
+ setup do
9
+ @config = BetterHtml::Config.new(
10
+ javascript_safe_methods: ['j', 'escape_javascript', 'to_json'],
11
+ javascript_attribute_names: [/\Aon/i, 'data-eval'],
12
+ )
13
+ end
14
+
15
+ test "javascript_tag helper is not allowed because it parses as text and unsafe erb cannot be detected" do
16
+ errors = validate(<<-EOF).errors
17
+ <%= javascript_tag do %>
18
+ if (a < 1) { <%= unsafe %> }
19
+ <% end %>
20
+ EOF
21
+
22
+ assert_equal 1, errors.size
23
+ assert_equal '<%= javascript_tag do %>', errors.first.location.source
24
+ assert_includes "'javascript_tag do' syntax is deprecated; use inline <script> instead", errors.first.message
25
+ end
26
+
27
+ private
28
+ def validate(data, template_language: :html)
29
+ parser = BetterHtml::Parser.new(data, template_language: template_language)
30
+ tester = BetterHtml::TestHelper::SafeErb::NoJavascriptTagHelper.new(parser, config: @config)
31
+ tester.validate
32
+ tester
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,128 @@
1
+ require 'test_helper'
2
+ require 'better_html/test_helper/safe_erb/no_statements'
3
+
4
+ module BetterHtml
5
+ module TestHelper
6
+ module SafeErb
7
+ class NoStatementsTest < ActiveSupport::TestCase
8
+ setup do
9
+ @config = BetterHtml::Config.new(
10
+ javascript_safe_methods: ['j', 'escape_javascript', 'to_json'],
11
+ javascript_attribute_names: [/\Aon/i, 'data-eval'],
12
+ )
13
+ end
14
+
15
+ test "<script> tag with non executable content type is ignored" do
16
+ errors = validate(<<-EOF).errors
17
+ <script type="text/html">
18
+ <a onclick="<%= unsafe %>">
19
+ </script>
20
+ EOF
21
+
22
+ assert_predicate errors, :empty?
23
+ end
24
+
25
+ test "statements not allowed in script tags" do
26
+ errors = validate(<<-EOF).errors
27
+ <script type="text/javascript">
28
+ <% if foo? %>
29
+ bla
30
+ <% end %>
31
+ </script>
32
+ EOF
33
+
34
+ assert_equal 1, errors.size
35
+ assert_equal "<% if foo? %>", errors.first.location.source
36
+ assert_equal "erb statement not allowed here; did you mean '<%=' ?", errors.first.message
37
+ end
38
+
39
+ test "statements not allowed in script without specified type" do
40
+ errors = validate(<<-EOF).errors
41
+ <script>
42
+ <% if foo? %>
43
+ bla
44
+ <% end %>
45
+ </script>
46
+ EOF
47
+
48
+ assert_equal 1, errors.size
49
+ assert_equal "<% if foo? %>", errors.first.location.source
50
+ assert_equal "erb statement not allowed here; did you mean '<%=' ?", errors.first.message
51
+ end
52
+
53
+ test "statements not allowed in javascript template" do
54
+ errors = validate(<<-JS, template_language: :javascript).errors
55
+ <% if foo %>
56
+ bla
57
+ <% end %>
58
+ JS
59
+
60
+ assert_equal 1, errors.size
61
+ assert_equal "<% if foo %>", errors.first.location.source
62
+ assert_equal "erb statement not allowed here; did you mean '<%=' ?", errors.first.message
63
+ end
64
+
65
+ test "erb comments allowed in scripts" do
66
+ errors = validate(<<-EOF).errors
67
+ <script type="text/javascript">
68
+ <%# comment %>
69
+ </script>
70
+ EOF
71
+
72
+ assert_predicate errors, :empty?
73
+ end
74
+
75
+ test "script tag without content" do
76
+ errors = validate(<<-EOF).errors
77
+ <script type="text/javascript"></script>
78
+ EOF
79
+
80
+ assert_predicate errors, :empty?
81
+ end
82
+
83
+ test "statement after script regression" do
84
+ errors = validate(<<-EOF).errors
85
+ <script type="text/javascript">
86
+ foo()
87
+ </script>
88
+ <% if condition? %>
89
+ EOF
90
+
91
+ assert_predicate errors, :empty?
92
+ end
93
+
94
+ test "end statements are allowed in script tags" do
95
+ errors = validate(<<-EOF).errors
96
+ <script type="text/template">
97
+ <%= ui_form do %>
98
+ <div></div>
99
+ <% end %>
100
+ </script>
101
+ EOF
102
+
103
+ assert_predicate errors, :empty?
104
+ end
105
+
106
+ test "statements are allowed in text/html tags" do
107
+ errors = validate(<<-EOF).errors
108
+ <script type="text/html">
109
+ <% if condition? %>
110
+ <div></div>
111
+ <% end %>
112
+ </script>
113
+ EOF
114
+
115
+ assert_predicate errors, :empty?
116
+ end
117
+
118
+ private
119
+ def validate(data, template_language: :html)
120
+ parser = BetterHtml::Parser.new(data, template_language: template_language)
121
+ tester = BetterHtml::TestHelper::SafeErb::NoStatements.new(parser, config: @config)
122
+ tester.validate
123
+ tester
124
+ end
125
+ end
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,149 @@
1
+ require 'test_helper'
2
+ require 'better_html/test_helper/safe_erb/script_interpolation'
3
+
4
+ module BetterHtml
5
+ module TestHelper
6
+ module SafeErb
7
+ class ScriptInterpolationTest < ActiveSupport::TestCase
8
+ setup do
9
+ @config = BetterHtml::Config.new(
10
+ javascript_safe_methods: ['j', 'escape_javascript', 'to_json'],
11
+ javascript_attribute_names: [/\Aon/i, 'data-eval'],
12
+ )
13
+ end
14
+
15
+ test "multi line erb comments in text" do
16
+ errors = validate(<<-EOF).errors
17
+ text
18
+ <%#
19
+ this is a nice comment
20
+ !@\#{$%?&*()}
21
+ %>
22
+ EOF
23
+
24
+ assert_predicate errors, :empty?
25
+ end
26
+
27
+ test "multi line erb comments in html attribute" do
28
+ errors = validate(<<-EOF).errors
29
+ <div title="
30
+ <%#
31
+ this is a comment right in the middle of an attribute for some reason
32
+ %>
33
+ ">
34
+ EOF
35
+
36
+ assert_predicate errors, :empty?
37
+ end
38
+
39
+ test "unsafe erb in <script> tag without type" do
40
+ errors = validate(<<-EOF).errors
41
+ <script>
42
+ if (a < 1) { <%= unsafe %> }
43
+ </script>
44
+ EOF
45
+
46
+ assert_equal 1, errors.size
47
+ assert_equal '<%= unsafe %>', errors.first.location.source
48
+ assert_equal "erb interpolation in javascript tag must call '(...).to_json'", errors.first.message
49
+ end
50
+
51
+ test "unsafe erb in javascript template" do
52
+ errors = validate(<<-JS, template_language: :javascript).errors
53
+ if (a < 1) { <%= unsafe %> }
54
+ JS
55
+
56
+ assert_equal 1, errors.size
57
+ assert_equal '<%= unsafe %>', errors.first.location.source
58
+ assert_equal "erb interpolation in javascript tag must call '(...).to_json'", errors.first.message
59
+ end
60
+
61
+ test "<script> tag without calls is unsafe" do
62
+ errors = validate(<<-EOF).errors
63
+ <script type="text/javascript">
64
+ if (a < 1) { <%= "unsafe" %> }
65
+ </script>
66
+ EOF
67
+
68
+ assert_equal 1, errors.size
69
+ assert_equal '<%= "unsafe" %>', errors.first.location.source
70
+ assert_equal "erb interpolation in javascript tag must call '(...).to_json'", errors.first.message
71
+ end
72
+
73
+ test "javascript template without calls is unsafe" do
74
+ errors = validate(<<-JS, template_language: :javascript).errors
75
+ if (a < 1) { <%= "unsafe" %> }
76
+ JS
77
+
78
+ assert_equal 1, errors.size
79
+ assert_equal '<%= "unsafe" %>', errors.first.location.source
80
+ assert_equal "erb interpolation in javascript tag must call '(...).to_json'", errors.first.message
81
+ end
82
+
83
+ test "unsafe erb in <script> tag with text/javascript content type" do
84
+ errors = validate(<<-EOF).errors
85
+ <script type="text/javascript">
86
+ if (a < 1) { <%= unsafe %> }
87
+ </script>
88
+ EOF
89
+
90
+ assert_equal 1, errors.size
91
+ assert_equal '<%= unsafe %>', errors.first.location.source
92
+ assert_equal "erb interpolation in javascript tag must call '(...).to_json'", errors.first.message
93
+ end
94
+
95
+ test "<script> with to_json is safe" do
96
+ errors = validate(<<-EOF).errors
97
+ <script type="text/javascript">
98
+ <%= unsafe.to_json %>
99
+ </script>
100
+ EOF
101
+
102
+ assert_predicate errors, :empty?
103
+ end
104
+
105
+ test "javascript template with to_json is safe" do
106
+ errors = validate(<<-JS, template_language: :javascript).errors
107
+ <%= unsafe.to_json %>
108
+ JS
109
+
110
+ assert_predicate errors, :empty?
111
+ end
112
+
113
+ test "<script> with raw and to_json is safe" do
114
+ errors = validate(<<-EOF).errors
115
+ <script type="text/javascript">
116
+ <%= raw unsafe.to_json %>
117
+ </script>
118
+ EOF
119
+
120
+ assert_predicate errors, :empty?
121
+ end
122
+
123
+ test "javascript template with raw and to_json is safe" do
124
+ errors = validate(<<-JS, template_language: :javascript).errors
125
+ <%= raw unsafe.to_json %>
126
+ JS
127
+
128
+ assert_predicate errors, :empty?
129
+ end
130
+
131
+ test "ivar missing .to_json is unsafe" do
132
+ errors = validate('<script><%= @feature.html_safe %></script>').errors
133
+
134
+ assert_equal 1, errors.size
135
+ assert_equal "<%= @feature.html_safe %>", errors.first.location.source
136
+ assert_equal "erb interpolation in javascript tag must call '(...).to_json'", errors.first.message
137
+ end
138
+
139
+ private
140
+ def validate(data, template_language: :html)
141
+ parser = BetterHtml::Parser.new(data, template_language: template_language)
142
+ tester = BetterHtml::TestHelper::SafeErb::ScriptInterpolation.new(parser, config: @config)
143
+ tester.validate
144
+ tester
145
+ end
146
+ end
147
+ end
148
+ end
149
+ end
@@ -0,0 +1,295 @@
1
+ require 'test_helper'
2
+ require 'better_html/test_helper/safe_erb/tag_interpolation'
3
+
4
+ module BetterHtml
5
+ module TestHelper
6
+ module SafeErb
7
+ class TagInterpolationTest < ActiveSupport::TestCase
8
+ setup do
9
+ @config = BetterHtml::Config.new(
10
+ javascript_safe_methods: ['j', 'escape_javascript', 'to_json'],
11
+ javascript_attribute_names: [/\Aon/i, 'data-eval'],
12
+ )
13
+ end
14
+
15
+ test "raw in <script> tag" do
16
+ errors = validate(<<-EOF).errors
17
+ <script>var myData = <%= raw(foo.to_json) %>;</script>
18
+ EOF
19
+
20
+ assert_equal 0, errors.size
21
+ end
22
+
23
+ test "html_safe in <script> tag" do
24
+ errors = validate(<<-EOF).errors
25
+ <script>var myData = <%= foo.to_json.html_safe %>;</script>
26
+ EOF
27
+
28
+ assert_equal 0, errors.size
29
+ end
30
+
31
+ test "<%== in <script> tag" do
32
+ errors = validate(<<-EOF).errors
33
+ <script>var myData = <%== foo.to_json %>;</script>
34
+ EOF
35
+
36
+ assert_equal 0, errors.size
37
+ end
38
+
39
+ test "string without interpolation is safe" do
40
+ errors = validate(<<-EOF).errors
41
+ <a onclick="alert('<%= "something" %>')">
42
+ EOF
43
+
44
+ assert_equal 0, errors.size
45
+ end
46
+
47
+ test "string with interpolation" do
48
+ errors = validate(<<-EOF).errors
49
+ <a onclick="<%= "hello \#{name}" %>">
50
+ EOF
51
+
52
+ assert_equal 1, errors.size
53
+ assert_equal 'name', errors.first.location.source
54
+ assert_equal "erb interpolation in javascript attribute must be wrapped in safe helper such as '(...).to_json'", errors.first.message
55
+ end
56
+
57
+ test "string with interpolation and ternary" do
58
+ errors = validate(<<-EOF).errors
59
+ <a onclick="<%= "hello \#{foo ? bar : baz}" if bla? %>">
60
+ EOF
61
+
62
+ assert_equal 2, errors.size
63
+
64
+ assert_equal 'bar', errors[0].location.source
65
+ assert_equal "erb interpolation in javascript attribute must be wrapped in safe helper such as '(...).to_json'", errors[0].message
66
+
67
+ assert_equal 'baz', errors[1].location.source
68
+ assert_equal "erb interpolation in javascript attribute must be wrapped in safe helper such as '(...).to_json'", errors[1].message
69
+ end
70
+
71
+ test "plain erb tag in html attribute" do
72
+ errors = validate(<<-EOF).errors
73
+ <a onclick="method(<%= unsafe %>)">
74
+ EOF
75
+
76
+ assert_equal 1, errors.size
77
+ assert_equal 'unsafe', errors.first.location.source
78
+ assert_equal "erb interpolation in javascript attribute must be wrapped in safe helper such as '(...).to_json'", errors.first.message
79
+ end
80
+
81
+ test "to_json is safe in html attribute" do
82
+ errors = validate(<<-EOF).errors
83
+ <a onclick="method(<%= unsafe.to_json %>)">
84
+ EOF
85
+ assert_predicate errors, :empty?
86
+ end
87
+
88
+ test "ternary with safe javascript escaping" do
89
+ errors = validate(<<-EOF).errors
90
+ <a onclick="method(<%= foo ? bar.to_json : j(baz) %>)">
91
+ EOF
92
+ assert_predicate errors, :empty?
93
+ end
94
+
95
+ test "ternary with unsafe javascript escaping" do
96
+ errors = validate(<<-EOF).errors
97
+ <a onclick="method(<%= foo ? bar : j(baz) %>)">
98
+ EOF
99
+
100
+ assert_equal 1, errors.size
101
+ assert_equal 'bar', errors.first.location.source
102
+ assert_equal "erb interpolation in javascript attribute must be wrapped in safe helper such as '(...).to_json'", errors.first.message
103
+ end
104
+
105
+ test "j is safe in html attribute" do
106
+ errors = validate(<<-EOF).errors
107
+ <a onclick="method('<%= j unsafe %>')">
108
+ EOF
109
+ assert_predicate errors, :empty?
110
+ end
111
+
112
+ test "j() is safe in html attribute" do
113
+ errors = validate(<<-EOF).errors
114
+ <a onclick="method('<%= j(unsafe) %>')">
115
+ EOF
116
+ assert_predicate errors, :empty?
117
+ end
118
+
119
+ test "escape_javascript is safe in html attribute" do
120
+ errors = validate(<<-EOF).errors
121
+ <a onclick="method(<%= escape_javascript unsafe %>)">
122
+ EOF
123
+ assert_predicate errors, :empty?
124
+ end
125
+
126
+ test "escape_javascript() is safe in html attribute" do
127
+ errors = validate(<<-EOF).errors
128
+ <a onclick="method(<%= escape_javascript(unsafe) %>)">
129
+ EOF
130
+ assert_predicate errors, :empty?
131
+ end
132
+
133
+ test "html_safe is never safe in html attribute, even non javascript attributes like href" do
134
+ errors = validate(<<-EOF).errors
135
+ <a href="<%= unsafe.html_safe %>">
136
+ EOF
137
+
138
+ assert_equal 1, errors.size
139
+ assert_equal 'unsafe.html_safe', errors.first.location.source
140
+ assert_equal "erb interpolation with '<%= (...).html_safe %>' in this context is never safe", errors.first.message
141
+ end
142
+
143
+ test "html_safe is never safe in html attribute, even with to_json" do
144
+ errors = validate(<<-EOF).errors
145
+ <a onclick="method(<%= unsafe.to_json.html_safe %>)">
146
+ EOF
147
+
148
+ assert_equal 2, errors.size
149
+ assert_equal 'unsafe.to_json.html_safe', errors[0].location.source
150
+ assert_equal "erb interpolation with '<%= (...).html_safe %>' in this context is never safe", errors[0].message
151
+ assert_equal 'unsafe.to_json.html_safe', errors[1].location.source
152
+ assert_equal "erb interpolation in javascript attribute must be wrapped in safe helper such as '(...).to_json'", errors[1].message
153
+ end
154
+
155
+ test "<%== is never safe in html attribute, even non javascript attributes like href" do
156
+ errors = validate(<<-EOF).errors
157
+ <a href="<%== unsafe %>">
158
+ EOF
159
+
160
+ assert_equal 1, errors.size
161
+ assert_equal '<%== unsafe %>', errors.first.location.source
162
+ assert_includes "erb interpolation with '<%==' inside html attribute is never safe", errors.first.message
163
+ end
164
+
165
+ test "<%== is never safe in html attribute, even with to_json" do
166
+ errors = validate(<<-EOF).errors
167
+ <a onclick="method(<%== unsafe.to_json %>)">
168
+ EOF
169
+
170
+ assert_equal 1, errors.size
171
+ assert_equal '<%== unsafe.to_json %>', errors.first.location.source
172
+ assert_includes "erb interpolation with '<%==' inside html attribute is never safe", errors.first.message
173
+ end
174
+
175
+ test "raw is never safe in html attribute, even non javascript attributes like href" do
176
+ errors = validate(<<-EOF).errors
177
+ <a href="<%= raw unsafe %>">
178
+ EOF
179
+
180
+ assert_equal 1, errors.size
181
+ assert_equal 'raw unsafe', errors.first.location.source
182
+ assert_equal "erb interpolation with '<%= raw(...) %>' in this context is never safe", errors.first.message
183
+ end
184
+
185
+ test "raw is never safe in html attribute, even with to_json" do
186
+ errors = validate(<<-EOF).errors
187
+ <a onclick="method(<%= raw unsafe.to_json %>)">
188
+ EOF
189
+
190
+ assert_equal 2, errors.size
191
+ assert_equal 'raw unsafe.to_json', errors[0].location.source
192
+ assert_equal "erb interpolation with '<%= raw(...) %>' in this context is never safe", errors[0].message
193
+ assert_equal 'raw unsafe.to_json', errors[1].location.source
194
+ assert_equal "erb interpolation in javascript attribute must be wrapped in safe helper such as '(...).to_json'", errors[1].message
195
+ end
196
+
197
+ test "unsafe javascript methods in helper calls with new hash syntax" do
198
+ errors = validate(<<-EOF).errors
199
+ <%= ui_my_helper(:foo, onclick: "alert(\#{unsafe})", onmouseover: "alert(\#{unsafe.to_json})") %>
200
+ EOF
201
+
202
+ assert_equal 1, errors.size
203
+ assert_equal "unsafe", errors[0].location.source
204
+ assert_equal "erb interpolation in javascript attribute must be wrapped in safe helper such as '(...).to_json'", errors[0].message
205
+ end
206
+
207
+ test "unsafe javascript methods in helper calls with old hash syntax" do
208
+ errors = validate(<<-EOF).errors
209
+ <%= ui_my_helper(:foo, :onclick => "alert(\#{unsafe})") %>
210
+ EOF
211
+
212
+ assert_equal 1, errors.size
213
+ assert_equal "unsafe", errors.first.location.source
214
+ assert_equal "erb interpolation in javascript attribute must be wrapped in safe helper such as '(...).to_json'", errors.first.message
215
+ end
216
+
217
+ test "unsafe javascript methods in helper calls with more than one level of nested hash and :dstr" do
218
+ errors = validate(<<-EOF).errors
219
+ <%= ui_my_helper(:foo, inner_html: { onclick: "foo \#{unsafe}" }) %>
220
+ EOF
221
+
222
+ assert_equal 1, errors.size
223
+ assert_equal "unsafe", errors.first.location.source
224
+ assert_equal "erb interpolation in javascript attribute must be wrapped in safe helper such as '(...).to_json'", errors.first.message
225
+ end
226
+
227
+ test "safe javascript methods in helper calls with more than one level of nested hash and :dstr" do
228
+ errors = validate(<<-EOF).errors
229
+ <%= ui_my_helper(:foo, inner_html: { onclick: "foo \#{unsafe.to_json}" }) %>
230
+ EOF
231
+
232
+ assert_equal 0, errors.size
233
+ end
234
+
235
+ test "unsafe javascript methods in helper calls with string as key" do
236
+ errors = validate(<<-EOF).errors
237
+ <%= ui_my_helper(:foo, 'data-eval' => "alert(\#{unsafe})") %>
238
+ EOF
239
+
240
+ assert_equal 1, errors.size
241
+ assert_equal "unsafe", errors.first.location.source
242
+ assert_equal "erb interpolation in javascript attribute must be wrapped in safe helper such as '(...).to_json'", errors.first.message
243
+ end
244
+
245
+ test "unsafe javascript methods in helper calls with nested data key" do
246
+ errors = validate(<<-EOF).errors
247
+ <%= ui_my_helper(:foo, data: { eval: "alert(\#{unsafe})" }) %>
248
+ EOF
249
+
250
+ assert_equal 1, errors.size
251
+ assert_equal "unsafe", errors.first.location.source
252
+ assert_equal "erb interpolation in javascript attribute must be wrapped in safe helper such as '(...).to_json'", errors.first.message
253
+ end
254
+
255
+ test "unsafe javascript methods in helper calls with more than one level of nested data key" do
256
+ errors = validate(<<-EOF).errors
257
+ <%= ui_my_helper(:foo, inner_html: { data: { eval: "alert(\#{unsafe})" } }) %>
258
+ EOF
259
+
260
+ assert_equal 1, errors.size
261
+ assert_equal "unsafe", errors.first.location.source
262
+ assert_equal "erb interpolation in javascript attribute must be wrapped in safe helper such as '(...).to_json'", errors.first.message
263
+ end
264
+
265
+ test "using raw anywhere in helpers" do
266
+ errors = validate(<<-EOF).errors
267
+ <%= ui_my_helper(:foo, help_text: raw("foo")) %>
268
+ EOF
269
+
270
+ assert_equal 1, errors.size
271
+ assert_equal "ui_my_helper(:foo, help_text: raw(\"foo\"))", errors.first.location.source
272
+ assert_equal "erb interpolation with '<%= raw(...) %>' in this context is never safe", errors.first.message
273
+ end
274
+
275
+ test "using raw anywhere in html tags" do
276
+ errors = validate(<<-EOF).errors
277
+ <a "<%= raw("hello") %>">
278
+ EOF
279
+
280
+ assert_equal 1, errors.size
281
+ assert_equal "raw(\"hello\")", errors.first.location.source
282
+ assert_equal "erb interpolation with '<%= raw(...) %>' in this context is never safe", errors.first.message
283
+ end
284
+
285
+ private
286
+ def validate(data, template_language: :html)
287
+ parser = BetterHtml::Parser.new(data, template_language: template_language)
288
+ tester = BetterHtml::TestHelper::SafeErb::TagInterpolation.new(parser, config: @config)
289
+ tester.validate
290
+ tester
291
+ end
292
+ end
293
+ end
294
+ end
295
+ end