brakeman 1.9.4 → 1.9.5
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 +4 -4
- data/CHANGES +15 -0
- data/README.md +6 -0
- data/lib/brakeman.rb +7 -2
- data/lib/brakeman/checks/check_link_to.rb +59 -67
- data/lib/brakeman/checks/check_mass_assignment.rb +5 -1
- data/lib/brakeman/checks/check_session_settings.rb +18 -7
- data/lib/brakeman/checks/check_symbol_dos.rb +50 -3
- data/lib/brakeman/processors/alias_processor.rb +116 -42
- data/lib/brakeman/processors/controller_processor.rb +5 -0
- data/lib/brakeman/processors/erb_template_processor.rb +2 -1
- data/lib/brakeman/processors/erubis_template_processor.rb +2 -1
- data/lib/brakeman/processors/haml_template_processor.rb +2 -1
- data/lib/brakeman/processors/lib/find_all_calls.rb +17 -0
- data/lib/brakeman/processors/lib/find_return_value.rb +3 -3
- data/lib/brakeman/processors/lib/render_helper.rb +1 -1
- data/lib/brakeman/processors/slim_template_processor.rb +1 -1
- data/lib/brakeman/processors/template_processor.rb +1 -1
- data/lib/brakeman/report.rb +60 -151
- data/lib/brakeman/report/initializers/faster_csv.rb +7 -0
- data/lib/brakeman/report/initializers/multi_json.rb +29 -0
- data/lib/brakeman/report/renderer.rb +22 -0
- data/lib/brakeman/{templates → report/templates}/controller_overview.html.erb +0 -0
- data/lib/brakeman/{templates → report/templates}/controller_warnings.html.erb +0 -0
- data/lib/brakeman/{templates → report/templates}/error_overview.html.erb +0 -0
- data/lib/brakeman/{templates → report/templates}/header.html.erb +2 -2
- data/lib/brakeman/{templates → report/templates}/model_warnings.html.erb +0 -0
- data/lib/brakeman/{templates → report/templates}/overview.html.erb +2 -2
- data/lib/brakeman/{templates → report/templates}/security_warnings.html.erb +0 -0
- data/lib/brakeman/{templates → report/templates}/template_overview.html.erb +0 -0
- data/lib/brakeman/{templates → report/templates}/view_warnings.html.erb +0 -0
- data/lib/brakeman/{templates → report/templates}/warning_overview.html.erb +0 -0
- data/lib/brakeman/scanner.rb +3 -0
- data/lib/brakeman/util.rb +6 -0
- data/lib/brakeman/version.rb +1 -1
- data/lib/brakeman/warning_codes.rb +1 -0
- data/lib/ruby_parser/bm_sexp.rb +14 -39
- metadata +17 -14
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA512:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5fec83c0cb268acf3954ea08df30a173ad10b3121d4d30d18c1670de66cf17d01fde3d0649c28f5c5570938d9d4a13368af819f4d580800441c1cdf4b4873cd2
|
4
|
+
data.tar.gz: ff597aced590649b3a90cf2f895407f9e347a8a81b1f34337e2eff32310958c34bbe711985b70ce58f6f91eb658bc8d6db533819b881fb4d3ec9fa3842cb751e
|
5
5
|
SHA1:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b4735612d0032bfd8a72f0feb285ee4e704a3a1a
|
7
|
+
data.tar.gz: 1898b18fbf38409a98ba3b5517f3896b057872c9
|
data/CHANGES
CHANGED
@@ -1,3 +1,18 @@
|
|
1
|
+
# 1.9.5
|
2
|
+
|
3
|
+
* Add check for unsafe symbol creation
|
4
|
+
* Do not warn on mass assignment with `slice`/`only`
|
5
|
+
* Do not warn on session secret if in `.gitignore`
|
6
|
+
* Fix scoping for blocks and block arguments
|
7
|
+
* Fix error when modifying blocks in templates
|
8
|
+
* Fix session secret check for Rails 4
|
9
|
+
* Fix crash on `before_filter` outside controller
|
10
|
+
* Fix `Sexp` hash cache invalidation
|
11
|
+
* Respect `quiet` option in configuration file
|
12
|
+
* Convert assignment to simple `if` expressions to `or`
|
13
|
+
* More fixes for assignments inside branches
|
14
|
+
* Pin to ruby2ruby version 2.0.3
|
15
|
+
|
1
16
|
# 1.9.4
|
2
17
|
|
3
18
|
* Add check for CVE-2013-1854
|
data/README.md
CHANGED
data/lib/brakeman.rb
CHANGED
@@ -65,7 +65,12 @@ module Brakeman
|
|
65
65
|
|
66
66
|
options[:app_path] = File.expand_path(options[:app_path])
|
67
67
|
|
68
|
-
|
68
|
+
file_options = load_options(options[:config_file])
|
69
|
+
|
70
|
+
options = file_options.merge options
|
71
|
+
|
72
|
+
options[:quiet] = true if options[:quiet].nil? && file_options[:quiet]
|
73
|
+
|
69
74
|
options = get_defaults.merge! options
|
70
75
|
options[:output_formats] = get_output_formats options
|
71
76
|
|
@@ -89,9 +94,9 @@ module Brakeman
|
|
89
94
|
def self.load_options custom_location
|
90
95
|
#Load configuration file
|
91
96
|
if config = config_file(custom_location)
|
92
|
-
notify "[Notice] Using configuration in #{config}"
|
93
97
|
options = YAML.load_file config
|
94
98
|
options.each { |k, v| options[k] = Set.new v if v.is_a? Array }
|
99
|
+
notify "[Notice] Using configuration in #{config}" unless options[:quiet]
|
95
100
|
options
|
96
101
|
else
|
97
102
|
{}
|
@@ -23,14 +23,10 @@ class Brakeman::CheckLinkTo < Brakeman::CheckCrossSiteScripting
|
|
23
23
|
@known_dangerous = []
|
24
24
|
#Ideally, I think this should also check to see if people are setting
|
25
25
|
#:escape => false
|
26
|
-
methods = tracker.find_call :target => false, :method => :link_to
|
27
|
-
|
28
26
|
@models = tracker.models.keys
|
29
27
|
@inspect_arguments = tracker.options[:check_arguments]
|
30
28
|
|
31
|
-
|
32
|
-
process_result call
|
33
|
-
end
|
29
|
+
tracker.find_call(:target => false, :method => :link_to).each {|call| process_result call}
|
34
30
|
end
|
35
31
|
|
36
32
|
def process_result result
|
@@ -61,68 +57,68 @@ class Brakeman::CheckLinkTo < Brakeman::CheckCrossSiteScripting
|
|
61
57
|
end
|
62
58
|
end
|
63
59
|
|
60
|
+
# Check the argument for possible xss exploits
|
64
61
|
def check_argument result, exp
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
case input.type
|
69
|
-
when :params
|
70
|
-
message = "Unescaped parameter value in link_to"
|
71
|
-
when :cookies
|
72
|
-
message = "Unescaped cookie value in link_to"
|
73
|
-
else
|
74
|
-
message = "Unescaped user input value in link_to"
|
75
|
-
end
|
62
|
+
argument = process(exp)
|
63
|
+
!check_user_input(result, argument) && !check_method(result, argument) && !check_matched(result, @matched)
|
64
|
+
end
|
76
65
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
add_result result
|
91
|
-
|
92
|
-
if MODEL_METHODS.include? method or method.to_s =~ /^find_by/
|
93
|
-
confidence = CONFIDENCE[:high]
|
94
|
-
else
|
95
|
-
confidence = CONFIDENCE[:med]
|
96
|
-
end
|
97
|
-
|
98
|
-
warn :result => result,
|
99
|
-
:warning_type => "Cross Site Scripting",
|
100
|
-
:warning_code => :xss_link_to,
|
101
|
-
:message => "Unescaped model attribute in link_to",
|
102
|
-
:user_input => match,
|
103
|
-
:confidence => confidence,
|
104
|
-
:link_path => "link_to"
|
105
|
-
end
|
66
|
+
# Check we should warn about the user input
|
67
|
+
def check_user_input(result, argument)
|
68
|
+
input = has_immediate_user_input?(argument)
|
69
|
+
return false unless input
|
70
|
+
|
71
|
+
case input.type
|
72
|
+
when :params
|
73
|
+
message = "Unescaped parameter value in link_to"
|
74
|
+
when :cookies
|
75
|
+
message = "Unescaped cookie value in link_to"
|
76
|
+
else
|
77
|
+
message = "Unescaped user input value in link_to"
|
78
|
+
end
|
106
79
|
|
107
|
-
|
108
|
-
|
109
|
-
message = "Unescaped model attribute in link_to"
|
110
|
-
elsif @matched.type == :params
|
111
|
-
message = "Unescaped parameter value in link_to"
|
112
|
-
end
|
80
|
+
warn_xss(result, message, input.match, CONFIDENCE[:high])
|
81
|
+
end
|
113
82
|
|
114
|
-
|
115
|
-
|
83
|
+
# Check if we should warn about the specified method
|
84
|
+
def check_method(result, argument)
|
85
|
+
return false if tracker.options[:ignore_model_output]
|
86
|
+
match = has_immediate_model?(argument)
|
87
|
+
return false unless match
|
88
|
+
method = match.method
|
89
|
+
return false if IGNORE_MODEL_METHODS.include? method
|
90
|
+
|
91
|
+
confidence = CONFIDENCE[:med]
|
92
|
+
confidence = CONFIDENCE[:high] if MODEL_METHODS.include? method or method.to_s =~ /^find_by/
|
93
|
+
warn_xss(result, "Unescaped model attribute in link_to", match, confidence)
|
94
|
+
end
|
116
95
|
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
96
|
+
# Check if we should warn about the matched result
|
97
|
+
def check_matched(result, matched = nil)
|
98
|
+
return false unless matched
|
99
|
+
message = nil
|
100
|
+
|
101
|
+
if matched.type == :model and not tracker.options[:ignore_model_output]
|
102
|
+
message = "Unescaped model attribute in link_to"
|
103
|
+
elsif matched.type == :params
|
104
|
+
message = "Unescaped parameter value in link_to"
|
125
105
|
end
|
106
|
+
|
107
|
+
message ? warn_xss(result, message, @matched.match, CONFIDENCE[:med]) : false
|
108
|
+
end
|
109
|
+
|
110
|
+
# Create a warn for this xss
|
111
|
+
def warn_xss(result, message, user_input, confidence)
|
112
|
+
add_result(result)
|
113
|
+
warn :result => result,
|
114
|
+
:warning_type => "Cross Site Scripting",
|
115
|
+
:warning_code => :xss_link_to,
|
116
|
+
:message => message,
|
117
|
+
:user_input => user_input,
|
118
|
+
:confidence => confidence,
|
119
|
+
:link_path => "link_to"
|
120
|
+
|
121
|
+
true
|
126
122
|
end
|
127
123
|
|
128
124
|
def process_call exp
|
@@ -135,16 +131,12 @@ class Brakeman::CheckLinkTo < Brakeman::CheckCrossSiteScripting
|
|
135
131
|
return if @matched
|
136
132
|
|
137
133
|
target = exp.target
|
138
|
-
if sexp? target
|
139
|
-
target = process target.dup
|
140
|
-
end
|
134
|
+
target = process target.dup if sexp? target
|
141
135
|
|
142
136
|
#Bare records create links to the model resource,
|
143
137
|
#not a string that could have injection
|
144
138
|
#TODO: Needs test? I think this is broken?
|
145
|
-
if model_name? target and context == [:call, :arglist]
|
146
|
-
return exp
|
147
|
-
end
|
139
|
+
return exp if model_name? target and context == [:call, :arglist]
|
148
140
|
|
149
141
|
super
|
150
142
|
end
|
@@ -59,7 +59,11 @@ class Brakeman::CheckMassAssignment < Brakeman::BaseCheck
|
|
59
59
|
if attr_protected and tracker.options[:ignore_attr_protected]
|
60
60
|
return
|
61
61
|
elsif input = include_user_input?(call.arglist)
|
62
|
-
|
62
|
+
first_arg = call.first_arg
|
63
|
+
|
64
|
+
if call? first_arg and (first_arg.method == :slice or first_arg.method == :only)
|
65
|
+
return
|
66
|
+
elsif not node_type? first_arg, :hash and not attr_protected
|
63
67
|
confidence = CONFIDENCE[:high]
|
64
68
|
user_input = input.match
|
65
69
|
else
|
@@ -23,12 +23,10 @@ class Brakeman::CheckSessionSettings < Brakeman::BaseCheck
|
|
23
23
|
|
24
24
|
check_for_issues settings, "#{tracker.options[:app_path]}/config/environment.rb"
|
25
25
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
if tracker.initializers["secret_token.rb"]
|
31
|
-
process tracker.initializers["secret_token.rb"]
|
26
|
+
["session_store.rb", "secret_token.rb"].each do |file|
|
27
|
+
if tracker.initializers[file] and not ignored? file
|
28
|
+
process tracker.initializers[file]
|
29
|
+
end
|
32
30
|
end
|
33
31
|
end
|
34
32
|
|
@@ -37,13 +35,16 @@ class Brakeman::CheckSessionSettings < Brakeman::BaseCheck
|
|
37
35
|
#
|
38
36
|
#and App::Application.config.secret_token =
|
39
37
|
#in Rails 3.x apps
|
38
|
+
#
|
39
|
+
#and App::Application.config.secret_key_base =
|
40
|
+
#in Rails 4.x apps
|
40
41
|
def process_attrasgn exp
|
41
42
|
if not tracker.options[:rails3] and exp.target == @session_settings and exp.method == :session=
|
42
43
|
check_for_issues exp.first_arg, "#{tracker.options[:app_path]}/config/initializers/session_store.rb"
|
43
44
|
end
|
44
45
|
|
45
46
|
if tracker.options[:rails3] and settings_target?(exp.target) and
|
46
|
-
exp.method == :secret_token= and string? exp.first_arg
|
47
|
+
(exp.method == :secret_token= or exp.method == :secret_key_base=) and string? exp.first_arg
|
47
48
|
|
48
49
|
warn_about_secret_token exp, "#{tracker.options[:app_path]}/config/initializers/secret_token.rb"
|
49
50
|
end
|
@@ -132,4 +133,14 @@ class Brakeman::CheckSessionSettings < Brakeman::BaseCheck
|
|
132
133
|
:line => value.line,
|
133
134
|
:file => file
|
134
135
|
end
|
136
|
+
|
137
|
+
def ignored? file
|
138
|
+
if @app_tree.exists? ".gitignore"
|
139
|
+
input = @app_tree.read(".gitignore")
|
140
|
+
|
141
|
+
input.include? file
|
142
|
+
else
|
143
|
+
false
|
144
|
+
end
|
145
|
+
end
|
135
146
|
end
|
@@ -3,7 +3,7 @@ require 'brakeman/checks/base_check'
|
|
3
3
|
class Brakeman::CheckSymbolDoS < Brakeman::BaseCheck
|
4
4
|
Brakeman::Checks.add self
|
5
5
|
|
6
|
-
@description = "Checks for versions with ActiveRecord symbol denial of service"
|
6
|
+
@description = "Checks for versions with ActiveRecord symbol denial of service, or code with a similar vulnerability"
|
7
7
|
|
8
8
|
def run_check
|
9
9
|
fix_version = case
|
@@ -14,10 +14,10 @@ class Brakeman::CheckSymbolDoS < Brakeman::BaseCheck
|
|
14
14
|
when version_between?('3.2.0', '3.2.12')
|
15
15
|
'3.2.13'
|
16
16
|
else
|
17
|
-
|
17
|
+
nil
|
18
18
|
end
|
19
19
|
|
20
|
-
|
20
|
+
if fix_version && active_record_models.any?
|
21
21
|
warn :warning_type => "Denial of Service",
|
22
22
|
:warning_code => :CVE_2013_1854,
|
23
23
|
:message => "Rails #{tracker.config[:rails_version]} has a denial of service vulnerability in ActiveRecord: upgrade to #{fix_version} or patch",
|
@@ -25,5 +25,52 @@ class Brakeman::CheckSymbolDoS < Brakeman::BaseCheck
|
|
25
25
|
:file => gemfile_or_environment,
|
26
26
|
:link => "https://groups.google.com/d/msg/rubyonrails-security/jgJ4cjjS8FE/BGbHRxnDRTIJ"
|
27
27
|
end
|
28
|
+
|
29
|
+
tracker.find_call(:methods => [:to_sym, :literal_to_sym], :nested => true).each do |result|
|
30
|
+
check_unsafe_symbol_creation(result)
|
31
|
+
end
|
32
|
+
|
28
33
|
end
|
34
|
+
|
35
|
+
def check_unsafe_symbol_creation result
|
36
|
+
|
37
|
+
call = result[:call]
|
38
|
+
if result[:method] == :to_sym
|
39
|
+
args = [call.target]
|
40
|
+
else
|
41
|
+
args = call.select { |e| sexp? e }
|
42
|
+
end
|
43
|
+
|
44
|
+
if input = args.map{ |arg| has_immediate_user_input?(arg) }.compact.first
|
45
|
+
confidence = CONFIDENCE[:high]
|
46
|
+
elsif input = args.map{ |arg| include_user_input?(arg) }.compact.first
|
47
|
+
confidence = CONFIDENCE[:med]
|
48
|
+
end
|
49
|
+
|
50
|
+
if confidence
|
51
|
+
input_type = case input.type
|
52
|
+
when :params
|
53
|
+
"parameter value"
|
54
|
+
when :cookies
|
55
|
+
"cookies value"
|
56
|
+
when :request
|
57
|
+
"request value"
|
58
|
+
when :model
|
59
|
+
"model attribute"
|
60
|
+
else
|
61
|
+
"user input"
|
62
|
+
end
|
63
|
+
|
64
|
+
message = "Symbol conversion from unsafe string (#{input_type})"
|
65
|
+
|
66
|
+
warn :result => result,
|
67
|
+
:warning_type => "Denial of Service",
|
68
|
+
:warning_code => :unsafe_symbol_creation,
|
69
|
+
:message => message,
|
70
|
+
:user_input => input.match,
|
71
|
+
:confidence => confidence
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
|
29
76
|
end
|
@@ -19,7 +19,7 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
|
|
19
19
|
def initialize tracker = nil
|
20
20
|
super()
|
21
21
|
@env = SexpProcessor::Environment.new
|
22
|
-
@inside_if =
|
22
|
+
@inside_if = false
|
23
23
|
@ignore_ifs = nil
|
24
24
|
@exp_context = []
|
25
25
|
@current_module = nil
|
@@ -167,6 +167,41 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
|
|
167
167
|
exp
|
168
168
|
end
|
169
169
|
|
170
|
+
def process_call_with_block exp
|
171
|
+
exp[1] = process exp.block_call
|
172
|
+
|
173
|
+
env.scope do
|
174
|
+
exp.block_args.each do |e|
|
175
|
+
#Force block arg(s) to be local
|
176
|
+
if node_type? e, :lasgn
|
177
|
+
env.current[Sexp.new(:lvar, e.lhs)] = e.rhs
|
178
|
+
elsif node_type? e, :masgn
|
179
|
+
e[1..-1].each do |var|
|
180
|
+
local = Sexp.new(:lvar, var)
|
181
|
+
env.current[local] = local
|
182
|
+
end
|
183
|
+
elsif e.is_a? Symbol
|
184
|
+
local = Sexp.new(:lvar, e)
|
185
|
+
env.current[local] = local
|
186
|
+
else
|
187
|
+
raise "Unexpected value in block args: #{e.inspect}"
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
block = exp.block
|
192
|
+
|
193
|
+
if block? block
|
194
|
+
process_all! block
|
195
|
+
else
|
196
|
+
exp[3] = process block
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
exp
|
201
|
+
end
|
202
|
+
|
203
|
+
alias process_iter process_call_with_block
|
204
|
+
|
170
205
|
#Process a new scope.
|
171
206
|
def process_scope exp
|
172
207
|
env.scope do
|
@@ -232,8 +267,9 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
|
|
232
267
|
def process_gasgn exp
|
233
268
|
match = Sexp.new(:gvar, exp.lhs)
|
234
269
|
value = exp.rhs = process(exp.rhs)
|
270
|
+
value.line = exp.line
|
235
271
|
|
236
|
-
set_value match, value
|
272
|
+
set_value match, value
|
237
273
|
|
238
274
|
exp
|
239
275
|
end
|
@@ -244,7 +280,7 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
|
|
244
280
|
match = Sexp.new(:cvar, exp.lhs)
|
245
281
|
value = exp.rhs = process(exp.rhs)
|
246
282
|
|
247
|
-
set_value match, value
|
283
|
+
set_value match, value
|
248
284
|
|
249
285
|
exp
|
250
286
|
end
|
@@ -265,7 +301,7 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
|
|
265
301
|
value = exp.second_arg = process(value_arg)
|
266
302
|
match = Sexp.new(:call, target, :[], index)
|
267
303
|
|
268
|
-
set_value match, value
|
304
|
+
set_value match, value
|
269
305
|
|
270
306
|
if hash? target
|
271
307
|
env[tar_variable] = hash_insert target.deep_clone, index, value
|
@@ -275,7 +311,7 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
|
|
275
311
|
#This is what we'll replace with the value
|
276
312
|
match = Sexp.new(:call, target, method.to_s[0..-2].to_sym)
|
277
313
|
|
278
|
-
set_value match, value
|
314
|
+
set_value match, value
|
279
315
|
else
|
280
316
|
raise "Unrecognized assignment: #{exp}"
|
281
317
|
end
|
@@ -377,34 +413,69 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
|
|
377
413
|
|
378
414
|
condition = process exp.condition
|
379
415
|
|
416
|
+
#Check if a branch is obviously going to be taken
|
380
417
|
if true? condition
|
381
418
|
no_branch = true
|
382
|
-
exps = [exp.then_clause]
|
419
|
+
exps = [exp.then_clause, nil]
|
383
420
|
elsif false? condition
|
384
421
|
no_branch = true
|
385
|
-
exps = [exp.else_clause]
|
422
|
+
exps = [nil, exp.else_clause]
|
386
423
|
else
|
387
424
|
no_branch = false
|
388
425
|
exps = [exp.then_clause, exp.else_clause]
|
389
426
|
end
|
390
427
|
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
428
|
+
if @ignore_ifs or no_branch
|
429
|
+
exps.each_with_index do |branch, i|
|
430
|
+
exp[2 + i] = process_if_branch branch
|
431
|
+
end
|
432
|
+
else
|
433
|
+
was_inside = @inside_if
|
434
|
+
@inside_if = true
|
435
|
+
|
436
|
+
branch_scopes = []
|
437
|
+
exps.each_with_index do |branch, i|
|
438
|
+
scope do
|
439
|
+
branch_index = 2 + i # s(:if, condition, then_branch, else_branch)
|
440
|
+
exp[branch_index] = process_if_branch branch
|
441
|
+
branch_scopes << env.current
|
399
442
|
end
|
400
443
|
end
|
401
444
|
|
402
|
-
@inside_if
|
445
|
+
@inside_if = was_inside
|
446
|
+
|
447
|
+
branch_scopes.each do |s|
|
448
|
+
merge_if_branch s
|
449
|
+
end
|
403
450
|
end
|
404
451
|
|
405
452
|
exp
|
406
453
|
end
|
407
454
|
|
455
|
+
def process_if_branch exp
|
456
|
+
if sexp? exp
|
457
|
+
if block? exp
|
458
|
+
process_default exp
|
459
|
+
else
|
460
|
+
process exp
|
461
|
+
end
|
462
|
+
end
|
463
|
+
end
|
464
|
+
|
465
|
+
def merge_if_branch branch_env
|
466
|
+
branch_env.each do |k, v|
|
467
|
+
current_val = env[k]
|
468
|
+
|
469
|
+
if current_val
|
470
|
+
unless same_value? current_val, v
|
471
|
+
env[k] = Sexp.new(:or, current_val, v).line(k.line || -2)
|
472
|
+
end
|
473
|
+
else
|
474
|
+
env[k] = v
|
475
|
+
end
|
476
|
+
end
|
477
|
+
end
|
478
|
+
|
408
479
|
#Process single integer access to an array.
|
409
480
|
#
|
410
481
|
#Returns the value inside the array, if possible.
|
@@ -601,12 +672,6 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
|
|
601
672
|
nil
|
602
673
|
end
|
603
674
|
|
604
|
-
#Return true if this value should be "branched" - i.e. converted into an or
|
605
|
-
#expression with two or more values
|
606
|
-
def branch_value? exp
|
607
|
-
not (@inside_if.empty? or @inside_if.last.include? exp)
|
608
|
-
end
|
609
|
-
|
610
675
|
#Return true if lhs == rhs or lhs is an or expression and
|
611
676
|
#rhs is one of its values
|
612
677
|
def same_value? lhs, rhs
|
@@ -619,32 +684,41 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
|
|
619
684
|
end
|
620
685
|
end
|
621
686
|
|
687
|
+
def value_from_if exp
|
688
|
+
if block? exp.else_clause or block? exp.then_clause
|
689
|
+
#If either clause is more than a single expression, just use entire
|
690
|
+
#if expression for now
|
691
|
+
exp
|
692
|
+
elsif exp.else_clause.nil?
|
693
|
+
exp.then_clause
|
694
|
+
elsif exp.then_clause.nil?
|
695
|
+
exp.else_clause
|
696
|
+
else
|
697
|
+
condition = exp.condition
|
698
|
+
|
699
|
+
if true? condition
|
700
|
+
exp.then_clause
|
701
|
+
elsif false? condition
|
702
|
+
exp.else_clause
|
703
|
+
else
|
704
|
+
Sexp.new(:or, exp.then_clause, exp.else_clause).line(exp.line)
|
705
|
+
end
|
706
|
+
end
|
707
|
+
end
|
708
|
+
|
622
709
|
#Set variable to given value.
|
623
710
|
#Creates "branched" versions of values when appropriate.
|
624
711
|
#Avoids creating multiple branched versions inside same
|
625
712
|
#if branch.
|
626
|
-
def set_value var, value
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
if branch_value? var and current_val = env[var]
|
632
|
-
unless same_value? current_val, value
|
633
|
-
env[var] = Sexp.new(:or, current_val, value).line(line || var.line || -2)
|
634
|
-
current_if << var
|
635
|
-
end
|
636
|
-
elsif current_if and current_if.include?(var) and node_type?(current_val, :or)
|
637
|
-
#Replace last value instead of creating another or
|
638
|
-
current_val.rhs = value
|
639
|
-
else
|
640
|
-
env[var] = value
|
713
|
+
def set_value var, value
|
714
|
+
if node_type? value, :if
|
715
|
+
value = value_from_if(value)
|
716
|
+
end
|
641
717
|
|
642
|
-
|
643
|
-
current_if << var
|
644
|
-
end
|
645
|
-
end
|
646
|
-
else
|
718
|
+
if @ignore_ifs or not @inside_if
|
647
719
|
env[var] = value
|
720
|
+
else
|
721
|
+
env.current[var] = value
|
648
722
|
end
|
649
723
|
end
|
650
724
|
|