brakeman 3.1.5 → 3.2.0.pre1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 449a20c68813d646031a349e4ef3144c387462f1
4
- data.tar.gz: 65f2ed189a51bfc5e9b3d7bbe0d04d7fdfc8ae39
3
+ metadata.gz: 1e770766f6b12a78d68bb5578ca2f03edc16dbb0
4
+ data.tar.gz: d16b6325409502c5828ce379e364e43fbc10ec9e
5
5
  SHA512:
6
- metadata.gz: fe400de4fdfe2d81dc1dfab9e5ff9f0b6f8c53f4c30f868b8e605185e74a907b2932ab3dbe5b793425fd90c5e55fb3f34efdd7d755f04223939ba38d4e5bb3ef
7
- data.tar.gz: 1a7e2f419f4c8a2fdfc438406700220b2aba13409a5371db909a571d7a51bde96b1a231fbcd12d19fce49b463288b4d65100d35ba7e4879ed8fd04b729a037a7
6
+ metadata.gz: 79dbc7972a53fd175306dd50e21943b1825870fa2273b489bb2fef00c7870c5f0c5fc48e90b919d78b57dd2ff46b1a1be7fdee40f55f545d8a0cbecfe0878826
7
+ data.tar.gz: 647e2c2f42057c5f2d64a4e5166f3541ed1764062d4b6bed7668e6ba31429214486dbb8a495435dc144a98f52ec7357330640cb2730c71157a236b23bd7fdbb4
data/CHANGES CHANGED
@@ -1,3 +1,14 @@
1
+ # 3.2.0.pre1
2
+
3
+ * Support calls using `&.` operator
4
+ * Update ruby_parser dependency to 3.8.1
5
+ * Remove `fastercsv` dependency
6
+ * Fix finding calls with `targets: nil`
7
+ * Remove `multi-json` dependecy
8
+ * Handle CoffeeScript in HAML
9
+ * Avoid render warnings about params[:action]/params[:controller]
10
+ * Index calls in class bodies but outside methods
11
+
1
12
  # 3.1.5
2
13
 
3
14
  * Fix CodeClimate construction of --only-files (Will Fleming)
@@ -407,20 +407,20 @@ module Brakeman
407
407
 
408
408
  # Compare JSON ouptut from a previous scan and return the diff of the two scans
409
409
  def self.compare options
410
- require 'multi_json'
410
+ require 'json'
411
411
  require 'brakeman/differ'
412
412
  raise ArgumentError.new("Comparison file doesn't exist") unless File.exist? options[:previous_results_json]
413
413
 
414
414
  begin
415
- previous_results = MultiJson.load(File.read(options[:previous_results_json]), :symbolize_keys => true)[:warnings]
416
- rescue MultiJson::DecodeError
415
+ previous_results = JSON.parse(File.read(options[:previous_results_json]), :symbolize_names => true)[:warnings]
416
+ rescue JSON::ParserError
417
417
  self.notify "Error parsing comparison file: #{options[:previous_results_json]}"
418
418
  exit!
419
419
  end
420
420
 
421
421
  tracker = run(options)
422
422
 
423
- new_results = MultiJson.load(tracker.report.to_json, :symbolize_keys => true)[:warnings]
423
+ new_results = JSON.parse(tracker.report.to_json, :symbolize_names => true)[:warnings]
424
424
 
425
425
  Brakeman::Differ.new(new_results, previous_results).diff
426
426
  end
@@ -5,8 +5,8 @@ class Brakeman::CallIndex
5
5
 
6
6
  #Initialize index with calls from FindAllCalls
7
7
  def initialize calls
8
- @calls_by_method = Hash.new
9
- @calls_by_target = Hash.new
8
+ @calls_by_method = Hash.new { |h, k| h[k] = [] }
9
+ @calls_by_target = Hash.new { |h, k| h[k] = [] }
10
10
 
11
11
  index_calls calls
12
12
  end
@@ -45,7 +45,7 @@ class Brakeman::CallIndex
45
45
 
46
46
  #Find calls with no explicit target
47
47
  #with either :target => nil or :target => false
48
- elsif options.key? :target and not target and method
48
+ elsif (options.key? :target or options.key? :targets) and not target and method
49
49
  calls = calls_by_method method
50
50
  calls = filter_by_target calls, nil
51
51
 
@@ -66,44 +66,35 @@ class Brakeman::CallIndex
66
66
  end
67
67
 
68
68
  def remove_template_indexes template_name = nil
69
- @calls_by_method.each do |name, calls|
70
- calls.delete_if do |call|
71
- from_template call, template_name
72
- end
73
- end
74
-
75
- @calls_by_target.each do |name, calls|
76
- calls.delete_if do |call|
77
- from_template call, template_name
69
+ [@calls_by_method, @calls_by_target].each do |calls_by|
70
+ calls_by.each do |name, calls|
71
+ calls.delete_if do |call|
72
+ from_template call, template_name
73
+ end
78
74
  end
79
75
  end
80
76
  end
81
77
 
82
78
  def remove_indexes_by_class classes
83
- @calls_by_method.each do |name, calls|
84
- calls.delete_if do |call|
85
- call[:location][:type] == :class and classes.include? call[:location][:class]
86
- end
87
- end
88
-
89
- @calls_by_target.each do |name, calls|
90
- calls.delete_if do |call|
91
- call[:location][:type] == :class and classes.include? call[:location][:class]
79
+ [@calls_by_method, @calls_by_target].each do |calls_by|
80
+ calls_by.each do |name, calls|
81
+ calls.delete_if do |call|
82
+ call[:location][:type] == :class and classes.include? call[:location][:class]
83
+ end
92
84
  end
93
85
  end
94
86
  end
95
87
 
96
88
  def index_calls calls
97
89
  calls.each do |call|
98
- @calls_by_method[call[:method]] ||= []
99
90
  @calls_by_method[call[:method]] << call
100
91
 
101
- if not call[:target].is_a? Sexp
102
- @calls_by_target[call[:target]] ||= []
103
- @calls_by_target[call[:target]] << call
104
- elsif call[:target].node_type == :params or call[:target].node_type == :session
105
- @calls_by_target[call[:target].node_type] ||= []
106
- @calls_by_target[call[:target].node_type] << call
92
+ target = call[:target]
93
+
94
+ if not target.is_a? Sexp
95
+ @calls_by_target[target] << call
96
+ elsif target.node_type == :params or target.node_type == :session
97
+ @calls_by_target[target.node_type] << call
107
98
  end
108
99
  end
109
100
  end
@@ -115,7 +106,7 @@ class Brakeman::CallIndex
115
106
  method = options[:method] || options[:methods]
116
107
 
117
108
  calls = calls_by_method method
118
-
109
+
119
110
  return [] if calls.nil?
120
111
 
121
112
  calls = filter_by_chain calls, target
@@ -145,7 +136,7 @@ class Brakeman::CallIndex
145
136
  elsif method.is_a? Regexp
146
137
  calls_by_methods_regex method
147
138
  else
148
- @calls_by_method[method.to_sym] || []
139
+ @calls_by_method[method.to_sym]
149
140
  end
150
141
  end
151
142
 
@@ -169,7 +160,7 @@ class Brakeman::CallIndex
169
160
  end
170
161
 
171
162
  def calls_with_no_target
172
- @calls_by_target[nil] || []
163
+ @calls_by_target[nil]
173
164
  end
174
165
 
175
166
  def filter calls, key, value
@@ -93,91 +93,49 @@ class Brakeman::Checks
93
93
  #Run all the checks on the given Tracker.
94
94
  #Returns a new instance of Checks with the results.
95
95
  def self.run_checks(app_tree, tracker)
96
- if tracker.options[:parallel_checks]
97
- self.run_checks_parallel(app_tree, tracker)
98
- else
99
- self.run_checks_sequential(app_tree, tracker)
100
- end
101
- end
102
-
103
- #Run checks sequentially
104
- def self.run_checks_sequential(app_tree, tracker)
96
+ checks = self.checks_to_run(tracker)
105
97
  check_runner = self.new :min_confidence => tracker.options[:min_confidence]
106
-
107
- self.checks_to_run(tracker).each do |c|
108
- check_name = get_check_name c
109
-
110
- #Run or don't run check based on options
111
- unless tracker.options[:skip_checks].include? check_name or
112
- (tracker.options[:run_checks] and not tracker.options[:run_checks].include? check_name)
113
-
114
- Brakeman.notify " - #{check_name}"
115
-
116
- check = c.new(app_tree, tracker)
117
-
118
- begin
119
- check.run_check
120
- rescue => e
121
- tracker.error e
122
- end
123
-
124
- check.warnings.each do |w|
125
- check_runner.add_warning w
126
- end
127
-
128
- #Maintain list of which checks were run
129
- #mainly for reporting purposes
130
- check_runner.checks_run << check_name[5..-1]
131
- end
132
- end
133
-
134
- check_runner
98
+ self.actually_run_checks(checks, check_runner, app_tree, tracker)
135
99
  end
136
100
 
137
- #Run checks in parallel threads
138
- def self.run_checks_parallel(app_tree, tracker)
139
- threads = []
101
+ def self.actually_run_checks(checks, check_runner, app_tree, tracker)
102
+ threads = [] # Results for parallel
103
+ results = [] # Results for sequential
104
+ parallel = tracker.options[:parallel_checks]
140
105
  error_mutex = Mutex.new
141
106
 
142
- check_runner = self.new :min_confidence => tracker.options[:min_confidence]
143
-
144
- self.checks_to_run(tracker).each do |c|
107
+ checks.each do |c|
145
108
  check_name = get_check_name c
109
+ Brakeman.notify " - #{check_name}"
146
110
 
147
- #Run or don't run check based on options
148
- unless tracker.options[:skip_checks].include? check_name or
149
- (tracker.options[:run_checks] and not tracker.options[:run_checks].include? check_name)
150
-
151
- Brakeman.notify " - #{check_name}"
152
-
111
+ if parallel
153
112
  threads << Thread.new do
154
- check = c.new(app_tree, tracker)
155
-
156
- begin
157
- check.run_check
158
- rescue => e
159
- error_mutex.synchronize do
160
- tracker.error e
161
- end
162
- end
163
-
164
- check.warnings
113
+ self.run_a_check(c, error_mutex, app_tree, tracker)
165
114
  end
166
-
167
- #Maintain list of which checks were run
168
- #mainly for reporting purposes
169
- check_runner.checks_run << check_name[5..-1]
115
+ else
116
+ results << self.run_a_check(c, error_mutex, app_tree, tracker)
170
117
  end
118
+
119
+ #Maintain list of which checks were run
120
+ #mainly for reporting purposes
121
+ check_runner.checks_run << check_name[5..-1]
171
122
  end
172
123
 
173
124
  threads.each { |t| t.join }
174
125
 
175
126
  Brakeman.notify "Checks finished, collecting results..."
176
127
 
177
- #Collect results
178
- threads.each do |thread|
179
- thread.value.each do |warning|
180
- check_runner.add_warning warning
128
+ if parallel
129
+ threads.each do |thread|
130
+ thread.value.each do |warning|
131
+ check_runner.add_warning warning
132
+ end
133
+ end
134
+ else
135
+ results.each do |warnings|
136
+ warnings.each do |warning|
137
+ check_runner.add_warning warning
138
+ end
181
139
  end
182
140
  end
183
141
 
@@ -191,11 +149,39 @@ class Brakeman::Checks
191
149
  end
192
150
 
193
151
  def self.checks_to_run tracker
194
- if tracker.options[:run_all_checks] or tracker.options[:run_checks]
195
- @checks + @optional_checks
196
- else
197
- @checks
152
+ to_run = if tracker.options[:run_all_checks] or tracker.options[:run_checks]
153
+ @checks + @optional_checks
154
+ else
155
+ @checks
156
+ end
157
+
158
+ self.filter_checks to_run, tracker
159
+ end
160
+
161
+ def self.filter_checks checks, tracker
162
+ skipped = tracker.options[:skip_checks]
163
+ explicit = tracker.options[:run_checks]
164
+
165
+ checks.reject do |c|
166
+ check_name = self.get_check_name(c)
167
+
168
+ skipped.include? check_name or
169
+ (explicit and not explicit.include? check_name)
170
+ end
171
+ end
172
+
173
+ def self.run_a_check klass, mutex, app_tree, tracker
174
+ check = klass.new(app_tree, tracker)
175
+
176
+ begin
177
+ check.run_check
178
+ rescue => e
179
+ mutex.synchronize do
180
+ tracker.error e
181
+ end
198
182
  end
183
+
184
+ check.warnings
199
185
  end
200
186
  end
201
187
 
@@ -17,31 +17,10 @@ class Brakeman::CheckBasicAuthTimingAttack < Brakeman::BaseCheck
17
17
  return
18
18
  end
19
19
 
20
- check_basic_auth_filter
21
20
  check_basic_auth_call
22
21
  end
23
22
 
24
- def check_basic_auth_filter
25
- controllers = tracker.controllers.select do |name, c|
26
- c.options[:http_basic_authenticate_with]
27
- end
28
-
29
- Hash[controllers].each do |name, controller|
30
- controller.options[:http_basic_authenticate_with].each do |call|
31
- warn :controller => name,
32
- :warning_type => "Timing Attack",
33
- :warning_code => :CVE_2015_7576,
34
- :message => "Basic authentication in Rails #{rails_version} is vulnerable to timing attacks. Upgrade to #@upgrade",
35
- :code => call,
36
- :confidence => CONFIDENCE[:high],
37
- :file => controller.file,
38
- :link => "https://groups.google.com/d/msg/rubyonrails-security/ANv0HDHEC3k/mt7wNGxbFQAJ"
39
- end
40
- end
41
- end
42
-
43
23
  def check_basic_auth_call
44
- # This is relatively unusual, but found in the wild
45
24
  tracker.find_call(target: nil, method: :http_basic_authenticate_with).each do |result|
46
25
  warn :result => result,
47
26
  :warning_type => "Timing Attack",
@@ -99,7 +99,7 @@ class Brakeman::CheckCrossSiteScripting < Brakeman::BaseCheck
99
99
  link_path = "cross_site_scripting"
100
100
  warning_code = :cross_site_scripting
101
101
 
102
- if node_type?(out, :call, :attrasgn) && out.method == :to_json
102
+ if node_type?(out, :call, :safe_call, :attrasgn, :safe_attrasgn) && out.method == :to_json
103
103
  message += " in JSON hash"
104
104
  link_path += "_to_json"
105
105
  warning_code = :xss_to_json
@@ -334,7 +334,7 @@ class Brakeman::CheckCrossSiteScripting < Brakeman::BaseCheck
334
334
  end
335
335
 
336
336
  def html_safe_call? exp
337
- exp.value.node_type == :call and exp.value.method == :html_safe
337
+ call? exp.value and exp.value.method == :html_safe
338
338
  end
339
339
 
340
340
  def ignore_call? target, method
@@ -35,7 +35,6 @@ class Brakeman::CheckRender < Brakeman::BaseCheck
35
35
  if sexp? view and not duplicate? result
36
36
  add_result result
37
37
 
38
-
39
38
  if input = has_immediate_user_input?(view)
40
39
  if string_interp? view
41
40
  confidence = CONFIDENCE[:med]
@@ -49,6 +48,7 @@ class Brakeman::CheckRender < Brakeman::BaseCheck
49
48
  end
50
49
 
51
50
  return if input.type == :model #skip models
51
+ return if safe_param? input.match
52
52
 
53
53
  message = "Render path contains #{friendly_type_of input}"
54
54
 
@@ -71,6 +71,7 @@ class Brakeman::CheckRender < Brakeman::BaseCheck
71
71
  if sexp? view and not duplicate? result
72
72
  if params? view
73
73
  add_result result
74
+ return if safe_param? view
74
75
 
75
76
  warn :result => result,
76
77
  :warning_type => "Remote Code Execution",
@@ -81,4 +82,11 @@ class Brakeman::CheckRender < Brakeman::BaseCheck
81
82
  end
82
83
  end
83
84
  end
85
+
86
+ def safe_param? exp
87
+ if params? exp and call? exp and exp.method == :[]
88
+ arg = exp.first_arg
89
+ symbol? arg and [:controller, :action].include? arg.value
90
+ end
91
+ end
84
92
  end
@@ -64,9 +64,9 @@ class Brakeman::CheckSQL < Brakeman::BaseCheck
64
64
  second_arg = args[2]
65
65
  next unless sexp? second_arg
66
66
 
67
- if second_arg.node_type == :iter and node_type? second_arg.block, :block, :call
67
+ if second_arg.node_type == :iter and node_type? second_arg.block, :block, :call, :safe_call
68
68
  process_scope_with_block(name, args)
69
- elsif second_arg.node_type == :call
69
+ elsif call? second_arg
70
70
  call = second_arg
71
71
  scope_calls << scope_call_hash(call, name, call.method)
72
72
  else
@@ -107,7 +107,7 @@ class Brakeman::CheckSQL < Brakeman::BaseCheck
107
107
  find_calls = Brakeman::FindAllCalls.new(tracker)
108
108
  find_calls.process_source(block, :class => model_name, :method => scope_name)
109
109
  find_calls.calls.each { |call| process_result(call) if @sql_targets.include?(call[:method]) }
110
- elsif block.node_type == :call
110
+ elsif call? block
111
111
  while call? block
112
112
  process_result :target => block.target, :method => block.method, :call => block,
113
113
  :location => { :type => :class, :class => model_name, :method => scope_name }
@@ -296,7 +296,7 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
296
296
 
297
297
  # Handles x = y = z = 1
298
298
  def get_rhs exp
299
- if node_type? exp, :lasgn, :iasgn, :gasgn, :attrasgn, :cvdecl, :cdecl
299
+ if node_type? exp, :lasgn, :iasgn, :gasgn, :attrasgn, :safe_attrasgn, :cvdecl, :cdecl
300
300
  get_rhs(exp.rhs)
301
301
  else
302
302
  exp
@@ -68,6 +68,14 @@ class Brakeman::BaseProcessor < Brakeman::SexpProcessor
68
68
  call
69
69
  end
70
70
 
71
+ def process_safe_call exp
72
+ if self.respond_to? :process_call
73
+ process_call exp
74
+ else
75
+ process_default exp
76
+ end
77
+ end
78
+
71
79
  #String with interpolation.
72
80
  def process_dstr exp
73
81
  exp = exp.dup
@@ -25,7 +25,7 @@ class Brakeman::ErbTemplateProcessor < Brakeman::TemplateProcessor
25
25
 
26
26
  arg = exp.first_arg
27
27
 
28
- if arg.node_type == :call and arg.method == :to_s #erb always calls to_s on output
28
+ if call? arg and arg.method == :to_s #erb always calls to_s on output
29
29
  arg = arg.target
30
30
  end
31
31
 
@@ -21,7 +21,7 @@ class Brakeman::ErubisTemplateProcessor < Brakeman::TemplateProcessor
21
21
  arg = exp.first_arg
22
22
 
23
23
  #We want the actual content
24
- if arg.node_type == :call and (arg.method == :to_s or arg.method == :html_safe!)
24
+ if call? arg and (arg.method == :to_s or arg.method == :html_safe!)
25
25
  arg = arg.target
26
26
  end
27
27
 
@@ -5,6 +5,7 @@ class Brakeman::HamlTemplateProcessor < Brakeman::TemplateProcessor
5
5
  HAML_FORMAT_METHOD = /format_script_(true|false)_(true|false)_(true|false)_(true|false)_(true|false)_(true|false)_(true|false)/
6
6
  HAML_HELPERS = s(:colon2, s(:const, :Haml), :Helpers)
7
7
  JAVASCRIPT_FILTER = s(:colon2, s(:colon2, s(:const, :Haml), :Filters), :Javascript)
8
+ COFFEE_FILTER = s(:colon2, s(:colon2, s(:const, :Haml), :Filters), :Coffee)
8
9
 
9
10
  #Processes call, looking for template output
10
11
  def process_call exp
@@ -90,7 +91,7 @@ class Brakeman::HamlTemplateProcessor < Brakeman::TemplateProcessor
90
91
  elsif target == nil and method == :find_and_preserve
91
92
  process exp.first_arg
92
93
  elsif method == :render_with_options
93
- if target == JAVASCRIPT_FILTER
94
+ if target == JAVASCRIPT_FILTER or target == COFFEE_FILTER
94
95
  @javascript = true
95
96
  end
96
97
 
@@ -14,4 +14,20 @@ class Brakeman::BasicProcessor < Brakeman::SexpProcessor
14
14
  def process_default exp
15
15
  process_all exp
16
16
  end
17
+
18
+ def process_safe_call exp
19
+ if self.respond_to? :process_call
20
+ process_call exp
21
+ else
22
+ process_default exp
23
+ end
24
+ end
25
+
26
+ def process_safe_attrasgn exp
27
+ if self.respond_to? :process_attrasgn
28
+ process_attrasgn exp
29
+ else
30
+ process_default exp
31
+ end
32
+ end
17
33
  end
@@ -24,11 +24,13 @@ class Brakeman::FindAllCalls < Brakeman::BasicProcessor
24
24
 
25
25
  #Process body of method
26
26
  def process_defn exp
27
+ return exp unless @current_method
27
28
  process_all exp.body
28
29
  end
29
30
 
30
31
  #Process body of method
31
32
  def process_defs exp
33
+ return exp unless @current_method
32
34
  process_all exp.body
33
35
  end
34
36
 
@@ -139,7 +141,7 @@ class Brakeman::FindAllCalls < Brakeman::BasicProcessor
139
141
  @current_class || @current_module || nil
140
142
  when :params, :session, :cookies
141
143
  exp.node_type
142
- when :call
144
+ when :call, :safe_call
143
145
  if include_calls
144
146
  if exp.target.nil?
145
147
  exp.method
@@ -165,7 +167,7 @@ class Brakeman::FindAllCalls < Brakeman::BasicProcessor
165
167
  #Returns method chain as an array
166
168
  #For example, User.human.alive.all would return [:User, :human, :alive, :all]
167
169
  def get_chain call
168
- if node_type? call, :call, :attrasgn
170
+ if node_type? call, :call, :attrasgn, :safe_call, :safe_attrasgn
169
171
  get_chain(call.target) + [call.method]
170
172
  elsif call.nil?
171
173
  []
@@ -102,7 +102,7 @@ class Brakeman::FindCall < Brakeman::BasicProcessor
102
102
  # User.find(:first, :conditions => "user = '#{params['user']}').name
103
103
  #
104
104
  #A search for User.find will not match this unless @in_depth is true.
105
- if @in_depth and node_type? exp.target, :call
105
+ if @in_depth and call? exp.target
106
106
  process exp.target
107
107
  end
108
108
 
@@ -95,7 +95,8 @@ module Brakeman
95
95
  end
96
96
 
97
97
  def to_json *args
98
- MultiJson.dump(@path)
98
+ require 'json'
99
+ JSON.generate(@path)
99
100
  end
100
101
 
101
102
  def initialize_copy original
@@ -1,5 +1,5 @@
1
1
  require 'set'
2
- require 'multi_json'
2
+ require 'json'
3
3
 
4
4
  module Brakeman
5
5
  class IgnoreConfig
@@ -75,7 +75,7 @@ module Brakeman
75
75
  # Read configuration to file
76
76
  def read_from_file file = @file
77
77
  if File.exist? file
78
- @already_ignored = MultiJson.load(File.read(file), :symbolize_keys => true)[:ignored_warnings]
78
+ @already_ignored = JSON.parse(File.read(file), :symbolize_names => true)[:ignored_warnings]
79
79
  else
80
80
  Brakeman.notify "[Notice] Could not find ignore configuration in #{file}"
81
81
  @already_ignored = []
@@ -107,7 +107,7 @@ module Brakeman
107
107
  }
108
108
 
109
109
  File.open file, "w" do |f|
110
- f.puts MultiJson.dump(output, :pretty => true)
110
+ f.puts JSON.pretty_generate(output)
111
111
  end
112
112
  end
113
113
 
@@ -1,5 +1,4 @@
1
- Brakeman.load_brakeman_dependency 'csv'
2
- require "brakeman/report/initializers/faster_csv"
1
+ require 'csv'
3
2
  require "brakeman/report/report_table"
4
3
 
5
4
  class Brakeman::Report::CSV < Brakeman::Report::Table
@@ -1,6 +1,3 @@
1
- Brakeman.load_brakeman_dependency 'multi_json'
2
- require 'brakeman/report/initializers/multi_json'
3
-
4
1
  class Brakeman::Report::JSON < Brakeman::Report::Base
5
2
  def generate_report
6
3
  errors = tracker.errors.map{|e| { :error => e[:error], :location => e[:backtrace][0] }}
@@ -32,7 +29,7 @@ class Brakeman::Report::JSON < Brakeman::Report::Base
32
29
  :errors => errors
33
30
  }
34
31
 
35
- MultiJson.dump(report_info, :pretty => true)
32
+ JSON.pretty_generate report_info
36
33
  end
37
34
 
38
35
  def convert_to_hashes warnings
@@ -115,6 +115,23 @@ class Brakeman::Tracker
115
115
  end
116
116
  end
117
117
 
118
+
119
+ def each_class
120
+ classes = [self.controllers, self.models]
121
+
122
+ if @options[:index_libs]
123
+ classes << self.libs
124
+ end
125
+
126
+ classes.each do |set|
127
+ set.each do |set_name, collection|
128
+ collection.src.each do |file, src|
129
+ yield src, set_name, file
130
+ end
131
+ end
132
+ end
133
+ end
134
+
118
135
  #Find a method call.
119
136
  #
120
137
  #Options:
@@ -178,6 +195,10 @@ class Brakeman::Tracker
178
195
  finder.process_source definition, :class => set_name, :method => method_name, :file => file
179
196
  end
180
197
 
198
+ self.each_class do |definition, set_name, file|
199
+ finder.process_source definition, :class => set_name, :file => file
200
+ end
201
+
181
202
  self.each_template do |name, template|
182
203
  finder.process_source template.src, :template => template, :file => template.file
183
204
  end
@@ -167,7 +167,8 @@ module Brakeman::Util
167
167
 
168
168
  #Check if _exp_ represents a method call: s(:call, ...)
169
169
  def call? exp
170
- exp.is_a? Sexp and exp.node_type == :call
170
+ exp.is_a? Sexp and
171
+ (exp.node_type == :call or exp.node_type == :safe_call)
171
172
  end
172
173
 
173
174
  #Check if _exp_ represents a Regexp: s(:lit, /.../)
@@ -214,7 +215,7 @@ module Brakeman::Util
214
215
  if exp.is_a? Sexp
215
216
  return true if exp.node_type == :params or ALL_PARAMETERS.include? exp
216
217
 
217
- if exp.node_type == :call
218
+ if call? exp
218
219
  if params? exp[1]
219
220
  return true
220
221
  elsif exp[2] == :[]
@@ -230,7 +231,7 @@ module Brakeman::Util
230
231
  if exp.is_a? Sexp
231
232
  return true if exp.node_type == :cookies or exp == COOKIES
232
233
 
233
- if exp.node_type == :call
234
+ if call? exp
234
235
  if cookies? exp[1]
235
236
  return true
236
237
  elsif exp[2] == :[]
@@ -1,3 +1,3 @@
1
1
  module Brakeman
2
- Version = "3.1.5"
2
+ Version = "3.2.0.pre1"
3
3
  end
@@ -1,4 +1,4 @@
1
- require 'multi_json'
1
+ require 'json'
2
2
  require 'digest/sha2'
3
3
  require 'brakeman/warning_codes'
4
4
 
@@ -241,7 +241,7 @@ class Brakeman::Warning
241
241
  end
242
242
 
243
243
  def to_json
244
- MultiJson.dump self.to_hash
244
+ JSON.generate self.to_hash
245
245
  end
246
246
 
247
247
  private
@@ -141,13 +141,13 @@ class Sexp
141
141
  #s(:call, s(:call, nil, :x, s(:arglist)), :y, s(:arglist, s(:lit, 1)))
142
142
  # ^-----------target-----------^
143
143
  def target
144
- expect :call, :attrasgn
144
+ expect :call, :attrasgn, :safe_call, :safe_attrasgn
145
145
  self[1]
146
146
  end
147
147
 
148
148
  #Sets the target of a method call:
149
149
  def target= exp
150
- expect :call, :attrasgn
150
+ expect :call, :attrasgn, :safe_call, :safe_attrasgn
151
151
  @my_hash_value = nil
152
152
  self[1] = exp
153
153
  end
@@ -157,10 +157,10 @@ class Sexp
157
157
  #s(:call, s(:call, nil, :x, s(:arglist)), :y, s(:arglist, s(:lit, 1)))
158
158
  # ^- method
159
159
  def method
160
- expect :call, :attrasgn, :super, :zsuper, :result
160
+ expect :call, :attrasgn, :safe_call, :safe_attrasgn, :super, :zsuper, :result
161
161
 
162
162
  case self.node_type
163
- when :call, :attrasgn
163
+ when :call, :attrasgn, :safe_call, :safe_attrasgn
164
164
  self[2]
165
165
  when :super, :zsuper
166
166
  :super
@@ -170,14 +170,14 @@ class Sexp
170
170
  end
171
171
 
172
172
  def method= name
173
- expect :call
173
+ expect :call, :safe_call
174
174
 
175
175
  self[2] = name
176
176
  end
177
177
 
178
178
  #Sets the arglist in a method call.
179
179
  def arglist= exp
180
- expect :call, :attrasgn
180
+ expect :call, :attrasgn, :safe_call, :safe_attrasgn
181
181
  @my_hash_value = nil
182
182
  start_index = 3
183
183
 
@@ -201,10 +201,10 @@ class Sexp
201
201
  # s(:call, s(:call, nil, :x, s(:arglist)), :y, s(:arglist, s(:lit, 1), s(:lit, 2)))
202
202
  # ^------------ arglist ------------^
203
203
  def arglist
204
- expect :call, :attrasgn, :super, :zsuper
204
+ expect :call, :attrasgn, :safe_call, :safe_attrasgn, :super, :zsuper
205
205
 
206
206
  case self.node_type
207
- when :call, :attrasgn
207
+ when :call, :attrasgn, :safe_call, :safe_attrasgn
208
208
  self[3..-1].unshift :arglist
209
209
  when :super, :zsuper
210
210
  if self[1]
@@ -220,10 +220,10 @@ class Sexp
220
220
  # s(:call, s(:call, nil, :x, s(:arglist)), :y, s(:arglist, s(:lit, 1), s(:lit, 2)))
221
221
  # ^--------args--------^
222
222
  def args
223
- expect :call, :attrasgn, :super, :zsuper
223
+ expect :call, :attrasgn, :safe_call, :safe_attrasgn, :super, :zsuper
224
224
 
225
225
  case self.node_type
226
- when :call, :attrasgn
226
+ when :call, :attrasgn, :safe_call, :safe_attrasgn
227
227
  if self[3]
228
228
  self[3..-1]
229
229
  else
@@ -239,11 +239,11 @@ class Sexp
239
239
  end
240
240
 
241
241
  def each_arg replace = false
242
- expect :call, :attrasgn, :super, :zsuper
242
+ expect :call, :attrasgn, :safe_call, :safe_attrasgn, :super, :zsuper
243
243
  range = nil
244
244
 
245
245
  case self.node_type
246
- when :call, :attrasgn
246
+ when :call, :attrasgn, :safe_call, :safe_attrasgn
247
247
  if self[3]
248
248
  range = (3...self.length)
249
249
  end
@@ -270,43 +270,43 @@ class Sexp
270
270
 
271
271
  #Returns first argument of a method call.
272
272
  def first_arg
273
- expect :call, :attrasgn
273
+ expect :call, :attrasgn, :safe_call, :safe_attrasgn
274
274
  self[3]
275
275
  end
276
276
 
277
277
  #Sets first argument of a method call.
278
278
  def first_arg= exp
279
- expect :call, :attrasgn
279
+ expect :call, :attrasgn, :safe_call, :safe_attrasgn
280
280
  @my_hash_value = nil
281
281
  self[3] = exp
282
282
  end
283
283
 
284
284
  #Returns second argument of a method call.
285
285
  def second_arg
286
- expect :call, :attrasgn
286
+ expect :call, :attrasgn, :safe_call, :safe_attrasgn
287
287
  self[4]
288
288
  end
289
289
 
290
290
  #Sets second argument of a method call.
291
291
  def second_arg= exp
292
- expect :call, :attrasgn
292
+ expect :call, :attrasgn, :safe_call, :safe_attrasgn
293
293
  @my_hash_value = nil
294
294
  self[4] = exp
295
295
  end
296
296
 
297
297
  def third_arg
298
- expect :call, :attrasgn
298
+ expect :call, :attrasgn, :safe_call, :safe_attrasgn
299
299
  self[5]
300
300
  end
301
301
 
302
302
  def third_arg= exp
303
- expect :call, :attrasgn
303
+ expect :call, :attrasgn, :safe_call, :safe_attrasgn
304
304
  @my_hash_value = nil
305
305
  self[5] = exp
306
306
  end
307
307
 
308
308
  def last_arg
309
- expect :call, :attrasgn
309
+ expect :call, :attrasgn, :safe_call, :safe_attrasgn
310
310
 
311
311
  if self[3]
312
312
  self[-1]
@@ -427,9 +427,9 @@ class Sexp
427
427
  # s(:lasgn, :x, s(:lit, 1))
428
428
  # ^--rhs---^
429
429
  def rhs
430
- expect :attrasgn, *ASSIGNMENT_BOOL
430
+ expect :attrasgn, :safe_attrasgn, *ASSIGNMENT_BOOL
431
431
 
432
- if self.node_type == :attrasgn
432
+ if self.node_type == :attrasgn or self.node_type == :safe_attrasgn
433
433
  self[3]
434
434
  else
435
435
  self[2]
@@ -438,10 +438,10 @@ class Sexp
438
438
 
439
439
  #Sets the right hand side of assignment or boolean.
440
440
  def rhs= exp
441
- expect :attrasgn, *ASSIGNMENT_BOOL
441
+ expect :attrasgn, :safe_attrasgn, *ASSIGNMENT_BOOL
442
442
  @my_hash_value = nil
443
443
 
444
- if self.node_type == :attrasgn
444
+ if self.node_type == :attrasgn or self.node_type == :safe_attrasgn
445
445
  self[3] = exp
446
446
  else
447
447
  self[2] = exp
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: brakeman
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.1.5
4
+ version: 3.2.0.pre1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Justin Collins
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain:
11
11
  - brakeman-public_cert.pem
12
- date: 2016-01-28 00:00:00.000000000 Z
12
+ date: 2016-02-22 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: test-unit
@@ -31,32 +31,26 @@ dependencies:
31
31
  requirements:
32
32
  - - "~>"
33
33
  - !ruby/object:Gem::Version
34
- version: 3.7.0
34
+ version: 3.8.1
35
35
  type: :runtime
36
36
  prerelease: false
37
37
  version_requirements: !ruby/object:Gem::Requirement
38
38
  requirements:
39
39
  - - "~>"
40
40
  - !ruby/object:Gem::Version
41
- version: 3.7.0
41
+ version: 3.8.1
42
42
  - !ruby/object:Gem::Dependency
43
43
  name: ruby2ruby
44
44
  requirement: !ruby/object:Gem::Requirement
45
45
  requirements:
46
- - - ">="
47
- - !ruby/object:Gem::Version
48
- version: 2.1.1
49
- - - "<"
46
+ - - "~>"
50
47
  - !ruby/object:Gem::Version
51
48
  version: 2.3.0
52
49
  type: :runtime
53
50
  prerelease: false
54
51
  version_requirements: !ruby/object:Gem::Requirement
55
52
  requirements:
56
- - - ">="
57
- - !ruby/object:Gem::Version
58
- version: 2.1.1
59
- - - "<"
53
+ - - "~>"
60
54
  - !ruby/object:Gem::Version
61
55
  version: 2.3.0
62
56
  - !ruby/object:Gem::Dependency
@@ -73,20 +67,6 @@ dependencies:
73
67
  - - "~>"
74
68
  - !ruby/object:Gem::Version
75
69
  version: '1.4'
76
- - !ruby/object:Gem::Dependency
77
- name: fastercsv
78
- requirement: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - "~>"
81
- - !ruby/object:Gem::Version
82
- version: '1.5'
83
- type: :runtime
84
- prerelease: false
85
- version_requirements: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - "~>"
88
- - !ruby/object:Gem::Version
89
- version: '1.5'
90
70
  - !ruby/object:Gem::Dependency
91
71
  name: highline
92
72
  requirement: !ruby/object:Gem::Requirement
@@ -175,20 +155,6 @@ dependencies:
175
155
  - - "<"
176
156
  - !ruby/object:Gem::Version
177
157
  version: '4.0'
178
- - !ruby/object:Gem::Dependency
179
- name: multi_json
180
- requirement: !ruby/object:Gem::Requirement
181
- requirements:
182
- - - "~>"
183
- - !ruby/object:Gem::Version
184
- version: '1.2'
185
- type: :runtime
186
- prerelease: false
187
- version_requirements: !ruby/object:Gem::Requirement
188
- requirements:
189
- - - "~>"
190
- - !ruby/object:Gem::Version
191
- version: '1.2'
192
158
  - !ruby/object:Gem::Dependency
193
159
  name: safe_yaml
194
160
  requirement: !ruby/object:Gem::Requirement
@@ -329,8 +295,6 @@ files:
329
295
  - lib/brakeman/report/config/remediation.yml
330
296
  - lib/brakeman/report/ignore/config.rb
331
297
  - lib/brakeman/report/ignore/interactive.rb
332
- - lib/brakeman/report/initializers/faster_csv.rb
333
- - lib/brakeman/report/initializers/multi_json.rb
334
298
  - lib/brakeman/report/renderer.rb
335
299
  - lib/brakeman/report/report_base.rb
336
300
  - lib/brakeman/report/report_codeclimate.rb
@@ -382,9 +346,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
382
346
  version: '0'
383
347
  required_rubygems_version: !ruby/object:Gem::Requirement
384
348
  requirements:
385
- - - ">="
349
+ - - ">"
386
350
  - !ruby/object:Gem::Version
387
- version: '0'
351
+ version: 1.3.1
388
352
  requirements: []
389
353
  rubyforge_project:
390
354
  rubygems_version: 2.4.8
@@ -1,7 +0,0 @@
1
- # Ruby 1.8 compatible
2
- if CSV.const_defined? :Reader
3
- require 'fastercsv'
4
- Object.send(:remove_const, :CSV)
5
- CSV = FasterCSV
6
- end
7
-
@@ -1,29 +0,0 @@
1
- #MultiJson interface changed in 1.3.0, but need
2
- #to support older MultiJson for Rails 3.1.
3
- mj_engine = nil
4
-
5
- if MultiJson.respond_to? :default_adapter
6
- mj_engine = MultiJson.default_adapter
7
- else
8
- mj_engine = MultiJson.default_engine
9
-
10
- module MultiJson
11
- def self.dump *args
12
- encode *args
13
- end
14
-
15
- def self.load *args
16
- decode *args
17
- end
18
- end
19
- end
20
-
21
- #This is so OkJson will work with symbol values
22
- if mj_engine == :ok_json
23
- class Symbol
24
- def to_json
25
- self.to_s.inspect
26
- end
27
- end
28
- end
29
-