brakeman 3.1.5 → 3.2.0.pre1

Sign up to get free protection for your applications and to get access to all the features.
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
-