提交 0e792305 编写于 作者: P Patrick Toomey 提交者: Justin Collins

Add support for namespaced models

上级 1eb6498b
......@@ -55,21 +55,24 @@ class Brakeman::ControllerProcessor < Brakeman::BaseProcessor
name = (@current_module[:name].to_s + "::" + name.to_s).to_sym
end
if @tracker.controllers[name.to_sym]
if @tracker.controllers[name]
@current_class = @tracker.controllers[name]
@current_class[:files] << @file_name unless @current_class[:files].include? @file_name
@current_class[:src][@file_name] = exp
else
@current_class = { :name => name,
:parent => parent,
:includes => [],
:public => {},
:private => {},
:protected => {},
:options => {:before_filters => []},
:src => { @file_name => exp },
:files => [ @file_name ] }
@tracker.controllers[@current_class[:name]] = @current_class
@current_class = {
:name => name,
:parent => parent,
:includes => [],
:public => {},
:private => {},
:protected => {},
:options => {:before_filters => []},
:src => { @file_name => exp },
:files => [ @file_name ]
}
@tracker.controllers[name] = @current_class
end
exp.body = process_all! exp.body
......@@ -98,20 +101,24 @@ class Brakeman::ControllerProcessor < Brakeman::BaseProcessor
if @tracker.libs[name]
@current_module = @tracker.libs[name]
@current_module[:files] << @file_name
@current_module[:files] << @file_name unless @current_module[:files].include? @file_name
@current_module[:src][@file_name] = exp
else
@current_module = { :name => name,
:parent => parent,
:includes => [],
:public => {},
:private => {},
:protected => {},
:options => {:before_filters => []},
:src => exp,
:files => [@file_name] }
@current_module = {
:name => name,
:parent => parent,
:includes => [],
:public => {},
:private => {},
:protected => {},
:options => {:before_filters => []},
:src => { @file_name => exp },
:files => [ @file_name ]
}
@tracker.libs[name] = @current_module
end
exp.body = process_all! exp.body
if outer_module
......
......@@ -8,6 +8,8 @@ class Brakeman::LibraryProcessor < Brakeman::BaseProcessor
super
@file_name = nil
@alias_processor = Brakeman::AliasProcessor.new tracker
@current_module = nil
@current_class = nil
end
def process_library src, file_name = nil
......@@ -17,6 +19,7 @@ class Brakeman::LibraryProcessor < Brakeman::BaseProcessor
def process_class exp
name = class_name(exp.class_name)
parent = class_name exp.parent_name
if @current_class
outer_class = @current_class
......@@ -32,16 +35,16 @@ class Brakeman::LibraryProcessor < Brakeman::BaseProcessor
@current_class[:files] << @file_name unless @current_class[:files].include? @file_name
@current_class[:src][@file_name] = exp
else
parent = class_name exp.parent_name
@current_class = { :name => name,
:parent => parent,
:includes => [],
:public => {},
:private => {},
:protected => {},
:src => { @file_name => exp },
:files => [ @file_name ] }
@current_class = {
:name => name,
:parent => parent,
:includes => [],
:public => {},
:private => {},
:protected => {},
:src => { @file_name => exp },
:files => [ @file_name ]
}
@tracker.libs[name] = @current_class
end
......@@ -61,8 +64,8 @@ class Brakeman::LibraryProcessor < Brakeman::BaseProcessor
name = class_name(exp.module_name)
if @current_module
outer_class = @current_module
name = (outer_class[:name].to_s + "::" + name.to_s).to_sym
outer_module = @current_module
name = (outer_module[:name].to_s + "::" + name.to_s).to_sym
end
if @current_class
......@@ -71,22 +74,26 @@ class Brakeman::LibraryProcessor < Brakeman::BaseProcessor
if @tracker.libs[name]
@current_module = @tracker.libs[name]
@current_module[:files] << @file_name unless @current_module[:files].include? @file_name
@current_module[:src][@file_name] = exp
else
@current_module = { :name => name,
:includes => [],
:public => {},
:private => {},
:protected => {},
:src => exp,
:files => [@file_name] }
@current_module = {
:name => name,
:includes => [],
:public => {},
:private => {},
:protected => {},
:src => { @file_name => exp },
:files => [ @file_name ]
}
@tracker.libs[name] = @current_module
end
exp.body = process_all! exp.body
if outer_class
@current_module = outer_class
if outer_module
@current_module = outer_module
else
@current_module = nil
end
......
......@@ -7,8 +7,9 @@ class Brakeman::ModelProcessor < Brakeman::BaseProcessor
def initialize tracker
super
@model = nil
@current_class = nil
@current_method = nil
@current_module = nil
@visibility = :public
@file_name = nil
end
......@@ -24,36 +25,101 @@ class Brakeman::ModelProcessor < Brakeman::BaseProcessor
name = class_name(exp.class_name)
parent = class_name(exp.parent_name)
if @model
Brakeman.debug "[Notice] Skipping inner class: #{name}"
ignore
elsif @tracker.models[name.to_sym]
@model = @tracker.models[name]
@model[:files] << @file_name unless @model[:files].include? @file_name
exp.body = process_all! exp.body
@model = nil
exp
#If inside an inner class we treat it as a library.
if @current_class
Brakeman.debug "[Notice] Treating inner class as library: #{name}"
Brakeman::LibraryProcessor.new(@tracker).process_library exp, @file_name
return exp
end
if @current_class
outer_class = @current_class
name = (outer_class[:name].to_s + "::" + name.to_s).to_sym
end
if @current_module
name = (@current_module[:name].to_s + "::" + name.to_s).to_sym
end
if @tracker.models[name]
@current_class = @tracker.models[name]
@current_class[:files] << @file_name unless @current_class[:files].include? @file_name
@current_class[:src][@file_name] = exp
else
@model = { :name => name.to_sym,
@current_class = {
:name => name,
:parent => parent,
:includes => [],
:public => {},
:private => {},
:protected => {},
:options => {},
:src => { @file_name => exp },
:associations => {},
:files => [ @file_name ]
}
@tracker.models[name] = @current_class
end
exp.body = process_all! exp.body
if outer_class
@current_class = outer_class
else
@current_class = nil
end
exp
end
def process_module exp
name = class_name(exp.class_name)
if @current_module
outer_module = @current_module
name = (outer_module[:name].to_s + "::" + name.to_s).to_sym
end
if @current_class
name = (@current_class[:name].to_s + "::" + name.to_s).to_sym
end
if @tracker.libs[name]
@current_module = @tracker.libs[name]
@current_module[:files] << @file_name unless @current_module[:files].include? @file_name
@current_module[:src][@file_name] = exp
else
@current_module = {
:name => name,
:includes => [],
:public => {},
:private => {},
:protected => {},
:options => {},
:src => { @file_name => exp },
:associations => {},
:files => [@file_name] }
@tracker.models[@model[:name]] = @model
exp.body = process_all! exp.body
@model = nil
exp
:files => [ @file_name ]
}
@tracker.libs[name] = @current_module
end
exp.body = process_all! exp.body
if outer_module
@current_module = outer_module
else
@current_module = nil
end
exp
end
#Handle calls outside of methods,
#such as include, attr_accessible, private, etc.
def process_call exp
return exp unless @model
return exp unless @current_class
target = exp.target
if sexp? target
target = process target
......@@ -70,36 +136,36 @@ class Brakeman::ModelProcessor < Brakeman::BaseProcessor
when :private, :protected, :public
@visibility = method
when :attr_accessible
@model[:attr_accessible] ||= []
@current_class[:attr_accessible] ||= []
else
#??
end
else
case method
when :include
@model[:includes] << class_name(first_arg) if @model
@current_class[:includes] << class_name(first_arg) if @current_class
when :attr_accessible
@model[:attr_accessible] ||= []
@current_class[:attr_accessible] ||= []
args = []
exp.each_arg do |e|
if node_type? e, :lit
args << e.value
elsif hash? e
@model[:options][:role_accessible] ||= []
@model[:options][:role_accessible].concat args
@current_class[:options][:role_accessible] ||= []
@current_class[:options][:role_accessible].concat args
end
end
@model[:attr_accessible].concat args
@current_class[:attr_accessible].concat args
else
if @model
if @current_class
if ASSOCIATIONS.include? method
@model[:associations][method] ||= []
@model[:associations][method].concat exp.args
@current_class[:associations][method] ||= []
@current_class[:associations][method].concat exp.args
else
@model[:options][method] ||= []
@model[:options][method] << exp.arglist.line(exp.line)
@current_class[:options][method] ||= []
@current_class[:options][method] << exp.arglist.line(exp.line)
end
end
end
......@@ -114,27 +180,36 @@ class Brakeman::ModelProcessor < Brakeman::BaseProcessor
#Add method definition to tracker
def process_defn exp
return exp unless @model
return exp unless @current_class
name = exp.method_name
@current_method = name
res = Sexp.new :methdef, name, exp.formal_args, *process_all!(exp.body)
res.line(exp.line)
@current_method = nil
if @model
list = @model[@visibility]
list[name] = { :src => res, :file => @file_name }
if @current_class
@current_class[@visibility][name] = { :src => res, :file => @file_name }
elsif @current_module
@current_module[@visibility][name] = { :src => res, :file => @file_name }
end
res
end
#Add method definition to tracker
def process_defs exp
return exp unless @model
return exp unless @current_class
name = exp.method_name
if exp[1].node_type == :self
target = @model[:name]
if @current_class
target = @current_class[:name]
elsif @current_module
target = @current_module
else
target = nil
end
else
target = class_name exp[1]
end
......@@ -143,8 +218,11 @@ class Brakeman::ModelProcessor < Brakeman::BaseProcessor
res = Sexp.new :selfdef, target, name, exp.formal_args, *process_all!(exp.body)
res.line(exp.line)
@current_method = nil
if @model
@model[@visibility][name] = { :src => res, :file => @file_name }
if @current_class
@current_class[@visibility][name] = { :src => res, :file => @file_name }
elsif @current_module
@current_module[@visibility][name] = { :src => res, :file => @file_name }
end
res
end
......
module MultiModel
class Model1 < ActiveRecord::Base
def model_exec
system params[:user_input]
end
end
class Model2 < ActiveRecord::Base
def model_exec
system params[:user_input2]
end
end
end
......@@ -16,7 +16,7 @@ class Rails32Tests < Test::Unit::TestCase
:controller => 8,
:model => 5,
:template => 11,
:generic => 14 }
:generic => 16 }
if RUBY_PLATFORM == 'java'
@expected[:generic] += 1
......@@ -336,9 +336,9 @@ class Rails32Tests < Test::Unit::TestCase
:format_code => /params\[:user_input\]/
end
def test_controller_default_routes
def test_controller_default_routes
# Test to ensure warnings are generated for loose routes
assert_warning :type => :controller,
assert_warning :type => :controller,
:warning_type => "Default Routes",
:message => /GlobGetController.*get requests/,
:fingerprint => "6550aaf3da845a600a9c8fb767d08489679a9e3d89554db3c920ddb4eafcfb8e",
......@@ -385,5 +385,29 @@ class Rails32Tests < Test::Unit::TestCase
:message => /BarMatchController.*matched requests/,
:fingerprint => "857efc249dfd1b5086dcf79c35e31ef19a7782d03b3beaa12f55f8634b543d2d",
:file => /routes\.rb/
end
end
def test_command_injection_from_namespaced_model_1
assert_warning :type => :warning,
:warning_type => "Command Injection",
:class => :"MultiModel::Model1",
:line => 5,
:message => /^Possible command injection/,
:confidence => 0,
:file => /multi_model\.rb/,
:relative_path => "app/models/multi_model.rb",
:format_code => /params\[:user_input\]/
end
def test_command_injection_from_namespaced_model_2
assert_warning :type => :warning,
:warning_type => "Command Injection",
:class => :"MultiModel::Model2",
:line => 13,
:message => /^Possible command injection/,
:confidence => 0,
:file => /multi_model\.rb/,
:relative_path => "app/models/multi_model.rb",
:format_code => /params\[:user_input2\]/
end
end
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册