better_html 1.0.1 → 1.0.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.
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