brakeman 1.1.0 → 1.2.0

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.
@@ -30,12 +30,12 @@ class Brakeman::Scanner
30
30
  RUBY_1_9 = !!(RUBY_VERSION =~ /^1\.9/)
31
31
 
32
32
  #Pass in path to the root of the Rails application
33
- def initialize options
33
+ def initialize options, processor = nil
34
34
  @options = options
35
35
  @report_progress = options[:report_progress]
36
36
  @path = options[:app_path]
37
37
  @app_path = File.join(@path, "app")
38
- @processor = Brakeman::Processor.new options
38
+ @processor = processor || Brakeman::Processor.new(options)
39
39
 
40
40
  if RUBY_1_9
41
41
  @ruby_parser = ::Ruby19Parser
@@ -124,13 +124,18 @@ class Brakeman::Scanner
124
124
  #Adds parsed information to tracker.initializers
125
125
  def process_initializers
126
126
  Dir.glob(@path + "/config/initializers/**/*.rb").sort.each do |f|
127
- begin
128
- @processor.process_initializer(f, parse_ruby(File.read(f)))
129
- rescue Racc::ParseError => e
130
- tracker.error e, "could not parse #{f}. There is probably a typo in the file. Test it with 'ruby_parse #{f}'"
131
- rescue Exception => e
132
- tracker.error e.exception(e.message + "\nWhile processing #{f}"), e.backtrace
133
- end
127
+ process_initializer f
128
+ end
129
+ end
130
+
131
+ #Process an initializer
132
+ def process_initializer path
133
+ begin
134
+ @processor.process_initializer(path, parse_ruby(File.read(path)))
135
+ rescue Racc::ParseError => e
136
+ tracker.error e, "could not parse #{path}. There is probably a typo in the file. Test it with 'ruby_parse #{path}'"
137
+ rescue Exception => e
138
+ tracker.error e.exception(e.message + "\nWhile processing #{path}"), e.backtrace
134
139
  end
135
140
  end
136
141
 
@@ -154,13 +159,18 @@ class Brakeman::Scanner
154
159
  current += 1
155
160
  end
156
161
 
157
- begin
158
- @processor.process_lib parse_ruby(File.read(f)), f
159
- rescue Racc::ParseError => e
160
- tracker.error e, "could not parse #{f}. There is probably a typo in the file. Test it with 'ruby_parse #{f}'"
161
- rescue Exception => e
162
- tracker.error e.exception(e.message + "\nWhile processing #{f}"), e.backtrace
163
- end
162
+ process_lib f
163
+ end
164
+ end
165
+
166
+ #Process a library
167
+ def process_lib path
168
+ begin
169
+ @processor.process_lib parse_ruby(File.read(path)), path
170
+ rescue Racc::ParseError => e
171
+ tracker.error e, "could not parse #{path}. There is probably a typo in the file. Test it with 'ruby_parse #{path}'"
172
+ rescue Exception => e
173
+ tracker.error e.exception(e.message + "\nWhile processing #{path}"), e.backtrace
164
174
  end
165
175
  end
166
176
 
@@ -196,13 +206,7 @@ class Brakeman::Scanner
196
206
  current += 1
197
207
  end
198
208
 
199
- begin
200
- @processor.process_controller(parse_ruby(File.read(f)), f)
201
- rescue Racc::ParseError => e
202
- tracker.error e, "could not parse #{f}. There is probably a typo in the file. Test it with 'ruby_parse #{f}'"
203
- rescue Exception => e
204
- tracker.error e.exception(e.message + "\nWhile processing #{f}"), e.backtrace
205
- end
209
+ process_controller f
206
210
  end
207
211
 
208
212
  current = 0
@@ -220,6 +224,16 @@ class Brakeman::Scanner
220
224
  end
221
225
  end
222
226
 
227
+ def process_controller path
228
+ begin
229
+ @processor.process_controller(parse_ruby(File.read(path)), path)
230
+ rescue Racc::ParseError => e
231
+ tracker.error e, "could not parse #{path}. There is probably a typo in the file. Test it with 'ruby_parse #{path}'"
232
+ rescue Exception => e
233
+ tracker.error e.exception(e.message + "\nWhile processing #{path}"), e.backtrace
234
+ end
235
+ end
236
+
223
237
  #Process all views and partials in views/
224
238
  #
225
239
  #Adds processed views to tracker.views
@@ -232,52 +246,13 @@ class Brakeman::Scanner
232
246
  template_files = Dir.glob(views_path).sort
233
247
  total = template_files.length
234
248
 
235
- template_files.each do |f|
249
+ template_files.each do |path|
236
250
  if @report_progress
237
251
  $stderr.print " #{count}/#{total} files processed\r"
238
252
  count += 1
239
253
  end
240
254
 
241
- type = f.match(/.*\.(erb|haml|rhtml)$/)[1].to_sym
242
- type = :erb if type == :rhtml
243
- name = template_path_to_name f
244
- text = File.read f
245
-
246
- begin
247
- if type == :erb
248
- if tracker.config[:escape_html]
249
- type = :erubis
250
- if options[:rails3]
251
- src = Brakeman::RailsXSSErubis.new(text).src
252
- else
253
- src = Brakeman::ErubisEscape.new(text).src
254
- end
255
- elsif tracker.config[:erubis]
256
- type = :erubis
257
- src = Brakeman::ScannerErubis.new(text).src
258
- else
259
- src = ERB.new(text, nil, "-").src
260
- src.sub!(/^#.*\n/, '') if RUBY_1_9
261
- end
262
-
263
- parsed = parse_ruby src
264
- elsif type == :haml
265
- src = Haml::Engine.new(text,
266
- :escape_html => !!tracker.config[:escape_html]).precompiled
267
- parsed = parse_ruby src
268
- else
269
- tracker.error "Unkown template type in #{f}"
270
- end
271
-
272
- @processor.process_template(name, parsed, type, nil, f)
273
-
274
- rescue Racc::ParseError => e
275
- tracker.error e, "could not parse #{f}"
276
- rescue Haml::Error => e
277
- tracker.error e, ["While compiling HAML in #{f}"] << e.backtrace
278
- rescue Exception => e
279
- tracker.error e.exception(e.message + "\nWhile processing #{f}"), e.backtrace
280
- end
255
+ process_template path
281
256
  end
282
257
 
283
258
  total = tracker.templates.length
@@ -293,7 +268,49 @@ class Brakeman::Scanner
293
268
 
294
269
  @processor.process_template_alias tracker.templates[name]
295
270
  end
271
+ end
272
+
273
+ def process_template path
274
+ type = path.match(/.*\.(erb|haml|rhtml)$/)[1].to_sym
275
+ type = :erb if type == :rhtml
276
+ name = template_path_to_name path
277
+ text = File.read path
278
+
279
+ begin
280
+ if type == :erb
281
+ if tracker.config[:escape_html]
282
+ type = :erubis
283
+ if options[:rails3]
284
+ src = Brakeman::RailsXSSErubis.new(text).src
285
+ else
286
+ src = Brakeman::ErubisEscape.new(text).src
287
+ end
288
+ elsif tracker.config[:erubis]
289
+ type = :erubis
290
+ src = Brakeman::ScannerErubis.new(text).src
291
+ else
292
+ src = ERB.new(text, nil, "-").src
293
+ src.sub!(/^#.*\n/, '') if RUBY_1_9
294
+ end
295
+
296
+ parsed = parse_ruby src
297
+ elsif type == :haml
298
+ src = Haml::Engine.new(text,
299
+ :escape_html => !!tracker.config[:escape_html]).precompiled
300
+ parsed = parse_ruby src
301
+ else
302
+ tracker.error "Unkown template type in #{path}"
303
+ end
296
304
 
305
+ @processor.process_template(name, parsed, type, nil, path)
306
+
307
+ rescue Racc::ParseError => e
308
+ tracker.error e, "could not parse #{path}"
309
+ rescue Haml::Error => e
310
+ tracker.error e, ["While compiling HAML in #{path}"] << e.backtrace
311
+ rescue Exception => e
312
+ tracker.error e.exception(e.message + "\nWhile processing #{path}"), e.backtrace
313
+ end
297
314
  end
298
315
 
299
316
  #Convert path/filename to view name
@@ -320,13 +337,18 @@ class Brakeman::Scanner
320
337
  current += 1
321
338
  end
322
339
 
323
- begin
324
- @processor.process_model(parse_ruby(File.read(f)), f)
325
- rescue Racc::ParseError => e
326
- tracker.error e, "could not parse #{f}"
327
- rescue Exception => e
328
- tracker.error e.exception(e.message + "\nWhile processing #{f}"), e.backtrace
329
- end
340
+ process_model f
341
+
342
+ end
343
+ end
344
+
345
+ def process_model path
346
+ begin
347
+ @processor.process_model(parse_ruby(File.read(path)), path)
348
+ rescue Racc::ParseError => e
349
+ tracker.error e, "could not parse #{path}"
350
+ rescue Exception => e
351
+ tracker.error e.exception(e.message + "\nWhile processing #{path}"), e.backtrace
330
352
  end
331
353
  end
332
354
 
@@ -335,11 +357,7 @@ class Brakeman::Scanner
335
357
  end
336
358
 
337
359
  def parse_ruby input
338
- if RUBY_1_9
339
- Ruby19Parser.new.parse input
340
- else
341
- Ruby18Parser.new.parse input
342
- end
360
+ @ruby_parser.new.parse input
343
361
  end
344
362
  end
345
363
 
@@ -67,7 +67,7 @@ class Brakeman::Tracker
67
67
  [self.controllers, self.models].each do |set|
68
68
  set.each do |set_name, info|
69
69
  [:private, :public, :protected].each do |visibility|
70
- info[visibility].each do |method_name, definition|
70
+ info[visibility].each do |method_name, definition|
71
71
  if definition.node_type == :selfdef
72
72
  method_name = "#{definition[1]}.#{method_name}"
73
73
  end
@@ -118,7 +118,7 @@ class Brakeman::Tracker
118
118
  # User.human.active.all(...)
119
119
  #
120
120
  def find_call options
121
- index_calls unless @call_index
121
+ index_call_sites unless @call_index
122
122
  @call_index.find_calls options
123
123
  end
124
124
 
@@ -151,4 +151,105 @@ class Brakeman::Tracker
151
151
 
152
152
  @call_index = Brakeman::CallIndex.new finder.calls
153
153
  end
154
+
155
+ #Reindex call sites
156
+ #
157
+ #Takes a set of symbols which can include :templates, :models,
158
+ #or :controllers
159
+ #
160
+ #This will limit reindexing to the given sets
161
+ def reindex_call_sites locations
162
+ #If reindexing templates, models, and controllers, just redo
163
+ #everything
164
+ if locations.length == 3
165
+ return index_call_sites
166
+ end
167
+
168
+ if locations.include? :templates
169
+ @call_index.remove_template_indexes
170
+ end
171
+
172
+ classes_to_reindex = Set.new
173
+ method_sets = []
174
+
175
+ if locations.include? :models
176
+ classes_to_reindex.merge self.models.keys
177
+ method_sets << self.models
178
+ end
179
+
180
+ if locations.include? :controllers
181
+ classes_to_reindex.merge self.controllers.keys
182
+ method_sets << self.controllers
183
+ end
184
+
185
+ @call_index.remove_indexes_by_class classes_to_reindex
186
+
187
+ finder = Brakeman::FindAllCalls.new self
188
+
189
+ method_sets.each do |set|
190
+ set.each do |set_name, info|
191
+ [:private, :public, :protected].each do |visibility|
192
+ info[visibility].each do |method_name, definition|
193
+ if definition.node_type == :selfdef
194
+ method_name = "#{definition[1]}.#{method_name}"
195
+ end
196
+
197
+ finder.process_source definition, set_name, method_name
198
+
199
+ end
200
+ end
201
+ end
202
+ end
203
+
204
+ if locations.include? :templates
205
+ self.each_template do |name, template|
206
+ finder.process_source template[:src], nil, nil, template
207
+ end
208
+ end
209
+
210
+ @call_index.index_calls finder.calls
211
+ end
212
+
213
+ #Clear information related to templates.
214
+ #If :only_rendered => true, will delete templates rendered from
215
+ #controllers (but not those rendered from other templates)
216
+ def reset_templates options = { :only_rendered => false }
217
+ if options[:only_rendered]
218
+ @templates.delete_if do |name, template|
219
+ name.to_s.include? "Controller#"
220
+ end
221
+ else
222
+ @templates = {}
223
+ end
224
+ @processed = nil
225
+ @rest = nil
226
+ @template_cache.clear
227
+ end
228
+
229
+ #Clear information related to template
230
+ def reset_template name
231
+ name = name.to_sym
232
+ @templates.delete name
233
+ @processed = nil
234
+ @rest = nil
235
+ end
236
+
237
+ #Clear information related to model
238
+ def reset_model path
239
+ model_name = nil
240
+
241
+ @models.each do |name, model|
242
+ if model[:file] == path
243
+ model_name = name
244
+ break
245
+ end
246
+ end
247
+
248
+ @models.delete model_name
249
+ end
250
+
251
+ #Clear information about routes
252
+ def reset_routes
253
+ @routes = {}
254
+ end
154
255
  end
data/lib/brakeman/util.rb CHANGED
@@ -186,4 +186,110 @@ module Brakeman::Util
186
186
  def sexp? exp
187
187
  exp.is_a? Sexp
188
188
  end
189
+
190
+ #Return file name related to given warning. Uses +warning.file+ if it exists
191
+ def file_for warning, tracker = nil
192
+ if tracker.nil?
193
+ tracker = @tracker || self.tracker
194
+ end
195
+
196
+ if warning.file
197
+ File.expand_path warning.file, tracker.options[:app_path]
198
+ else
199
+ case warning.warning_set
200
+ when :controller
201
+ file_by_name warning.controller, :controller, tracker
202
+ when :template
203
+ file_by_name warning.template[:name], :template, tracker
204
+ when :model
205
+ file_by_name warning.model, :model, tracker
206
+ when :warning
207
+ file_by_name warning.class, nil, tracker
208
+ else
209
+ nil
210
+ end
211
+ end
212
+ end
213
+
214
+ #Attempt to determine path to context file based on the reported name
215
+ #in the warning.
216
+ #
217
+ #For example,
218
+ #
219
+ # file_by_name FileController #=> "/rails/root/app/controllers/file_controller.rb
220
+ def file_by_name name, type, tracker = nil
221
+ return nil unless name
222
+ string_name = name.to_s
223
+ name = name.to_sym
224
+
225
+ unless type
226
+ if string_name =~ /Controller$/
227
+ type = :controller
228
+ elsif camelize(string_name) == string_name
229
+ type = :model
230
+ else
231
+ type = :template
232
+ end
233
+ end
234
+
235
+ path = tracker.options[:app_path]
236
+
237
+ case type
238
+ when :controller
239
+ if tracker.controllers[name] and tracker.controllers[name][:file]
240
+ path = tracker.controllers[name][:file]
241
+ else
242
+ path += "/app/controllers/#{underscore(string_name)}.rb"
243
+ end
244
+ when :model
245
+ if tracker.models[name] and tracker.models[name][:file]
246
+ path = tracker.models[name][:file]
247
+ else
248
+ path += "/app/controllers/#{underscore(string_name)}.rb"
249
+ end
250
+ when :template
251
+ if tracker.templates[name] and tracker.templates[name][:file]
252
+ path = tracker.templates[name][:file]
253
+ elsif string_name.include? " "
254
+ name = string_name.split[0].to_sym
255
+ path = file_for tracker, name, :template
256
+ else
257
+ path = nil
258
+ end
259
+ end
260
+
261
+ path
262
+ end
263
+
264
+ #Return array of lines surrounding the warning location from the original
265
+ #file.
266
+ def context_for warning, tracker = nil
267
+ file = file_for warning, tracker
268
+ context = []
269
+ return context unless warning.line and file and File.exist? file
270
+
271
+ current_line = 0
272
+ start_line = warning.line - 5
273
+ end_line = warning.line + 5
274
+
275
+ start_line = 1 if start_line < 0
276
+
277
+ File.open file do |f|
278
+ f.each_line do |line|
279
+ current_line += 1
280
+
281
+ next if line.strip == ""
282
+
283
+ if current_line > end_line
284
+ break
285
+ end
286
+
287
+ if current_line >= start_line
288
+ context << [current_line, line]
289
+ end
290
+ end
291
+ end
292
+
293
+ context
294
+ end
189
295
  end