brakeman-lib 3.3.1

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 (159) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGES +872 -0
  3. data/FEATURES +16 -0
  4. data/README.md +169 -0
  5. data/WARNING_TYPES +95 -0
  6. data/bin/brakeman +89 -0
  7. data/lib/brakeman.rb +495 -0
  8. data/lib/brakeman/app_tree.rb +161 -0
  9. data/lib/brakeman/brakeman.rake +17 -0
  10. data/lib/brakeman/call_index.rb +219 -0
  11. data/lib/brakeman/checks.rb +191 -0
  12. data/lib/brakeman/checks/base_check.rb +518 -0
  13. data/lib/brakeman/checks/check_basic_auth.rb +88 -0
  14. data/lib/brakeman/checks/check_basic_auth_timing_attack.rb +33 -0
  15. data/lib/brakeman/checks/check_content_tag.rb +160 -0
  16. data/lib/brakeman/checks/check_create_with.rb +75 -0
  17. data/lib/brakeman/checks/check_cross_site_scripting.rb +385 -0
  18. data/lib/brakeman/checks/check_default_routes.rb +86 -0
  19. data/lib/brakeman/checks/check_deserialize.rb +57 -0
  20. data/lib/brakeman/checks/check_detailed_exceptions.rb +55 -0
  21. data/lib/brakeman/checks/check_digest_dos.rb +38 -0
  22. data/lib/brakeman/checks/check_dynamic_finders.rb +49 -0
  23. data/lib/brakeman/checks/check_escape_function.rb +21 -0
  24. data/lib/brakeman/checks/check_evaluation.rb +36 -0
  25. data/lib/brakeman/checks/check_execute.rb +167 -0
  26. data/lib/brakeman/checks/check_file_access.rb +63 -0
  27. data/lib/brakeman/checks/check_file_disclosure.rb +35 -0
  28. data/lib/brakeman/checks/check_filter_skipping.rb +31 -0
  29. data/lib/brakeman/checks/check_forgery_setting.rb +74 -0
  30. data/lib/brakeman/checks/check_header_dos.rb +31 -0
  31. data/lib/brakeman/checks/check_i18n_xss.rb +48 -0
  32. data/lib/brakeman/checks/check_jruby_xml.rb +38 -0
  33. data/lib/brakeman/checks/check_json_encoding.rb +47 -0
  34. data/lib/brakeman/checks/check_json_parsing.rb +107 -0
  35. data/lib/brakeman/checks/check_link_to.rb +132 -0
  36. data/lib/brakeman/checks/check_link_to_href.rb +115 -0
  37. data/lib/brakeman/checks/check_mail_to.rb +49 -0
  38. data/lib/brakeman/checks/check_mass_assignment.rb +198 -0
  39. data/lib/brakeman/checks/check_mime_type_dos.rb +39 -0
  40. data/lib/brakeman/checks/check_model_attr_accessible.rb +55 -0
  41. data/lib/brakeman/checks/check_model_attributes.rb +119 -0
  42. data/lib/brakeman/checks/check_model_serialize.rb +67 -0
  43. data/lib/brakeman/checks/check_nested_attributes.rb +38 -0
  44. data/lib/brakeman/checks/check_nested_attributes_bypass.rb +58 -0
  45. data/lib/brakeman/checks/check_number_to_currency.rb +74 -0
  46. data/lib/brakeman/checks/check_quote_table_name.rb +40 -0
  47. data/lib/brakeman/checks/check_redirect.rb +215 -0
  48. data/lib/brakeman/checks/check_regex_dos.rb +69 -0
  49. data/lib/brakeman/checks/check_render.rb +92 -0
  50. data/lib/brakeman/checks/check_render_dos.rb +37 -0
  51. data/lib/brakeman/checks/check_render_inline.rb +54 -0
  52. data/lib/brakeman/checks/check_response_splitting.rb +21 -0
  53. data/lib/brakeman/checks/check_route_dos.rb +42 -0
  54. data/lib/brakeman/checks/check_safe_buffer_manipulation.rb +31 -0
  55. data/lib/brakeman/checks/check_sanitize_methods.rb +79 -0
  56. data/lib/brakeman/checks/check_secrets.rb +40 -0
  57. data/lib/brakeman/checks/check_select_tag.rb +60 -0
  58. data/lib/brakeman/checks/check_select_vulnerability.rb +60 -0
  59. data/lib/brakeman/checks/check_send.rb +48 -0
  60. data/lib/brakeman/checks/check_send_file.rb +19 -0
  61. data/lib/brakeman/checks/check_session_manipulation.rb +36 -0
  62. data/lib/brakeman/checks/check_session_settings.rb +170 -0
  63. data/lib/brakeman/checks/check_simple_format.rb +59 -0
  64. data/lib/brakeman/checks/check_single_quotes.rb +101 -0
  65. data/lib/brakeman/checks/check_skip_before_filter.rb +60 -0
  66. data/lib/brakeman/checks/check_sql.rb +660 -0
  67. data/lib/brakeman/checks/check_sql_cves.rb +101 -0
  68. data/lib/brakeman/checks/check_ssl_verify.rb +49 -0
  69. data/lib/brakeman/checks/check_strip_tags.rb +89 -0
  70. data/lib/brakeman/checks/check_symbol_dos.rb +64 -0
  71. data/lib/brakeman/checks/check_symbol_dos_cve.rb +30 -0
  72. data/lib/brakeman/checks/check_translate_bug.rb +45 -0
  73. data/lib/brakeman/checks/check_unsafe_reflection.rb +51 -0
  74. data/lib/brakeman/checks/check_unscoped_find.rb +41 -0
  75. data/lib/brakeman/checks/check_validation_regex.rb +116 -0
  76. data/lib/brakeman/checks/check_weak_hash.rb +151 -0
  77. data/lib/brakeman/checks/check_without_protection.rb +80 -0
  78. data/lib/brakeman/checks/check_xml_dos.rb +51 -0
  79. data/lib/brakeman/checks/check_yaml_parsing.rb +121 -0
  80. data/lib/brakeman/differ.rb +66 -0
  81. data/lib/brakeman/file_parser.rb +50 -0
  82. data/lib/brakeman/format/style.css +133 -0
  83. data/lib/brakeman/options.rb +301 -0
  84. data/lib/brakeman/parsers/rails2_erubis.rb +6 -0
  85. data/lib/brakeman/parsers/rails2_xss_plugin_erubis.rb +48 -0
  86. data/lib/brakeman/parsers/rails3_erubis.rb +74 -0
  87. data/lib/brakeman/parsers/template_parser.rb +89 -0
  88. data/lib/brakeman/processor.rb +102 -0
  89. data/lib/brakeman/processors/alias_processor.rb +1013 -0
  90. data/lib/brakeman/processors/base_processor.rb +277 -0
  91. data/lib/brakeman/processors/config_processor.rb +14 -0
  92. data/lib/brakeman/processors/controller_alias_processor.rb +273 -0
  93. data/lib/brakeman/processors/controller_processor.rb +326 -0
  94. data/lib/brakeman/processors/erb_template_processor.rb +80 -0
  95. data/lib/brakeman/processors/erubis_template_processor.rb +104 -0
  96. data/lib/brakeman/processors/gem_processor.rb +57 -0
  97. data/lib/brakeman/processors/haml_template_processor.rb +190 -0
  98. data/lib/brakeman/processors/lib/basic_processor.rb +37 -0
  99. data/lib/brakeman/processors/lib/find_all_calls.rb +223 -0
  100. data/lib/brakeman/processors/lib/find_call.rb +183 -0
  101. data/lib/brakeman/processors/lib/find_return_value.rb +134 -0
  102. data/lib/brakeman/processors/lib/processor_helper.rb +75 -0
  103. data/lib/brakeman/processors/lib/rails2_config_processor.rb +145 -0
  104. data/lib/brakeman/processors/lib/rails2_route_processor.rb +313 -0
  105. data/lib/brakeman/processors/lib/rails3_config_processor.rb +132 -0
  106. data/lib/brakeman/processors/lib/rails3_route_processor.rb +308 -0
  107. data/lib/brakeman/processors/lib/render_helper.rb +181 -0
  108. data/lib/brakeman/processors/lib/render_path.rb +107 -0
  109. data/lib/brakeman/processors/lib/route_helper.rb +68 -0
  110. data/lib/brakeman/processors/lib/safe_call_helper.rb +16 -0
  111. data/lib/brakeman/processors/library_processor.rb +119 -0
  112. data/lib/brakeman/processors/model_processor.rb +191 -0
  113. data/lib/brakeman/processors/output_processor.rb +171 -0
  114. data/lib/brakeman/processors/route_processor.rb +17 -0
  115. data/lib/brakeman/processors/slim_template_processor.rb +107 -0
  116. data/lib/brakeman/processors/template_alias_processor.rb +116 -0
  117. data/lib/brakeman/processors/template_processor.rb +74 -0
  118. data/lib/brakeman/report.rb +78 -0
  119. data/lib/brakeman/report/config/remediation.yml +71 -0
  120. data/lib/brakeman/report/ignore/config.rb +135 -0
  121. data/lib/brakeman/report/ignore/interactive.rb +311 -0
  122. data/lib/brakeman/report/renderer.rb +24 -0
  123. data/lib/brakeman/report/report_base.rb +286 -0
  124. data/lib/brakeman/report/report_codeclimate.rb +70 -0
  125. data/lib/brakeman/report/report_csv.rb +55 -0
  126. data/lib/brakeman/report/report_hash.rb +23 -0
  127. data/lib/brakeman/report/report_html.rb +216 -0
  128. data/lib/brakeman/report/report_json.rb +42 -0
  129. data/lib/brakeman/report/report_markdown.rb +156 -0
  130. data/lib/brakeman/report/report_table.rb +107 -0
  131. data/lib/brakeman/report/report_tabs.rb +17 -0
  132. data/lib/brakeman/report/templates/controller_overview.html.erb +22 -0
  133. data/lib/brakeman/report/templates/controller_warnings.html.erb +21 -0
  134. data/lib/brakeman/report/templates/error_overview.html.erb +29 -0
  135. data/lib/brakeman/report/templates/header.html.erb +58 -0
  136. data/lib/brakeman/report/templates/ignored_warnings.html.erb +25 -0
  137. data/lib/brakeman/report/templates/model_warnings.html.erb +21 -0
  138. data/lib/brakeman/report/templates/overview.html.erb +38 -0
  139. data/lib/brakeman/report/templates/security_warnings.html.erb +23 -0
  140. data/lib/brakeman/report/templates/template_overview.html.erb +21 -0
  141. data/lib/brakeman/report/templates/view_warnings.html.erb +34 -0
  142. data/lib/brakeman/report/templates/warning_overview.html.erb +17 -0
  143. data/lib/brakeman/rescanner.rb +483 -0
  144. data/lib/brakeman/scanner.rb +317 -0
  145. data/lib/brakeman/tracker.rb +347 -0
  146. data/lib/brakeman/tracker/collection.rb +93 -0
  147. data/lib/brakeman/tracker/config.rb +101 -0
  148. data/lib/brakeman/tracker/constants.rb +101 -0
  149. data/lib/brakeman/tracker/controller.rb +161 -0
  150. data/lib/brakeman/tracker/library.rb +17 -0
  151. data/lib/brakeman/tracker/model.rb +90 -0
  152. data/lib/brakeman/tracker/template.rb +33 -0
  153. data/lib/brakeman/util.rb +481 -0
  154. data/lib/brakeman/version.rb +3 -0
  155. data/lib/brakeman/warning.rb +255 -0
  156. data/lib/brakeman/warning_codes.rb +111 -0
  157. data/lib/ruby_parser/bm_sexp.rb +610 -0
  158. data/lib/ruby_parser/bm_sexp_processor.rb +116 -0
  159. metadata +362 -0
@@ -0,0 +1,326 @@
1
+ require 'brakeman/processors/base_processor'
2
+ require 'brakeman/tracker/controller'
3
+
4
+ #Processes controller. Results are put in tracker.controllers
5
+ class Brakeman::ControllerProcessor < Brakeman::BaseProcessor
6
+ FORMAT_HTML = Sexp.new(:call, Sexp.new(:lvar, :format), :html)
7
+
8
+ def initialize app_tree, tracker
9
+ super(tracker)
10
+ @app_tree = app_tree
11
+ @current_class = nil
12
+ @current_method = nil
13
+ @current_module = nil
14
+ @visibility = :public
15
+ @file_name = nil
16
+ end
17
+
18
+ #Use this method to process a Controller
19
+ def process_controller src, file_name = nil
20
+ @file_name = file_name
21
+ process src
22
+ end
23
+
24
+ #s(:class, NAME, PARENT, s(:scope ...))
25
+ def process_class exp
26
+ name = class_name(exp.class_name)
27
+ parent = class_name(exp.parent_name)
28
+
29
+ #If inside a real controller, treat any other classes as libraries.
30
+ #But if not inside a controller already, then the class may include
31
+ #a real controller, so we can't take this shortcut.
32
+ if @current_class and @current_class.name.to_s.end_with? "Controller"
33
+ Brakeman.debug "[Notice] Treating inner class as library: #{name}"
34
+ Brakeman::LibraryProcessor.new(@tracker).process_library exp, @file_name
35
+ return exp
36
+ end
37
+
38
+ if not name.to_s.end_with? "Controller"
39
+ Brakeman.debug "[Notice] Adding noncontroller as library: #{name}"
40
+ #Set the class to be a module in order to get the right namespacing.
41
+ #Add class to libraries, in case it is needed later (e.g. it's used
42
+ #as a parent class for a controller.)
43
+ #However, still want to process it in this class, so have to set
44
+ #@current_class to this not-really-a-controller thing.
45
+ process_module exp, parent
46
+
47
+ return exp
48
+ end
49
+
50
+ if @current_class
51
+ outer_class = @current_class
52
+ name = (outer_class.name.to_s + "::" + name.to_s).to_sym
53
+ end
54
+
55
+ if @current_module
56
+ name = (@current_module.name.to_s + "::" + name.to_s).to_sym
57
+ end
58
+
59
+ if @tracker.controllers[name]
60
+ @current_class = @tracker.controllers[name]
61
+ @current_class.add_file @file_name, exp
62
+ else
63
+ @current_class = Brakeman::Controller.new name, parent, @file_name, exp, @tracker
64
+ @tracker.controllers[name] = @current_class
65
+ end
66
+
67
+ exp.body = process_all! exp.body
68
+ set_layout_name
69
+
70
+ if outer_class
71
+ @current_class = outer_class
72
+ else
73
+ @current_class = nil
74
+ end
75
+
76
+ exp
77
+ end
78
+
79
+ def process_module exp, parent = nil
80
+ name = class_name(exp.module_name)
81
+
82
+ if @current_module
83
+ outer_module = @current_module
84
+ name = (outer_module.name.to_s + "::" + name.to_s).to_sym
85
+ end
86
+
87
+ if @current_class
88
+ name = (@current_class.name.to_s + "::" + name.to_s).to_sym
89
+ end
90
+
91
+ if @tracker.libs[name]
92
+ @current_module = @tracker.libs[name]
93
+ @current_module.add_file @file_name, exp
94
+ else
95
+ @current_module = Brakeman::Controller.new name, parent, @file_name, exp, @tracker
96
+ @tracker.libs[name] = @current_module
97
+ end
98
+
99
+ exp.body = process_all! exp.body
100
+
101
+ if outer_module
102
+ @current_module = outer_module
103
+ else
104
+ @current_module = nil
105
+ end
106
+
107
+ exp
108
+ end
109
+
110
+ #Look for specific calls inside the controller
111
+ def process_call exp
112
+ return exp if process_call_defn? exp
113
+
114
+ target = exp.target
115
+ if sexp? target
116
+ target = process target
117
+ end
118
+
119
+ method = exp.method
120
+ first_arg = exp.first_arg
121
+ last_arg = exp.last_arg
122
+
123
+ #Methods called inside class definition
124
+ #like attr_* and other settings
125
+ if @current_method.nil? and target.nil? and @current_class
126
+ if first_arg.nil? #No args
127
+ case method
128
+ when :private, :protected, :public
129
+ @visibility = method
130
+ when :protect_from_forgery
131
+ @current_class.options[:protect_from_forgery] = true
132
+ else
133
+ #??
134
+ end
135
+ else
136
+ case method
137
+ when :include
138
+ @current_class.add_include class_name(first_arg) if @current_class
139
+ when :before_filter, :append_before_filter, :before_action, :append_before_action
140
+ if node_type? exp.first_arg, :iter
141
+ add_lambda_filter exp
142
+ else
143
+ @current_class.add_before_filter exp
144
+ end
145
+ when :prepend_before_filter, :prepend_before_action
146
+ if node_type? exp.first_arg, :iter
147
+ add_lambda_filter exp
148
+ else
149
+ @current_class.prepend_before_filter exp
150
+ end
151
+ when :skip_before_filter, :skip_filter, :skip_before_action, :skip_action_callback
152
+ @current_class.skip_filter exp
153
+ when :layout
154
+ if string? last_arg
155
+ #layout "some_layout"
156
+
157
+ name = last_arg.value.to_s
158
+ if @app_tree.layout_exists?(name)
159
+ @current_class.layout = "layouts/#{name}"
160
+ else
161
+ Brakeman.debug "[Notice] Layout not found: #{name}"
162
+ end
163
+ elsif node_type? last_arg, :nil, :false
164
+ #layout :false or layout nil
165
+ @current_class.layout = false
166
+ end
167
+ else
168
+ @current_class.add_option method, exp
169
+ end
170
+ end
171
+
172
+ exp
173
+ elsif target == nil and method == :render
174
+ make_render exp
175
+ elsif exp == FORMAT_HTML and context[1] != :iter
176
+ #This is an empty call to
177
+ # format.html
178
+ #Which renders the default template if no arguments
179
+ #Need to make more generic, though.
180
+ call = Sexp.new :render, :default, @current_method
181
+ call.line(exp.line)
182
+ call
183
+ else
184
+ call = make_call target, method, process_all!(exp.args)
185
+ call.line(exp.line)
186
+ call
187
+ end
188
+ end
189
+
190
+ #Process method definition and store in Tracker
191
+ def process_defn exp
192
+ name = exp.method_name
193
+ @current_method = name
194
+ res = Sexp.new :defn, name, exp.formal_args, *process_all!(exp.body)
195
+ res.line(exp.line)
196
+ @current_method = nil
197
+
198
+ if @current_class
199
+ @current_class.add_method @visibility, name, res, @file_name
200
+ elsif @current_module
201
+ @current_module.add_method @visibility, name, res, @file_name
202
+ end
203
+
204
+ res
205
+ end
206
+
207
+ #Process self.method definition and store in Tracker
208
+ def process_defs exp
209
+ name = exp.method_name
210
+
211
+ if node_type? exp[1], :self
212
+ if @current_class
213
+ target = @current_class.name
214
+ elsif @current_module
215
+ target = @current_module.name
216
+ else
217
+ target = nil
218
+ end
219
+ else
220
+ target = class_name exp[1]
221
+ end
222
+
223
+ @current_method = name
224
+ res = Sexp.new :defs, target, name, exp.formal_args, *process_all!(exp.body)
225
+ res.line(exp.line)
226
+ @current_method = nil
227
+
228
+ if @current_class
229
+ @current_class.add_method @visibility, name, res, @file_name
230
+ elsif @current_module
231
+ @current_module.add_method @visibility, name, res, @file_name
232
+ end
233
+
234
+ res
235
+ end
236
+
237
+ #Look for before_filters and add fake ones if necessary
238
+ def process_iter exp
239
+ if @current_method.nil? and call? exp.block_call
240
+ block_call_name = exp.block_call.method
241
+
242
+ if block_call_name == :before_filter or block_call_name == :before_action
243
+ add_fake_filter exp
244
+ else
245
+ super
246
+ end
247
+ else
248
+ super
249
+ end
250
+ end
251
+
252
+ #Sets default layout for renders inside Controller
253
+ def set_layout_name
254
+ return if @current_class.layout
255
+
256
+ name = underscore(@current_class.name.to_s.split("::")[-1].gsub("Controller", ''))
257
+
258
+ #There is a layout for this Controller
259
+ if @app_tree.layout_exists?(name)
260
+ @current_class.layout = "layouts/#{name}"
261
+ end
262
+ end
263
+
264
+ #This is to handle before_filter do |controller| ... end
265
+ #
266
+ #We build a new method and process that the same way as usual
267
+ #methods and filters.
268
+ def add_fake_filter exp
269
+ unless @current_class
270
+ Brakeman.debug "Skipping before_filter outside controller: #{exp}"
271
+ return exp
272
+ end
273
+
274
+ filter_name = ("fake_filter" + rand.to_s[/\d+$/]).to_sym
275
+ args = exp.block_call.arglist
276
+ args.insert(1, Sexp.new(:lit, filter_name))
277
+ before_filter_call = make_call(nil, :before_filter, args)
278
+
279
+ if exp.block_args.length > 1
280
+ block_variable = exp.block_args[1]
281
+ else
282
+ block_variable = :temp
283
+ end
284
+
285
+ if node_type? exp.block, :block
286
+ block_inner = exp.block[1..-1]
287
+ else
288
+ block_inner = [exp.block]
289
+ end
290
+
291
+ #Build Sexp for filter method
292
+ body = Sexp.new(:lasgn,
293
+ block_variable,
294
+ Sexp.new(:call, Sexp.new(:const, @current_class.name), :new))
295
+
296
+ filter_method = Sexp.new(:defn, filter_name, Sexp.new(:args), body).concat(block_inner).line(exp.line)
297
+
298
+ vis = @visibility
299
+ @visibility = :private
300
+ process_defn filter_method
301
+ @visibility = vis
302
+ process before_filter_call
303
+ exp
304
+ end
305
+
306
+ def add_lambda_filter exp
307
+ # Convert into regular block call
308
+ e = exp.dup
309
+ lambda_node = e.delete_at(3)
310
+ result = Sexp.new(:iter, e).line(e.line)
311
+
312
+ # Add block arguments
313
+ if node_type? lambda_node[2], :args
314
+ result << lambda_node[2].last
315
+ else
316
+ result << s(:args)
317
+ end
318
+
319
+ # Add block contents
320
+ if sexp? lambda_node[3]
321
+ result << lambda_node[3]
322
+ end
323
+
324
+ add_fake_filter result
325
+ end
326
+ end
@@ -0,0 +1,80 @@
1
+ require 'brakeman/processors/template_processor'
2
+
3
+ #Processes ERB templates
4
+ #(those ending in .html.erb or .rthml).
5
+ class Brakeman::ErbTemplateProcessor < Brakeman::TemplateProcessor
6
+
7
+ #s(:call, TARGET, :method, ARGS)
8
+ def process_call exp
9
+ target = exp.target
10
+ if sexp? target
11
+ target = process target
12
+ end
13
+ method = exp.method
14
+
15
+ #_erbout is the default output variable for erb
16
+ if node_type? target, :lvar and target.value == :_erbout
17
+ if method == :concat
18
+ @inside_concat = true
19
+ exp.arglist = process(exp.arglist)
20
+ @inside_concat = false
21
+
22
+ if exp.second_arg
23
+ raise "Did not expect more than a single argument to _erbout.concat"
24
+ end
25
+
26
+ arg = normalize_output(exp.first_arg)
27
+
28
+ if arg.node_type == :str #ignore plain strings
29
+ ignore
30
+ else
31
+ s = Sexp.new :output, arg
32
+ s.line(exp.line)
33
+ @current_template.add_output s
34
+ s
35
+ end
36
+ elsif method == :force_encoding
37
+ ignore
38
+ else
39
+ abort "Unrecognized action on _erbout: #{method}"
40
+ end
41
+ elsif target == nil and method == :render
42
+ exp.arglist = process(exp.arglist)
43
+ make_render_in_view exp
44
+ else
45
+ exp.target = target
46
+ exp.arglist = process(exp.arglist)
47
+ exp
48
+ end
49
+ end
50
+
51
+ #Process block, removing irrelevant expressions
52
+ def process_block exp
53
+ exp = exp.dup
54
+ exp.shift
55
+ if @inside_concat
56
+ @inside_concat = false
57
+ exp[0..-2].each do |e|
58
+ process e
59
+ end
60
+ @inside_concat = true
61
+ process exp.last
62
+ else
63
+ exp.map! do |e|
64
+ res = process e
65
+ if res.empty? or res == ignore
66
+ nil
67
+ elsif node_type?(res, :lvar) and res.value == :_erbout
68
+ nil
69
+
70
+ else
71
+ res
72
+ end
73
+ end
74
+ block = Sexp.new(:rlist).concat(exp).compact
75
+ block.line(exp.line)
76
+ block
77
+ end
78
+ end
79
+
80
+ end
@@ -0,0 +1,104 @@
1
+ require 'brakeman/processors/template_processor'
2
+
3
+ #Processes ERB templates using Erubis instead of erb.
4
+ class Brakeman::ErubisTemplateProcessor < Brakeman::TemplateProcessor
5
+
6
+ #s(:call, TARGET, :method, ARGS)
7
+ def process_call exp
8
+ target = exp.target
9
+ if sexp? target
10
+ target = process target
11
+ end
12
+
13
+ exp.target = target
14
+ exp.arglist = process exp.arglist
15
+ method = exp.method
16
+
17
+ #_buf is the default output variable for Erubis
18
+ if node_type?(target, :lvar, :ivar) and (target.value == :_buf or target.value == :@output_buffer)
19
+ if method == :<< or method == :safe_concat
20
+
21
+ arg = normalize_output(exp.first_arg)
22
+
23
+ if arg.node_type == :str #ignore plain strings
24
+ ignore
25
+ elsif node_type? target, :ivar and target.value == :@output_buffer
26
+ s = Sexp.new :escaped_output, arg
27
+ s.line(exp.line)
28
+ @current_template.add_output s
29
+ s
30
+ else
31
+ s = Sexp.new :output, arg
32
+ s.line(exp.line)
33
+ @current_template.add_output s
34
+ s
35
+ end
36
+ elsif method == :to_s
37
+ ignore
38
+ else
39
+ abort "Unrecognized action on buffer: #{method}"
40
+ end
41
+ elsif target == nil and method == :render
42
+ make_render_in_view exp
43
+ else
44
+ exp
45
+ end
46
+ end
47
+
48
+ #Process blocks, ignoring :ignore exps
49
+ def process_block exp
50
+ exp = exp.dup
51
+ exp.shift
52
+ exp.map! do |e|
53
+ res = process e
54
+ if res.empty? or res == ignore
55
+ nil
56
+ else
57
+ res
58
+ end
59
+ end
60
+ block = Sexp.new(:rlist).concat(exp).compact
61
+ block.line(exp.line)
62
+ block
63
+ end
64
+
65
+ #Look for assignments to output buffer that look like this:
66
+ # @output_buffer.append = some_output
67
+ # @output_buffer.safe_append = some_output
68
+ # @output_buffer.safe_expr_append = some_output
69
+ def process_attrasgn exp
70
+ if exp.target.node_type == :ivar and exp.target.value == :@output_buffer
71
+ if append_method?(exp.method)
72
+ exp.first_arg = process(exp.first_arg)
73
+ arg = normalize_output(exp.first_arg)
74
+
75
+ if arg.node_type == :str
76
+ ignore
77
+ elsif safe_append_method?(exp.method)
78
+ s = Sexp.new :output, arg
79
+ s.line(exp.line)
80
+ @current_template.add_output s
81
+ s
82
+ else
83
+ s = Sexp.new :escaped_output, arg
84
+ s.line(exp.line)
85
+ @current_template.add_output s
86
+ s
87
+ end
88
+ else
89
+ super
90
+ end
91
+ else
92
+ super
93
+ end
94
+ end
95
+
96
+ private
97
+ def append_method?(method)
98
+ method == :append= || safe_append_method?(method)
99
+ end
100
+
101
+ def safe_append_method?(method)
102
+ method == :safe_append= || method == :safe_expr_append=
103
+ end
104
+ end