brakeman 1.0.0 → 1.1.pre
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/brakeman +13 -0
- data/lib/brakeman.rb +7 -1
- data/lib/brakeman/processors/alias_processor.rb +63 -12
- data/lib/brakeman/processors/haml_template_processor.rb +1 -1
- data/lib/brakeman/processors/lib/render_helper.rb +1 -1
- data/lib/brakeman/processors/library_processor.rb +2 -2
- data/lib/brakeman/processors/template_alias_processor.rb +12 -0
- data/lib/brakeman/scanner.rb +89 -20
- data/lib/brakeman/util.rb +5 -10
- data/lib/brakeman/version.rb +1 -1
- data/lib/ruby_parser/ruby_parser_extras.rb +89 -1
- metadata +52 -28
data/bin/brakeman
CHANGED
@@ -24,6 +24,10 @@ OptionParser.new do |opts|
|
|
24
24
|
options[:parallel_checks] = false
|
25
25
|
end
|
26
26
|
|
27
|
+
opts.on "--no-progress", "Do not show progress reports" do
|
28
|
+
options[:report_progress] = false
|
29
|
+
end
|
30
|
+
|
27
31
|
opts.on "-p", "--path PATH", "Specify path to Rails application" do |path|
|
28
32
|
options[:app_path] = File.expand_path path
|
29
33
|
end
|
@@ -55,6 +59,15 @@ OptionParser.new do |opts|
|
|
55
59
|
options[:escape_html] = true
|
56
60
|
end
|
57
61
|
|
62
|
+
opts.on "--faster", "Faster, but less accurate scan" do
|
63
|
+
options[:ignore_ifs] = true
|
64
|
+
options[:skip_libs] = true
|
65
|
+
end
|
66
|
+
|
67
|
+
opts.on "--no-branching", "Disable flow sensitivity on conditionals" do
|
68
|
+
options[:ignore_ifs] = true
|
69
|
+
end
|
70
|
+
|
58
71
|
opts.on "-r", "--report-direct", "Only report direct use of untrusted data" do |option|
|
59
72
|
options[:check_arguments] = !option
|
60
73
|
end
|
data/lib/brakeman.rb
CHANGED
@@ -48,6 +48,7 @@ module Brakeman
|
|
48
48
|
options = set_options options
|
49
49
|
|
50
50
|
if options[:quiet]
|
51
|
+
options[:report_progress] = false
|
51
52
|
$VERBOSE = nil
|
52
53
|
end
|
53
54
|
|
@@ -120,6 +121,7 @@ module Brakeman
|
|
120
121
|
:message_limit => 100,
|
121
122
|
:parallel_checks => true,
|
122
123
|
:quiet => true,
|
124
|
+
:report_progress => true,
|
123
125
|
:html_style => "#{File.expand_path(File.dirname(__FILE__))}/brakeman/format/style.css"
|
124
126
|
}
|
125
127
|
end
|
@@ -206,7 +208,11 @@ module Brakeman
|
|
206
208
|
warn "Processing application in #{options[:app_path]}"
|
207
209
|
tracker = scanner.process
|
208
210
|
|
209
|
-
|
211
|
+
if options[:parallel_checks]
|
212
|
+
warn "Running checks in parallel..."
|
213
|
+
else
|
214
|
+
warn "Runnning checks..."
|
215
|
+
end
|
210
216
|
tracker.run_checks
|
211
217
|
|
212
218
|
if options[:output_file]
|
@@ -25,6 +25,9 @@ class Brakeman::AliasProcessor < SexpProcessor
|
|
25
25
|
self.default_method = :process_default
|
26
26
|
self.warn_on_default = false
|
27
27
|
@env = SexpProcessor::Environment.new
|
28
|
+
@inside_if = false
|
29
|
+
@ignore_ifs = false
|
30
|
+
@tracker = nil #set in subclass as necessary
|
28
31
|
set_env_defaults
|
29
32
|
end
|
30
33
|
|
@@ -117,6 +120,20 @@ class Brakeman::AliasProcessor < SexpProcessor
|
|
117
120
|
joined = join_strings target, args[1]
|
118
121
|
joined.line(exp.line)
|
119
122
|
exp = joined
|
123
|
+
elsif number? target and number? args[1]
|
124
|
+
exp = Sexp.new(:lit, target[1] + args[1][1])
|
125
|
+
end
|
126
|
+
when :-
|
127
|
+
if number? target and number? args[1]
|
128
|
+
exp = Sexp.new(:lit, target[1] - args[1][1])
|
129
|
+
end
|
130
|
+
when :*
|
131
|
+
if number? target and number? args[1]
|
132
|
+
exp = Sexp.new(:lit, target[1] * args[1][1])
|
133
|
+
end
|
134
|
+
when :/
|
135
|
+
if number? target and number? args[1]
|
136
|
+
exp = Sexp.new(:lit, target[1] / args[1][1])
|
120
137
|
end
|
121
138
|
when :[]
|
122
139
|
if array? target
|
@@ -136,6 +153,19 @@ class Brakeman::AliasProcessor < SexpProcessor
|
|
136
153
|
if hash? target and hash? args[1]
|
137
154
|
return process_hash_merge(target, args[1])
|
138
155
|
end
|
156
|
+
when :<<
|
157
|
+
if string? target and string? args[1]
|
158
|
+
target[1] << args[1][1]
|
159
|
+
env[target_var] = target
|
160
|
+
return target
|
161
|
+
elsif array? target
|
162
|
+
target << args[1]
|
163
|
+
env[target_var] = target
|
164
|
+
return target
|
165
|
+
else
|
166
|
+
target = find_push_target exp
|
167
|
+
env[target] = exp unless target.nil? #Happens in TemplateAliasProcessor
|
168
|
+
end
|
139
169
|
end
|
140
170
|
|
141
171
|
exp
|
@@ -183,8 +213,10 @@ class Brakeman::AliasProcessor < SexpProcessor
|
|
183
213
|
exp[2] = process exp[2] if sexp? exp[2]
|
184
214
|
local = Sexp.new(:lvar, exp[1]).line(exp.line || -2)
|
185
215
|
|
186
|
-
if @inside_if and env[local]
|
187
|
-
|
216
|
+
if @inside_if and val = env[local]
|
217
|
+
if val != exp[2] #avoid setting to value it already is (e.g. "1 or 1")
|
218
|
+
env[local] = Sexp.new(:or, val, exp[2]).line(exp.line || -2)
|
219
|
+
end
|
188
220
|
else
|
189
221
|
env[local] = exp[2]
|
190
222
|
end
|
@@ -198,8 +230,10 @@ class Brakeman::AliasProcessor < SexpProcessor
|
|
198
230
|
exp[2] = process exp[2]
|
199
231
|
ivar = Sexp.new(:ivar, exp[1]).line(exp.line)
|
200
232
|
|
201
|
-
if @inside_if and env[ivar]
|
202
|
-
|
233
|
+
if @inside_if and val = env[ivar]
|
234
|
+
if val != exp[2]
|
235
|
+
env[ivar] = Sexp.new(:or, val, exp[2]).line(exp.line)
|
236
|
+
end
|
203
237
|
else
|
204
238
|
env[ivar] = exp[2]
|
205
239
|
end
|
@@ -213,8 +247,10 @@ class Brakeman::AliasProcessor < SexpProcessor
|
|
213
247
|
match = Sexp.new(:gvar, exp[1])
|
214
248
|
value = exp[2] = process(exp[2])
|
215
249
|
|
216
|
-
if @inside_if and env[match]
|
217
|
-
|
250
|
+
if @inside_if and val = env[match]
|
251
|
+
if val != value
|
252
|
+
env[match] = Sexp.new(:or, env[match], value)
|
253
|
+
end
|
218
254
|
else
|
219
255
|
env[match] = value
|
220
256
|
end
|
@@ -228,8 +264,10 @@ class Brakeman::AliasProcessor < SexpProcessor
|
|
228
264
|
match = Sexp.new(:cvar, exp[1])
|
229
265
|
value = exp[2] = process(exp[2])
|
230
266
|
|
231
|
-
if @inside_if and env[match]
|
232
|
-
|
267
|
+
if @inside_if and val = env[match]
|
268
|
+
if val != value
|
269
|
+
env[match] = Sexp.new(:or, env[match], value)
|
270
|
+
end
|
233
271
|
else
|
234
272
|
env[match] = value
|
235
273
|
end
|
@@ -259,8 +297,10 @@ class Brakeman::AliasProcessor < SexpProcessor
|
|
259
297
|
#This is what we'll replace with the value
|
260
298
|
match = Sexp.new(:call, target, method.to_s[0..-2].to_sym, Sexp.new(:arglist))
|
261
299
|
|
262
|
-
if @inside_if and env[match]
|
263
|
-
|
300
|
+
if @inside_if and val = env[match]
|
301
|
+
if val != value
|
302
|
+
env[match] = Sexp.new(:or, env[match], value)
|
303
|
+
end
|
264
304
|
else
|
265
305
|
env[match] = value
|
266
306
|
end
|
@@ -349,8 +389,7 @@ class Brakeman::AliasProcessor < SexpProcessor
|
|
349
389
|
|
350
390
|
#Sets @inside_if = true
|
351
391
|
def process_if exp
|
352
|
-
|
353
|
-
@inside_if = true
|
392
|
+
@ignore_ifs ||= @tracker && @tracker.options[:ignore_ifs]
|
354
393
|
|
355
394
|
condition = process exp[1]
|
356
395
|
|
@@ -362,6 +401,9 @@ class Brakeman::AliasProcessor < SexpProcessor
|
|
362
401
|
exps = exp[2..-1]
|
363
402
|
end
|
364
403
|
|
404
|
+
was_inside = @inside_if
|
405
|
+
@inside_if = !@ignore_ifs
|
406
|
+
|
365
407
|
exps.each do |e|
|
366
408
|
process e if sexp? e
|
367
409
|
end
|
@@ -436,4 +478,13 @@ class Brakeman::AliasProcessor < SexpProcessor
|
|
436
478
|
|
437
479
|
exp
|
438
480
|
end
|
481
|
+
|
482
|
+
#Finds the inner most call target which is not the target of a call to <<
|
483
|
+
def find_push_target exp
|
484
|
+
if call? exp and exp[2] == :<<
|
485
|
+
find_push_target exp[1]
|
486
|
+
else
|
487
|
+
exp
|
488
|
+
end
|
489
|
+
end
|
439
490
|
end
|
@@ -31,7 +31,7 @@ class Brakeman::HamlTemplateProcessor < Brakeman::TemplateProcessor
|
|
31
31
|
|
32
32
|
if (sexp? target and target[2] == :_hamlout) or target == :_hamlout
|
33
33
|
res = case method
|
34
|
-
when :adjust_tabs, :rstrip
|
34
|
+
when :adjust_tabs, :rstrip!, :attributes #Check attributes, maybe?
|
35
35
|
ignore
|
36
36
|
when :options
|
37
37
|
Sexp.new :call, :_hamlout, :options, exp[3]
|
@@ -59,7 +59,7 @@ module Brakeman::RenderHelper
|
|
59
59
|
#Hash the environment and the source of the template to avoid
|
60
60
|
#pointlessly processing templates, which can become prohibitively
|
61
61
|
#expensive in terms of time and memory.
|
62
|
-
digest = Digest::SHA1.new.update(template_env.instance_variable_get(:@env).to_a.sort.to_s <<
|
62
|
+
digest = Digest::SHA1.new.update(template_env.instance_variable_get(:@env).to_a.sort.to_s << name).to_s.to_sym
|
63
63
|
|
64
64
|
if @tracker.template_cache.include? digest
|
65
65
|
#Already processed this template with identical environment
|
@@ -92,7 +92,7 @@ class Brakeman::LibraryProcessor < Brakeman::BaseProcessor
|
|
92
92
|
|
93
93
|
def process_defn exp
|
94
94
|
exp[0] = :methdef
|
95
|
-
exp[3] = @alias_processor.
|
95
|
+
exp[3] = @alias_processor.process exp[3]
|
96
96
|
|
97
97
|
if @current_class
|
98
98
|
@current_class[:public][exp[1]] = exp[3]
|
@@ -105,7 +105,7 @@ class Brakeman::LibraryProcessor < Brakeman::BaseProcessor
|
|
105
105
|
|
106
106
|
def process_defs exp
|
107
107
|
exp[0] = :selfdef
|
108
|
-
exp[4] = @alias_processor.
|
108
|
+
exp[4] = @alias_processor.process exp[4]
|
109
109
|
|
110
110
|
if @current_class
|
111
111
|
@current_class[:public][exp[2]] = exp[4]
|
@@ -83,4 +83,16 @@ class Brakeman::TemplateAliasProcessor < Brakeman::AliasProcessor
|
|
83
83
|
|
84
84
|
false
|
85
85
|
end
|
86
|
+
|
87
|
+
def find_push_target exp
|
88
|
+
if sexp? exp
|
89
|
+
if exp.node_type == :lvar and (exp[1] == :_buf or exp[1] == :_erbout)
|
90
|
+
return nil
|
91
|
+
elsif exp.node_type == :ivar and exp[1] == :@output_buffer
|
92
|
+
return nil
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
super
|
97
|
+
end
|
86
98
|
end
|
data/lib/brakeman/scanner.rb
CHANGED
@@ -32,6 +32,7 @@ class Brakeman::Scanner
|
|
32
32
|
#Pass in path to the root of the Rails application
|
33
33
|
def initialize options
|
34
34
|
@options = options
|
35
|
+
@report_progress = options[:report_progress]
|
35
36
|
@path = options[:app_path]
|
36
37
|
@app_path = File.join(@path, "app")
|
37
38
|
@processor = Brakeman::Processor.new options
|
@@ -58,15 +59,15 @@ class Brakeman::Scanner
|
|
58
59
|
process_initializers
|
59
60
|
warn "Processing libs..."
|
60
61
|
process_libs
|
61
|
-
warn "Processing routes..."
|
62
|
+
warn "Processing routes... "
|
62
63
|
process_routes
|
63
|
-
warn "Processing templates..."
|
64
|
+
warn "Processing templates... "
|
64
65
|
process_templates
|
65
|
-
warn "Processing models..."
|
66
|
+
warn "Processing models... "
|
66
67
|
process_models
|
67
|
-
warn "Processing controllers..."
|
68
|
+
warn "Processing controllers... "
|
68
69
|
process_controllers
|
69
|
-
warn "Indexing call sites..."
|
70
|
+
warn "Indexing call sites... "
|
70
71
|
index_call_sites
|
71
72
|
tracker
|
72
73
|
end
|
@@ -76,18 +77,14 @@ class Brakeman::Scanner
|
|
76
77
|
#Stores parsed information in tracker.config
|
77
78
|
def process_config
|
78
79
|
if options[:rails3]
|
79
|
-
|
80
|
-
|
80
|
+
process_config_file "application.rb"
|
81
|
+
process_config_file "environments/production.rb"
|
81
82
|
else
|
82
|
-
|
83
|
-
|
84
|
-
if File.exists? "#@path/config/gems.rb"
|
85
|
-
@processor.process_config(parse_ruby(File.read("#@path/config/gems.rb")))
|
86
|
-
end
|
87
|
-
|
83
|
+
process_config_file "environment.rb"
|
84
|
+
process_config_file "gems.rb"
|
88
85
|
end
|
89
86
|
|
90
|
-
if File.exists? "#@path/vendor/plugins/rails_xss" or
|
87
|
+
if File.exists? "#@path/vendor/plugins/rails_xss" or
|
91
88
|
options[:rails3] or options[:escape_html] or
|
92
89
|
(File.exists? "#@path/Gemfile" and File.read("#@path/Gemfile").include? "rails_xss")
|
93
90
|
|
@@ -96,6 +93,18 @@ class Brakeman::Scanner
|
|
96
93
|
end
|
97
94
|
end
|
98
95
|
|
96
|
+
def process_config_file file
|
97
|
+
if File.exists? "#@path/config/#{file}"
|
98
|
+
@processor.process_config(parse_ruby(File.read("#@path/config/#{file}")))
|
99
|
+
end
|
100
|
+
|
101
|
+
rescue Exception => e
|
102
|
+
warn "[Notice] Error while processing config/#{file}"
|
103
|
+
tracker.error e.exception(e.message + "\nwhile processing Gemfile"), e.backtrace
|
104
|
+
end
|
105
|
+
|
106
|
+
private :process_config_file
|
107
|
+
|
99
108
|
#Process Gemfile
|
100
109
|
def process_gems
|
101
110
|
if File.exists? "#@path/Gemfile"
|
@@ -105,6 +114,9 @@ class Brakeman::Scanner
|
|
105
114
|
@processor.process_gems(parse_ruby(File.read("#@path/Gemfile")))
|
106
115
|
end
|
107
116
|
end
|
117
|
+
rescue Exception => e
|
118
|
+
warn "[Notice] Error while processing Gemfile."
|
119
|
+
tracker.error e.exception(e.message + "\nWhile processing Gemfile"), e.backtrace
|
108
120
|
end
|
109
121
|
|
110
122
|
#Process all the .rb files in config/initializers/
|
@@ -131,7 +143,17 @@ class Brakeman::Scanner
|
|
131
143
|
return
|
132
144
|
end
|
133
145
|
|
134
|
-
Dir.glob(@path + "/lib/**/*.rb").sort
|
146
|
+
lib_files = Dir.glob(@path + "/lib/**/*.rb").sort
|
147
|
+
total = lib_files.length
|
148
|
+
current = 0
|
149
|
+
|
150
|
+
lib_files.each do |f|
|
151
|
+
warn "Processing #{f}" if options[:debug]
|
152
|
+
if @report_progress
|
153
|
+
$stderr.print " #{current}/#{total} files processed\r"
|
154
|
+
current += 1
|
155
|
+
end
|
156
|
+
|
135
157
|
begin
|
136
158
|
@processor.process_lib parse_ruby(File.read(f)), f
|
137
159
|
rescue Racc::ParseError => e
|
@@ -163,7 +185,17 @@ class Brakeman::Scanner
|
|
163
185
|
#
|
164
186
|
#Adds processed controllers to tracker.controllers
|
165
187
|
def process_controllers
|
166
|
-
Dir.glob(@app_path + "/controllers/**/*.rb").sort
|
188
|
+
controller_files = Dir.glob(@app_path + "/controllers/**/*.rb").sort
|
189
|
+
total = controller_files.length * 2
|
190
|
+
current = 0
|
191
|
+
|
192
|
+
controller_files.each do |f|
|
193
|
+
warn "Processing #{f}" if options[:debug]
|
194
|
+
if @report_progress
|
195
|
+
$stderr.print " #{current}/#{total} files processed\r"
|
196
|
+
current += 1
|
197
|
+
end
|
198
|
+
|
167
199
|
begin
|
168
200
|
@processor.process_controller(parse_ruby(File.read(f)), f)
|
169
201
|
rescue Racc::ParseError => e
|
@@ -173,7 +205,17 @@ class Brakeman::Scanner
|
|
173
205
|
end
|
174
206
|
end
|
175
207
|
|
208
|
+
current = 0
|
209
|
+
total = tracker.controllers.length
|
210
|
+
|
211
|
+
warn "Processing data flow in controllers..."
|
212
|
+
|
176
213
|
tracker.controllers.each do |name, controller|
|
214
|
+
if @report_progress
|
215
|
+
$stderr.print " #{current}/#{total} controllers processed\r"
|
216
|
+
current += 1
|
217
|
+
end
|
218
|
+
|
177
219
|
@processor.process_controller_alias controller[:src]
|
178
220
|
end
|
179
221
|
end
|
@@ -187,8 +229,15 @@ class Brakeman::Scanner
|
|
187
229
|
$stdout.sync = true
|
188
230
|
count = 0
|
189
231
|
|
190
|
-
Dir.glob(views_path).sort
|
191
|
-
|
232
|
+
template_files = Dir.glob(views_path).sort
|
233
|
+
total = template_files.length
|
234
|
+
|
235
|
+
template_files.each do |f|
|
236
|
+
if @report_progress
|
237
|
+
$stderr.print " #{count}/#{total} files processed\r"
|
238
|
+
count += 1
|
239
|
+
end
|
240
|
+
|
192
241
|
type = f.match(/.*\.(erb|haml|rhtml)$/)[1].to_sym
|
193
242
|
type = :erb if type == :rhtml
|
194
243
|
name = template_path_to_name f
|
@@ -231,7 +280,17 @@ class Brakeman::Scanner
|
|
231
280
|
end
|
232
281
|
end
|
233
282
|
|
283
|
+
total = tracker.templates.length
|
284
|
+
count = 0
|
285
|
+
|
286
|
+
warn "Processing data flow in templates..."
|
287
|
+
|
234
288
|
tracker.templates.keys.dup.each do |name|
|
289
|
+
if @report_progress
|
290
|
+
count += 1
|
291
|
+
$stderr.print " #{count}/#{total} templates processed\r"
|
292
|
+
end
|
293
|
+
|
235
294
|
@processor.process_template_alias tracker.templates[name]
|
236
295
|
end
|
237
296
|
|
@@ -250,7 +309,17 @@ class Brakeman::Scanner
|
|
250
309
|
#
|
251
310
|
#Adds the processed models to tracker.models
|
252
311
|
def process_models
|
253
|
-
Dir.glob(@app_path + "/models/*.rb").sort
|
312
|
+
model_files = Dir.glob(@app_path + "/models/*.rb").sort
|
313
|
+
|
314
|
+
total = model_files.length
|
315
|
+
current = 0
|
316
|
+
|
317
|
+
model_files.each do |f|
|
318
|
+
if @report_progress
|
319
|
+
$stderr.print " #{current}/#{total} files processed\r"
|
320
|
+
current += 1
|
321
|
+
end
|
322
|
+
|
254
323
|
begin
|
255
324
|
@processor.process_model(parse_ruby(File.read(f)), f)
|
256
325
|
rescue Racc::ParseError => e
|
@@ -294,7 +363,7 @@ class Brakeman::RailsXSSErubis < ::Erubis::Eruby
|
|
294
363
|
lines[0..-2].each do |line|
|
295
364
|
src << "@output_buffer << ('" << escape_text(line) << "'.html_safe!);\n"
|
296
365
|
end
|
297
|
-
|
366
|
+
|
298
367
|
src << "@output_buffer << ('" << escape_text(lines.last) << "'.html_safe!);"
|
299
368
|
end
|
300
369
|
else
|
data/lib/brakeman/util.rb
CHANGED
@@ -125,6 +125,11 @@ module Brakeman::Util
|
|
125
125
|
exp.is_a? Sexp and exp.node_type == :lit and exp[1].is_a? Integer
|
126
126
|
end
|
127
127
|
|
128
|
+
#Check if _exp_ represents a number: s(:lit, ...)
|
129
|
+
def number? exp
|
130
|
+
exp.is_a? Sexp and exp.node_type == :lit and exp[1].is_a? Numeric
|
131
|
+
end
|
132
|
+
|
128
133
|
#Check if _exp_ represents a result: s(:result, ...)
|
129
134
|
def result? exp
|
130
135
|
exp.is_a? Sexp and exp.node_type == :result
|
@@ -182,13 +187,3 @@ module Brakeman::Util
|
|
182
187
|
exp.is_a? Sexp
|
183
188
|
end
|
184
189
|
end
|
185
|
-
|
186
|
-
class Sexp
|
187
|
-
def original_line line = nil
|
188
|
-
if line
|
189
|
-
@original_line = line
|
190
|
-
else
|
191
|
-
@original_line
|
192
|
-
end
|
193
|
-
end
|
194
|
-
end
|
data/lib/brakeman/version.rb
CHANGED
@@ -1052,7 +1052,7 @@ class Symbol
|
|
1052
1052
|
end
|
1053
1053
|
|
1054
1054
|
class Sexp
|
1055
|
-
|
1055
|
+
attr_reader :paren
|
1056
1056
|
|
1057
1057
|
def paren
|
1058
1058
|
@paren ||= false
|
@@ -1069,6 +1069,94 @@ class Sexp
|
|
1069
1069
|
|
1070
1070
|
alias :node_type :sexp_type
|
1071
1071
|
alias :values :sexp_body # TODO: retire
|
1072
|
+
|
1073
|
+
alias :old_init :initialize
|
1074
|
+
alias :old_push :<<
|
1075
|
+
alias :old_line :line
|
1076
|
+
alias :old_line_set :line=
|
1077
|
+
alias :old_file_set :file=
|
1078
|
+
alias :old_comments_set :comments=
|
1079
|
+
alias :old_compact :compact
|
1080
|
+
alias :old_fara :find_and_replace_all
|
1081
|
+
alias :old_find_node :find_node
|
1082
|
+
|
1083
|
+
def initialize *args
|
1084
|
+
old_init *args
|
1085
|
+
@original_line = nil
|
1086
|
+
@my_hash_value = nil
|
1087
|
+
end
|
1088
|
+
|
1089
|
+
def original_line line = nil
|
1090
|
+
if line
|
1091
|
+
@my_hash_value = nil
|
1092
|
+
@original_line = line
|
1093
|
+
else
|
1094
|
+
@original_line
|
1095
|
+
end
|
1096
|
+
end
|
1097
|
+
|
1098
|
+
def hash
|
1099
|
+
#There still seems to be some instances in which the hash of the
|
1100
|
+
#Sexp changes, but I have not found what method call is doing it.
|
1101
|
+
#Of course, Sexp is subclasses from Array, so who knows what might
|
1102
|
+
#be going on.
|
1103
|
+
@my_hash_value ||= super
|
1104
|
+
end
|
1105
|
+
|
1106
|
+
def line *args
|
1107
|
+
@my_hash_value = nil
|
1108
|
+
old_line *args
|
1109
|
+
end
|
1110
|
+
|
1111
|
+
def line= *args
|
1112
|
+
@my_hash_value = nil
|
1113
|
+
old_line_set *args
|
1114
|
+
end
|
1115
|
+
|
1116
|
+
def file= *args
|
1117
|
+
@my_hash_value = nil
|
1118
|
+
old_file_set *args
|
1119
|
+
end
|
1120
|
+
|
1121
|
+
def compact
|
1122
|
+
@my_hash_value = nil
|
1123
|
+
old_compact
|
1124
|
+
end
|
1125
|
+
|
1126
|
+
def find_and_replace_all *args
|
1127
|
+
@my_hash_value = nil
|
1128
|
+
old_fara *args
|
1129
|
+
end
|
1130
|
+
|
1131
|
+
def find_node *args
|
1132
|
+
@my_hash_value = nil
|
1133
|
+
old_find_node *args
|
1134
|
+
end
|
1135
|
+
|
1136
|
+
def paren= arg
|
1137
|
+
@my_hash_value = nil
|
1138
|
+
@paren = arg
|
1139
|
+
end
|
1140
|
+
|
1141
|
+
def comments= *args
|
1142
|
+
@my_hash_value = nil
|
1143
|
+
old_comments_set *args
|
1144
|
+
end
|
1145
|
+
end
|
1146
|
+
|
1147
|
+
#Invalidate hash cache if the Sexp changes
|
1148
|
+
[:[]=, :clear, :collect!, :compact!, :concat, :delete, :delete_at,
|
1149
|
+
:delete_if, :drop, :drop_while, :fill, :flatten!, :replace, :insert,
|
1150
|
+
:keep_if, :map!, :pop, :push, :reject!, :replace, :reverse!, :rotate!,
|
1151
|
+
:select!, :shift, :shuffle!, :slice!, :sort!, :sort_by!, :transpose,
|
1152
|
+
:uniq!, :unshift].each do |method|
|
1153
|
+
|
1154
|
+
Sexp.class_eval <<-RUBY
|
1155
|
+
def #{method} *args
|
1156
|
+
@my_hash_value = nil
|
1157
|
+
super
|
1158
|
+
end
|
1159
|
+
RUBY
|
1072
1160
|
end
|
1073
1161
|
|
1074
1162
|
# END HACK
|
metadata
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: brakeman
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
prerelease:
|
4
|
+
prerelease: true
|
5
5
|
segments:
|
6
6
|
- 1
|
7
|
-
-
|
8
|
-
-
|
9
|
-
version: 1.
|
7
|
+
- 1
|
8
|
+
- pre
|
9
|
+
version: 1.1.pre
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Justin Collins
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2011-12-
|
17
|
+
date: 2011-12-21 00:00:00 -08:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -23,18 +23,30 @@ dependencies:
|
|
23
23
|
requirement: &id001 !ruby/object:Gem::Requirement
|
24
24
|
none: false
|
25
25
|
requirements:
|
26
|
-
- -
|
26
|
+
- - ">="
|
27
27
|
- !ruby/object:Gem::Version
|
28
28
|
segments:
|
29
|
-
-
|
30
|
-
|
31
|
-
version: "2.2"
|
29
|
+
- 0
|
30
|
+
version: "0"
|
32
31
|
type: :runtime
|
33
32
|
version_requirements: *id001
|
34
33
|
- !ruby/object:Gem::Dependency
|
35
|
-
name:
|
34
|
+
name: i18n
|
36
35
|
prerelease: false
|
37
36
|
requirement: &id002 !ruby/object:Gem::Requirement
|
37
|
+
none: false
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
segments:
|
42
|
+
- 0
|
43
|
+
version: "0"
|
44
|
+
type: :runtime
|
45
|
+
version_requirements: *id002
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: ruby2ruby
|
48
|
+
prerelease: false
|
49
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
38
50
|
none: false
|
39
51
|
requirements:
|
40
52
|
- - ~>
|
@@ -42,14 +54,13 @@ dependencies:
|
|
42
54
|
segments:
|
43
55
|
- 1
|
44
56
|
- 2
|
45
|
-
|
46
|
-
version: 1.2.4
|
57
|
+
version: "1.2"
|
47
58
|
type: :runtime
|
48
|
-
version_requirements: *
|
59
|
+
version_requirements: *id003
|
49
60
|
- !ruby/object:Gem::Dependency
|
50
61
|
name: ruport
|
51
62
|
prerelease: false
|
52
|
-
requirement: &
|
63
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
53
64
|
none: false
|
54
65
|
requirements:
|
55
66
|
- - ~>
|
@@ -57,14 +68,13 @@ dependencies:
|
|
57
68
|
segments:
|
58
69
|
- 1
|
59
70
|
- 6
|
60
|
-
|
61
|
-
version: 1.6.3
|
71
|
+
version: "1.6"
|
62
72
|
type: :runtime
|
63
|
-
version_requirements: *
|
73
|
+
version_requirements: *id004
|
64
74
|
- !ruby/object:Gem::Dependency
|
65
75
|
name: erubis
|
66
76
|
prerelease: false
|
67
|
-
requirement: &
|
77
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
68
78
|
none: false
|
69
79
|
requirements:
|
70
80
|
- - ~>
|
@@ -72,14 +82,13 @@ dependencies:
|
|
72
82
|
segments:
|
73
83
|
- 2
|
74
84
|
- 6
|
75
|
-
|
76
|
-
version: 2.6.5
|
85
|
+
version: "2.6"
|
77
86
|
type: :runtime
|
78
|
-
version_requirements: *
|
87
|
+
version_requirements: *id005
|
79
88
|
- !ruby/object:Gem::Dependency
|
80
89
|
name: haml
|
81
90
|
prerelease: false
|
82
|
-
requirement: &
|
91
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
83
92
|
none: false
|
84
93
|
requirements:
|
85
94
|
- - ~>
|
@@ -87,10 +96,23 @@ dependencies:
|
|
87
96
|
segments:
|
88
97
|
- 3
|
89
98
|
- 0
|
90
|
-
|
91
|
-
version: 3.0.12
|
99
|
+
version: "3.0"
|
92
100
|
type: :runtime
|
93
|
-
version_requirements: *
|
101
|
+
version_requirements: *id006
|
102
|
+
- !ruby/object:Gem::Dependency
|
103
|
+
name: sass
|
104
|
+
prerelease: false
|
105
|
+
requirement: &id007 !ruby/object:Gem::Requirement
|
106
|
+
none: false
|
107
|
+
requirements:
|
108
|
+
- - ~>
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
segments:
|
111
|
+
- 3
|
112
|
+
- 0
|
113
|
+
version: "3.0"
|
114
|
+
type: :runtime
|
115
|
+
version_requirements: *id007
|
94
116
|
description: Brakeman detects security vulnerabilities in Ruby on Rails applications via static analysis.
|
95
117
|
email:
|
96
118
|
executables:
|
@@ -190,11 +212,13 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
190
212
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
191
213
|
none: false
|
192
214
|
requirements:
|
193
|
-
- - "
|
215
|
+
- - ">"
|
194
216
|
- !ruby/object:Gem::Version
|
195
217
|
segments:
|
196
|
-
-
|
197
|
-
|
218
|
+
- 1
|
219
|
+
- 3
|
220
|
+
- 1
|
221
|
+
version: 1.3.1
|
198
222
|
requirements: []
|
199
223
|
|
200
224
|
rubyforge_project:
|