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.
- checksums.yaml +7 -0
- data/CHANGES +872 -0
- data/FEATURES +16 -0
- data/README.md +169 -0
- data/WARNING_TYPES +95 -0
- data/bin/brakeman +89 -0
- data/lib/brakeman.rb +495 -0
- data/lib/brakeman/app_tree.rb +161 -0
- data/lib/brakeman/brakeman.rake +17 -0
- data/lib/brakeman/call_index.rb +219 -0
- data/lib/brakeman/checks.rb +191 -0
- data/lib/brakeman/checks/base_check.rb +518 -0
- data/lib/brakeman/checks/check_basic_auth.rb +88 -0
- data/lib/brakeman/checks/check_basic_auth_timing_attack.rb +33 -0
- data/lib/brakeman/checks/check_content_tag.rb +160 -0
- data/lib/brakeman/checks/check_create_with.rb +75 -0
- data/lib/brakeman/checks/check_cross_site_scripting.rb +385 -0
- data/lib/brakeman/checks/check_default_routes.rb +86 -0
- data/lib/brakeman/checks/check_deserialize.rb +57 -0
- data/lib/brakeman/checks/check_detailed_exceptions.rb +55 -0
- data/lib/brakeman/checks/check_digest_dos.rb +38 -0
- data/lib/brakeman/checks/check_dynamic_finders.rb +49 -0
- data/lib/brakeman/checks/check_escape_function.rb +21 -0
- data/lib/brakeman/checks/check_evaluation.rb +36 -0
- data/lib/brakeman/checks/check_execute.rb +167 -0
- data/lib/brakeman/checks/check_file_access.rb +63 -0
- data/lib/brakeman/checks/check_file_disclosure.rb +35 -0
- data/lib/brakeman/checks/check_filter_skipping.rb +31 -0
- data/lib/brakeman/checks/check_forgery_setting.rb +74 -0
- data/lib/brakeman/checks/check_header_dos.rb +31 -0
- data/lib/brakeman/checks/check_i18n_xss.rb +48 -0
- data/lib/brakeman/checks/check_jruby_xml.rb +38 -0
- data/lib/brakeman/checks/check_json_encoding.rb +47 -0
- data/lib/brakeman/checks/check_json_parsing.rb +107 -0
- data/lib/brakeman/checks/check_link_to.rb +132 -0
- data/lib/brakeman/checks/check_link_to_href.rb +115 -0
- data/lib/brakeman/checks/check_mail_to.rb +49 -0
- data/lib/brakeman/checks/check_mass_assignment.rb +198 -0
- data/lib/brakeman/checks/check_mime_type_dos.rb +39 -0
- data/lib/brakeman/checks/check_model_attr_accessible.rb +55 -0
- data/lib/brakeman/checks/check_model_attributes.rb +119 -0
- data/lib/brakeman/checks/check_model_serialize.rb +67 -0
- data/lib/brakeman/checks/check_nested_attributes.rb +38 -0
- data/lib/brakeman/checks/check_nested_attributes_bypass.rb +58 -0
- data/lib/brakeman/checks/check_number_to_currency.rb +74 -0
- data/lib/brakeman/checks/check_quote_table_name.rb +40 -0
- data/lib/brakeman/checks/check_redirect.rb +215 -0
- data/lib/brakeman/checks/check_regex_dos.rb +69 -0
- data/lib/brakeman/checks/check_render.rb +92 -0
- data/lib/brakeman/checks/check_render_dos.rb +37 -0
- data/lib/brakeman/checks/check_render_inline.rb +54 -0
- data/lib/brakeman/checks/check_response_splitting.rb +21 -0
- data/lib/brakeman/checks/check_route_dos.rb +42 -0
- data/lib/brakeman/checks/check_safe_buffer_manipulation.rb +31 -0
- data/lib/brakeman/checks/check_sanitize_methods.rb +79 -0
- data/lib/brakeman/checks/check_secrets.rb +40 -0
- data/lib/brakeman/checks/check_select_tag.rb +60 -0
- data/lib/brakeman/checks/check_select_vulnerability.rb +60 -0
- data/lib/brakeman/checks/check_send.rb +48 -0
- data/lib/brakeman/checks/check_send_file.rb +19 -0
- data/lib/brakeman/checks/check_session_manipulation.rb +36 -0
- data/lib/brakeman/checks/check_session_settings.rb +170 -0
- data/lib/brakeman/checks/check_simple_format.rb +59 -0
- data/lib/brakeman/checks/check_single_quotes.rb +101 -0
- data/lib/brakeman/checks/check_skip_before_filter.rb +60 -0
- data/lib/brakeman/checks/check_sql.rb +660 -0
- data/lib/brakeman/checks/check_sql_cves.rb +101 -0
- data/lib/brakeman/checks/check_ssl_verify.rb +49 -0
- data/lib/brakeman/checks/check_strip_tags.rb +89 -0
- data/lib/brakeman/checks/check_symbol_dos.rb +64 -0
- data/lib/brakeman/checks/check_symbol_dos_cve.rb +30 -0
- data/lib/brakeman/checks/check_translate_bug.rb +45 -0
- data/lib/brakeman/checks/check_unsafe_reflection.rb +51 -0
- data/lib/brakeman/checks/check_unscoped_find.rb +41 -0
- data/lib/brakeman/checks/check_validation_regex.rb +116 -0
- data/lib/brakeman/checks/check_weak_hash.rb +151 -0
- data/lib/brakeman/checks/check_without_protection.rb +80 -0
- data/lib/brakeman/checks/check_xml_dos.rb +51 -0
- data/lib/brakeman/checks/check_yaml_parsing.rb +121 -0
- data/lib/brakeman/differ.rb +66 -0
- data/lib/brakeman/file_parser.rb +50 -0
- data/lib/brakeman/format/style.css +133 -0
- data/lib/brakeman/options.rb +301 -0
- data/lib/brakeman/parsers/rails2_erubis.rb +6 -0
- data/lib/brakeman/parsers/rails2_xss_plugin_erubis.rb +48 -0
- data/lib/brakeman/parsers/rails3_erubis.rb +74 -0
- data/lib/brakeman/parsers/template_parser.rb +89 -0
- data/lib/brakeman/processor.rb +102 -0
- data/lib/brakeman/processors/alias_processor.rb +1013 -0
- data/lib/brakeman/processors/base_processor.rb +277 -0
- data/lib/brakeman/processors/config_processor.rb +14 -0
- data/lib/brakeman/processors/controller_alias_processor.rb +273 -0
- data/lib/brakeman/processors/controller_processor.rb +326 -0
- data/lib/brakeman/processors/erb_template_processor.rb +80 -0
- data/lib/brakeman/processors/erubis_template_processor.rb +104 -0
- data/lib/brakeman/processors/gem_processor.rb +57 -0
- data/lib/brakeman/processors/haml_template_processor.rb +190 -0
- data/lib/brakeman/processors/lib/basic_processor.rb +37 -0
- data/lib/brakeman/processors/lib/find_all_calls.rb +223 -0
- data/lib/brakeman/processors/lib/find_call.rb +183 -0
- data/lib/brakeman/processors/lib/find_return_value.rb +134 -0
- data/lib/brakeman/processors/lib/processor_helper.rb +75 -0
- data/lib/brakeman/processors/lib/rails2_config_processor.rb +145 -0
- data/lib/brakeman/processors/lib/rails2_route_processor.rb +313 -0
- data/lib/brakeman/processors/lib/rails3_config_processor.rb +132 -0
- data/lib/brakeman/processors/lib/rails3_route_processor.rb +308 -0
- data/lib/brakeman/processors/lib/render_helper.rb +181 -0
- data/lib/brakeman/processors/lib/render_path.rb +107 -0
- data/lib/brakeman/processors/lib/route_helper.rb +68 -0
- data/lib/brakeman/processors/lib/safe_call_helper.rb +16 -0
- data/lib/brakeman/processors/library_processor.rb +119 -0
- data/lib/brakeman/processors/model_processor.rb +191 -0
- data/lib/brakeman/processors/output_processor.rb +171 -0
- data/lib/brakeman/processors/route_processor.rb +17 -0
- data/lib/brakeman/processors/slim_template_processor.rb +107 -0
- data/lib/brakeman/processors/template_alias_processor.rb +116 -0
- data/lib/brakeman/processors/template_processor.rb +74 -0
- data/lib/brakeman/report.rb +78 -0
- data/lib/brakeman/report/config/remediation.yml +71 -0
- data/lib/brakeman/report/ignore/config.rb +135 -0
- data/lib/brakeman/report/ignore/interactive.rb +311 -0
- data/lib/brakeman/report/renderer.rb +24 -0
- data/lib/brakeman/report/report_base.rb +286 -0
- data/lib/brakeman/report/report_codeclimate.rb +70 -0
- data/lib/brakeman/report/report_csv.rb +55 -0
- data/lib/brakeman/report/report_hash.rb +23 -0
- data/lib/brakeman/report/report_html.rb +216 -0
- data/lib/brakeman/report/report_json.rb +42 -0
- data/lib/brakeman/report/report_markdown.rb +156 -0
- data/lib/brakeman/report/report_table.rb +107 -0
- data/lib/brakeman/report/report_tabs.rb +17 -0
- data/lib/brakeman/report/templates/controller_overview.html.erb +22 -0
- data/lib/brakeman/report/templates/controller_warnings.html.erb +21 -0
- data/lib/brakeman/report/templates/error_overview.html.erb +29 -0
- data/lib/brakeman/report/templates/header.html.erb +58 -0
- data/lib/brakeman/report/templates/ignored_warnings.html.erb +25 -0
- data/lib/brakeman/report/templates/model_warnings.html.erb +21 -0
- data/lib/brakeman/report/templates/overview.html.erb +38 -0
- data/lib/brakeman/report/templates/security_warnings.html.erb +23 -0
- data/lib/brakeman/report/templates/template_overview.html.erb +21 -0
- data/lib/brakeman/report/templates/view_warnings.html.erb +34 -0
- data/lib/brakeman/report/templates/warning_overview.html.erb +17 -0
- data/lib/brakeman/rescanner.rb +483 -0
- data/lib/brakeman/scanner.rb +317 -0
- data/lib/brakeman/tracker.rb +347 -0
- data/lib/brakeman/tracker/collection.rb +93 -0
- data/lib/brakeman/tracker/config.rb +101 -0
- data/lib/brakeman/tracker/constants.rb +101 -0
- data/lib/brakeman/tracker/controller.rb +161 -0
- data/lib/brakeman/tracker/library.rb +17 -0
- data/lib/brakeman/tracker/model.rb +90 -0
- data/lib/brakeman/tracker/template.rb +33 -0
- data/lib/brakeman/util.rb +481 -0
- data/lib/brakeman/version.rb +3 -0
- data/lib/brakeman/warning.rb +255 -0
- data/lib/brakeman/warning_codes.rb +111 -0
- data/lib/ruby_parser/bm_sexp.rb +610 -0
- data/lib/ruby_parser/bm_sexp_processor.rb +116 -0
- 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
|