提交 d6e01317 编写于 作者: B Bryan Helmkamp

Refactor: Introduce AppTree as facade for filesystem

* Cleans up duplicated logic for skipping files
* This is not being used for the install_rake_task behavior
上级 ef27b7ab
......@@ -40,7 +40,7 @@ module Brakeman
# * :skip_libs - do not process lib/ directory (default: false)
# * :skip_checks - checks not to run (run all if not specified)
# * :relative_path - show relative path of each file(default: false)
# * :summary_only - only output summary section of report
# * :summary_only - only output summary section of report
# (does not apply to tabs format)
#
#Alternatively, just supply a path as a string.
......@@ -68,15 +68,6 @@ module Brakeman
options = get_defaults.merge! options
options[:output_formats] = get_output_formats options
app_path = options[:app_path]
abort("Please supply the path to a Rails application.") unless app_path and File.exist? app_path + "/app"
if File.exist? app_path + "/script/rails"
options[:rails3] = true
notify "[Notice] Detected Rails 3 application" unless options[:quiet]
end
options
end
......@@ -116,8 +107,8 @@ module Brakeman
#Default set of options
def self.get_defaults
{ :skip_checks => Set.new,
:check_arguments => true,
{ :skip_checks => Set.new,
:check_arguments => true,
:safe_methods => Set.new,
:min_confidence => 2,
:combine_locations => true,
......@@ -130,7 +121,7 @@ module Brakeman
:relative_path => false,
:quiet => true,
:report_progress => true,
:html_style => "#{File.expand_path(File.dirname(__FILE__))}/brakeman/format/style.css"
:html_style => "#{File.expand_path(File.dirname(__FILE__))}/brakeman/format/style.css"
}
end
......
module Brakeman
class AppTree
VIEW_EXTENSIONS = %w[html.erb html.haml rhtml js.erb].join(",")
attr_reader :root
def self.from_options(options)
root = options[:app_path]
# Convert files into Regexp for matching
if options[:skip_files]
list = "(?:" << options[:skip_files].map { |f| Regexp.escape f }.join("|") << ")$"
new(root, Regexp.new(list))
else
new(root)
end
end
def initialize(root, skip_files = nil)
@root = root
@skip_files = skip_files
end
def expand_path(path)
File.expand_path(path, @root)
end
def read(path)
File.read(File.join(@root, path))
end
# This variation requires full paths instead of paths based
# off the project root. I'd prefer to get all the code outside
# of AppTree using project-root based paths (e.g. app/models/user.rb)
# instead of full paths, but I suspect it's an incompatible change.
def read_path(path)
File.read(path)
end
def exists?(path)
File.exists?(File.join(@root, path))
end
# This is a pair for #read_path. Again, would like to kill these
def path_exists?(path)
File.exists?(path)
end
def initializer_paths
@initializer_paths ||= find_paths("config/initializers")
end
def controller_paths
@controller_paths ||= find_paths("app/controllers")
end
def model_paths
@model_paths ||= find_paths("app/models")
end
def template_paths
@template_paths ||= find_paths("app/views", "*.{#{VIEW_EXTENSIONS}}")
end
def layout_exists?(name)
pattern = "#{@root}/app/views/layouts/#{name}.html.{erb,haml}"
!Dir.glob(pattern).empty?
end
def lib_paths
@lib_files ||= find_paths("lib")
end
private
def find_paths(directory, extensions = "*.rb")
pattern = @root + "/#{directory}/**/#{extensions}"
Dir.glob(pattern).sort.tap do |paths|
reject_skipped_files(paths)
end
end
def reject_skipped_files(paths)
return unless @skip_files
paths.reject! { |f| @skip_files.match f }
end
end
end
......@@ -75,28 +75,28 @@ class Brakeman::Checks
#Run all the checks on the given Tracker.
#Returns a new instance of Checks with the results.
def self.run_checks tracker
def self.run_checks(app_tree, tracker)
if tracker.options[:parallel_checks]
self.run_checks_parallel tracker
self.run_checks_parallel(app_tree, tracker)
else
self.run_checks_sequential tracker
self.run_checks_sequential(app_tree, tracker)
end
end
#Run checks sequentially
def self.run_checks_sequential tracker
def self.run_checks_sequential(app_tree, tracker)
check_runner = self.new :min_confidence => tracker.options[:min_confidence]
@checks.each do |c|
check_name = get_check_name c
#Run or don't run check based on options
unless tracker.options[:skip_checks].include? check_name or
unless tracker.options[:skip_checks].include? check_name or
(tracker.options[:run_checks] and not tracker.options[:run_checks].include? check_name)
Brakeman.notify " - #{check_name}"
check = c.new(tracker)
check = c.new(app_tree, tracker)
begin
check.run_check
......@@ -118,23 +118,23 @@ class Brakeman::Checks
end
#Run checks in parallel threads
def self.run_checks_parallel tracker
def self.run_checks_parallel(app_tree, tracker)
threads = []
error_mutex = Mutex.new
check_runner = self.new :min_confidence => tracker.options[:min_confidence]
@checks.each do |c|
check_name = get_check_name c
#Run or don't run check based on options
unless tracker.options[:skip_checks].include? check_name or
unless tracker.options[:skip_checks].include? check_name or
(tracker.options[:run_checks] and not tracker.options[:run_checks].include? check_name)
Brakeman.notify " - #{check_name}"
threads << Thread.new do
check = c.new(tracker)
check = c.new(app_tree, tracker)
begin
check.run_check
......@@ -175,6 +175,6 @@ class Brakeman::Checks
end
#Load all files in checks/ directory
Dir.glob("#{File.expand_path(File.dirname(__FILE__))}/checks/*.rb").sort.each do |f|
Dir.glob("#{File.expand_path(File.dirname(__FILE__))}/checks/*.rb").sort.each do |f|
require f.match(/(brakeman\/checks\/.*)\.rb$/)[0]
end
......@@ -14,8 +14,9 @@ class Brakeman::BaseCheck < Brakeman::SexpProcessor
Match = Struct.new(:type, :match)
#Initialize Check with Checks.
def initialize tracker
def initialize(app_tree, tracker)
super()
@app_tree = app_tree
@results = [] #only to check for duplicates
@warnings = []
@tracker = tracker
......@@ -105,13 +106,13 @@ class Brakeman::BaseCheck < Brakeman::SexpProcessor
private
#Report a warning
#Report a warning
def warn options
warning = Brakeman::Warning.new(options.merge({ :check => self.class.to_s }))
warning.file = file_for warning
@warnings << warning
end
@warnings << warning
end
#Run _exp_ through OutputProcessor to get a nice String.
def format_output exp
......@@ -149,12 +150,12 @@ class Brakeman::BaseCheck < Brakeman::SexpProcessor
#Checks if mass assignment is disabled globally in an initializer.
def mass_assign_disabled?
return @mass_assign_disabled unless @mass_assign_disabled.nil?
@mass_assign_disabled = false
if version_between?("3.1.0", "4.0.0") and
if version_between?("3.1.0", "4.0.0") and
tracker.config[:rails] and
tracker.config[:rails][:active_record] and
tracker.config[:rails][:active_record] and
tracker.config[:rails][:active_record][:whitelist_attributes] == Sexp.new(:true)
@mass_assign_disabled = true
......@@ -364,7 +365,7 @@ class Brakeman::BaseCheck < Brakeman::SexpProcessor
#Checks if +exp+ is a model name.
#
#Prior to using this method, either @tracker must be set to
#Prior to using this method, either @tracker must be set to
#the current tracker, or else @models should contain an array of the model
#names, which is available via tracker.models.keys
def model_name? exp
......@@ -387,14 +388,14 @@ class Brakeman::BaseCheck < Brakeman::SexpProcessor
#Finds entire method call chain where +target+ is a target in the chain
def find_chain exp, target
return unless sexp? exp
return unless sexp? exp
case exp.node_type
when :output, :format
find_chain exp.value, target
when :call
if exp == target or include_target? exp, target
return exp
return exp
end
else
exp.each do |e|
......@@ -448,7 +449,7 @@ class Brakeman::BaseCheck < Brakeman::SexpProcessor
end
def gemfile_or_environment
if File.exist? File.expand_path "#{tracker.options[:app_path]}/Gemfile"
if @app_tree.exists?("Gemfile")
"Gemfile"
else
"config/environment.rb"
......
......@@ -12,8 +12,9 @@ module Brakeman
class Processor
include Util
def initialize options
@tracker = Tracker.new self, options
def initialize(app_tree, options)
@app_tree = app_tree
@tracker = Tracker.new(@app_tree, self, options)
end
def tracked_events
......@@ -38,7 +39,7 @@ module Brakeman
#Process controller source. +file_name+ is used for reporting
def process_controller src, file_name
if contains_class? src
ControllerProcessor.new(@tracker).process_controller src, file_name
ControllerProcessor.new(@app_tree, @tracker).process_controller src, file_name
else
LibraryProcessor.new(@tracker).process_library src, file_name
end
......@@ -47,7 +48,7 @@ module Brakeman
#Process variable aliasing in controller source and save it in the
#tracker.
def process_controller_alias name, src, only_method = nil
ControllerAliasProcessor.new(@tracker, only_method).process_controller name, src
ControllerAliasProcessor.new(@app_tree, @tracker, only_method).process_controller name, src
end
#Process a model source
......
......@@ -9,8 +9,9 @@ class Brakeman::ControllerAliasProcessor < Brakeman::AliasProcessor
#If only_method is specified, only that method will be processed,
#other methods will be skipped.
#This is for rescanning just a single action.
def initialize tracker, only_method = nil
def initialize app_tree, tracker, only_method = nil
super()
@app_tree = app_tree
@only_method = only_method
@tracker = tracker
@rendered = false
......@@ -46,7 +47,7 @@ class Brakeman::ControllerAliasProcessor < Brakeman::AliasProcessor
methods.each do |name|
#Need to process the method like it was in a controller in order
#to get the renders set
processor = Brakeman::ControllerProcessor.new(@tracker)
processor = Brakeman::ControllerProcessor.new(@app_tree, @tracker)
method = mixin[:public][name]
if node_type? method, :methdef
......@@ -132,7 +133,7 @@ class Brakeman::ControllerAliasProcessor < Brakeman::AliasProcessor
#Processes a call to a before filter.
#Basically, adds any instance variable assignments to the environment.
#TODO: method arguments?
def process_before_filter name
def process_before_filter name
filter = find_method name, @current_class
if filter.nil?
......@@ -236,9 +237,9 @@ class Brakeman::ControllerAliasProcessor < Brakeman::AliasProcessor
end
controller[:before_filter_cache].each do |f|
if f[:all] or
if f[:all] or
(f[:only] == method) or
(f[:only].is_a? Array and f[:only].include? method) or
(f[:only].is_a? Array and f[:only].include? method) or
(f[:except].is_a? Symbol and f[:except] != method) or
(f[:except].is_a? Array and not f[:except].include? method)
......
......@@ -4,8 +4,9 @@ require 'brakeman/processors/base_processor'
class Brakeman::ControllerProcessor < Brakeman::BaseProcessor
FORMAT_HTML = Sexp.new(:call, Sexp.new(:lvar, :format), :html, Sexp.new(:arglist))
def initialize tracker
super
def initialize app_tree, tracker
super(tracker)
@app_tree = app_tree
@controller = nil
@current_method = nil
@current_module = nil
......@@ -89,7 +90,7 @@ class Brakeman::ControllerProcessor < Brakeman::BaseProcessor
#layout "some_layout"
name = args.last.value.to_s
unless Dir.glob("#{@tracker.options[:app_path]}/app/views/layouts/#{name}.html.{erb,haml}").empty?
if @app_tree.layout_exists?(name)
@controller[:layout] = "layouts/#{name}"
else
Brakeman.debug "[Notice] Layout not found: #{name}"
......@@ -107,7 +108,7 @@ class Brakeman::ControllerProcessor < Brakeman::BaseProcessor
exp
elsif target == nil and method == :render
make_render exp
elsif exp == FORMAT_HTML and context[1] != :iter
elsif exp == FORMAT_HTML and context[1] != :iter
#This is an empty call to
# format.html
#Which renders the default template if no arguments
......@@ -175,7 +176,7 @@ class Brakeman::ControllerProcessor < Brakeman::BaseProcessor
name = underscore(@controller[:name].to_s.split("::")[-1].gsub("Controller", ''))
#There is a layout for this Controller
unless Dir.glob("#{@tracker.options[:app_path]}/app/views/layouts/#{name}.html.{erb,haml}").empty?
if @app_tree.layout_exists?(name)
@controller[:layout] = "layouts/#{name}"
end
end
......@@ -203,9 +204,9 @@ class Brakeman::ControllerProcessor < Brakeman::BaseProcessor
end
#Build Sexp for filter method
body = Sexp.new(:scope,
body = Sexp.new(:scope,
Sexp.new(:block,
Sexp.new(:lasgn, block_variable,
Sexp.new(:lasgn, block_variable,
Sexp.new(:call, Sexp.new(:const, @controller[:name]), :new, Sexp.new(:arglist)))).concat(block_inner))
filter_method = Sexp.new(:defn, filter_name, Sexp.new(:args), body).line(exp.line)
......
......@@ -40,7 +40,8 @@ class Brakeman::Report
"<span class='med-confidence'>Medium</span>",
"<span class='weak-confidence'>Weak</span>" ]
def initialize tracker
def initialize(app_tree, tracker)
@app_tree = app_tree
@tracker = tracker
@checks = tracker.checks
@element_id = 0 #Used for HTML ids
......@@ -158,7 +159,7 @@ class Brakeman::Report
end
return nil if warnings.empty?
stabilizer = 0
warnings = warnings.sort_by{|row| stabilizer += 1; [row["Confidence"], row["Warning Type"], row["Template"], stabilizer]}
if html
......@@ -232,7 +233,7 @@ class Brakeman::Report
end
return nil if warnings.empty?
stabilizer = 0
warnings = warnings.sort_by{|row| stabilizer +=1; [row["Confidence"], row["Warning Type"], row["Controller"], stabilizer]}
......@@ -318,7 +319,7 @@ class Brakeman::Report
else
output = ''
template_rows.each do |template|
output << template.first.to_s << "\n\n"
output << template.first.to_s << "\n\n"
table = Terminal::Table.new(:headings => ['Output']) do |t|
# template[1] is an array of calls
template[1].each do |v|
......@@ -392,7 +393,7 @@ class Brakeman::Report
res = generate_controller_warnings
out << "\n\n\nController Warnings:\n\n" << truncate_table(res.to_s) if res
res = generate_model_warnings
res = generate_model_warnings
out << "\n\n\nModel Warnings:\n\n" << truncate_table(res.to_s) if res
res = generate_template_warnings
......@@ -404,8 +405,8 @@ class Brakeman::Report
#Generate CSV output
def to_csv
output = csv_header
output << "\nSUMMARY\n"
output = csv_header
output << "\nSUMMARY\n"
output << table_to_csv(generate_overview) << "\n"
......@@ -437,7 +438,7 @@ class Brakeman::Report
output << table_to_csv(res) << "\n" if res
output << "Model Warnings\n"
res = generate_model_warnings
res = generate_model_warnings
output << table_to_csv(res) << "\n" if res
res = generate_template_warnings
......@@ -542,11 +543,11 @@ HEADER
#Generate HTML for warnings, including context show/hidden via Javascript
def with_context warning, message
context = context_for warning
context = context_for(@app_tree, warning)
full_message = nil
if tracker.options[:message_limit] and
tracker.options[:message_limit] > 0 and
tracker.options[:message_limit] > 0 and
message.length > tracker.options[:message_limit]
full_message = html_message(warning, message)
......@@ -657,12 +658,12 @@ HEADER
else
w.code = ""
end
w.context = context_for(w).join("\n")
w.context = context_for(@app_tree, w).join("\n")
end
end
report[:config] = tracker.config
report
end
......
......@@ -12,7 +12,7 @@ class Brakeman::Rescanner < Brakeman::Scanner
def initialize options, processor, changed_files
super(options, processor)
@paths = changed_files.map {|f| File.expand_path f, tracker.options[:app_path] }
@paths = changed_files.map {|f| @app_tree.expand_path(f) }
@old_results = tracker.checks #Old warnings from previous scan
@changes = nil #True if files had to be rescanned
@reindex = Set.new
......@@ -66,7 +66,7 @@ class Brakeman::Rescanner < Brakeman::Scanner
def rescan_file path, type = nil
type ||= file_type path
unless File.exist? path
unless @app_tree.path_exists?(path)
return rescan_deleted_file path, type
end
......@@ -128,7 +128,7 @@ class Brakeman::Rescanner < Brakeman::Scanner
end
def rescan_template path
return unless path.match KNOWN_TEMPLATE_EXTENSIONS and File.exist? path
return unless path.match KNOWN_TEMPLATE_EXTENSIONS and @app_tree.path_exists?(path)
template_name = template_path_to_name(path)
......@@ -177,7 +177,7 @@ class Brakeman::Rescanner < Brakeman::Scanner
def rescan_model path
num_models = tracker.models.length
tracker.reset_model path
process_model path if File.exists? path
process_model path if @app_tree.path_exists?(path)
#Only need to rescan other things if a model is added or removed
if num_models != tracker.models.length
......@@ -190,7 +190,7 @@ class Brakeman::Rescanner < Brakeman::Scanner
end
def rescan_lib path
process_lib path if File.exists? path
process_lib path if @app_tree.path_exists?(path)
lib = nil
......
......@@ -15,6 +15,7 @@ begin
require 'erb'
require 'erubis'
require 'brakeman/processor'
require 'brakeman/app_tree'
require 'brakeman/parsers/rails2_erubis'
require 'brakeman/parsers/rails2_xss_plugin_erubis'
require 'brakeman/parsers/rails3_erubis'
......@@ -34,18 +35,19 @@ class Brakeman::Scanner
#Pass in path to the root of the Rails application
def initialize options, processor = nil
@options = options
@report_progress = options[:report_progress]
@path = options[:app_path]
@app_path = File.join(@path, "app")
@processor = processor || Brakeman::Processor.new(options)
@skip_files = nil
#Convert files into Regexp for matching
if options[:skip_files]
list = "(?:" << options[:skip_files].map { |f| Regexp.escape f }.join("|") << ")$"
@skip_files = Regexp.new(list)
@app_tree = Brakeman::AppTree.from_options(options)
if !@app_tree.root || !@app_tree.exists?("app")
abort("Please supply the path to a Rails application.")
end
if @app_tree.exists?("script/rails")
options[:rails3] = true
Brakeman.notify "[Notice] Detected Rails 3 application"
end
@processor = processor || Brakeman::Processor.new(@app_tree, options)
if RUBY_1_9
@ruby_parser = ::Ruby19Parser
else
......@@ -93,7 +95,7 @@ class Brakeman::Scanner
process_config_file "gems.rb"
end
if File.exists? "#@path/vendor/plugins/rails_xss" or
if @app_tree.exists?("vendor/plugins/rails_xss") or
options[:rails3] or options[:escape_html]
tracker.config[:escape_html] = true
......@@ -102,8 +104,10 @@ class Brakeman::Scanner
end
def process_config_file file
if File.exists? "#@path/config/#{file}"
@processor.process_config(parse_ruby(File.read("#@path/config/#{file}")))
path = "config/#{file}"
if @app_tree.exists?(path)
@processor.process_config(parse_ruby(@app_tree.read(path)))
end
rescue Exception => e
......@@ -115,11 +119,11 @@ class Brakeman::Scanner
#Process Gemfile
def process_gems
if File.exists? "#@path/Gemfile"
if File.exists? "#@path/Gemfile.lock"
@processor.process_gems(parse_ruby(File.read("#@path/Gemfile")), File.read("#@path/Gemfile.lock"))
if @app_tree.exists? "Gemfile"
if @app_tree.exists? "Gemfile.lock"
@processor.process_gems(parse_ruby(@app_tree.read("Gemfile")), @app_tree.read("Gemfile.lock"))
else
@processor.process_gems(parse_ruby(File.read("#@path/Gemfile")))
@processor.process_gems(parse_ruby(@app_tree.read("Gemfile")))
end
end
rescue Exception => e
......@@ -131,10 +135,7 @@ class Brakeman::Scanner
#
#Adds parsed information to tracker.initializers
def process_initializers
initializer_files = Dir.glob(@path + "/config/initializers/**/*.rb").sort
initializer_files.reject! { |f| @skip_files.match f } if @skip_files
initializer_files.each do |f|
@app_tree.initializer_paths.each do |f|
process_initializer f
end
end
......@@ -142,7 +143,7 @@ class Brakeman::Scanner
#Process an initializer
def process_initializer path
begin
@processor.process_initializer(path, parse_ruby(File.read(path)))
@processor.process_initializer(path, parse_ruby(@app_tree.read_path(path)))
rescue Racc::ParseError => e
tracker.error e, "could not parse #{path}. There is probably a typo in the file. Test it with 'ruby_parse #{path}'"
rescue Exception => e
......@@ -159,19 +160,13 @@ class Brakeman::Scanner
return
end
lib_files = Dir.glob(@path + "/lib/**/*.rb").sort
lib_files.reject! { |f| @skip_files.match f } if @skip_files
total = lib_files.length
total = @app_tree.lib_paths.length
current = 0
lib_files.each do |f|
@app_tree.lib_paths.each do |f|
Brakeman.debug "Processing #{f}"
if @report_progress
$stderr.print " #{current}/#{total} files processed\r"
current += 1
end
report_progress(current, total)
current += 1
process_lib f
end
end
......@@ -179,7 +174,7 @@ class Brakeman::Scanner
#Process a library
def process_lib path
begin
@processor.process_lib parse_ruby(File.read(path)), path
@processor.process_lib parse_ruby(@app_tree.read_path(path)), path
rescue Racc::ParseError => e
tracker.error e, "could not parse #{path}. There is probably a typo in the file. Test it with 'ruby_parse #{path}'"
rescue Exception => e
......@@ -191,9 +186,9 @@ class Brakeman::Scanner
#
#Adds parsed information to tracker.routes
def process_routes
if File.exists? "#@path/config/routes.rb"
if @app_tree.exists?("config/routes.rb")
begin
@processor.process_routes parse_ruby(File.read("#@path/config/routes.rb"))
@processor.process_routes parse_ruby(@app_tree.read("config/routes.rb"))
rescue Exception => e
tracker.error e.exception(e.message + "\nWhile processing routes.rb"), e.backtrace
Brakeman.notify "[Notice] Error while processing routes - assuming all public controller methods are actions."
......@@ -208,19 +203,13 @@ class Brakeman::Scanner
#
#Adds processed controllers to tracker.controllers
def process_controllers
controller_files = Dir.glob(@app_path + "/controllers/**/*.rb").sort
controller_files.reject! { |f| @skip_files.match f } if @skip_files
total = controller_files.length
total = @app_tree.controller_paths.length
current = 0
controller_files.each do |f|
@app_tree.controller_paths.each do |f|
Brakeman.debug "Processing #{f}"
if @report_progress
$stderr.print " #{current}/#{total} files processed\r"
current += 1
end
report_progress(current, total)
current += 1
process_controller f
end
......@@ -231,11 +220,8 @@ class Brakeman::Scanner
tracker.controllers.sort_by{|name| name.to_s}.each do |name, controller|
Brakeman.debug "Processing #{name}"
if @report_progress
$stderr.print " #{current}/#{total} controllers processed\r"
current += 1
end
report_progress(current, total, "controllers")
current += 1
@processor.process_controller_alias name, controller[:src]
end
......@@ -245,7 +231,7 @@ class Brakeman::Scanner
def process_controller path
begin
@processor.process_controller(parse_ruby(File.read(path)), path)
@processor.process_controller(parse_ruby(@app_tree.read_path(path)), path)
rescue Racc::ParseError => e
tracker.error e, "could not parse #{path}. There is probably a typo in the file. Test it with 'ruby_parse #{path}'"
rescue Exception => e
......@@ -257,23 +243,15 @@ class Brakeman::Scanner
#
#Adds processed views to tracker.views
def process_templates
views_path = @app_path + "/views/**/*.{html.erb,html.haml,rhtml,js.erb}"
$stdout.sync = true
count = 0
template_files = Dir.glob(views_path).sort
template_files.reject! { |f| @skip_files.match f } if @skip_files
total = template_files.length
count = 0
total = @app_tree.template_paths.length
template_files.each do |path|
@app_tree.template_paths.each do |path|
Brakeman.debug "Processing #{path}"
if @report_progress
$stderr.print " #{count}/#{total} files processed\r"
count += 1
end
report_progress(count, total)
count += 1
process_template path
end
......@@ -284,11 +262,8 @@ class Brakeman::Scanner
tracker.templates.keys.dup.sort_by{|name| name.to_s}.each do |name|
Brakeman.debug "Processing #{name}"
if @report_progress
count += 1
$stderr.print " #{count}/#{total} templates processed\r"
end
report_progress(count, total, "templates")
count += 1
@processor.process_template_alias tracker.templates[name]
end
end
......@@ -297,7 +272,7 @@ class Brakeman::Scanner
type = path.match(KNOWN_TEMPLATE_EXTENSIONS)[1].to_sym
type = :erb if type == :rhtml
name = template_path_to_name path
text = File.read path
text = @app_tree.read_path path
begin
if type == :erb
......@@ -349,27 +324,20 @@ class Brakeman::Scanner
#
#Adds the processed models to tracker.models
def process_models
model_files = Dir.glob(@app_path + "/models/**/*.rb").sort
model_files.reject! { |f| @skip_files.match f } if @skip_files
total = model_files.length
total = @app_tree.model_paths.length
current = 0
model_files.each do |f|
@app_tree.model_paths.each do |f|
Brakeman.debug "Processing #{f}"
if @report_progress
$stderr.print " #{current}/#{total} files processed\r"
current += 1
end
report_progress(current, total)
current += 1
process_model f
end
end
def process_model path
begin
@processor.process_model(parse_ruby(File.read(path)), path)
@processor.process_model(parse_ruby(@app_tree.read_path(path)), path)
rescue Racc::ParseError => e
tracker.error e, "could not parse #{path}"
rescue Exception => e
......@@ -377,6 +345,11 @@ class Brakeman::Scanner
end
end
def report_progress(current, total, type = "files")
return unless @options[:report_progress]
$stderr.print " #{current}/#{total} #{type} processed\r"
end
def index_call_sites
tracker.index_call_sites
end
......
......@@ -20,9 +20,11 @@ class Brakeman::Tracker
#
#The Processor argument is only used by other Processors
#that might need to access it.
def initialize processor = nil, options = {}
def initialize(app_tree, processor = nil, options = {})
@app_tree = app_tree
@processor = processor
@options = options
@config = {}
@templates = {}
@controllers = {}
......@@ -67,7 +69,7 @@ class Brakeman::Tracker
#Run a set of checks on the current information. Results will be stored
#in Tracker#checks.
def run_checks
@checks = Brakeman::Checks.run_checks(self)
@checks = Brakeman::Checks.run_checks(@app_tree, self)
@end_time = Time.now
@duration = @end_time - @start_time
......@@ -147,7 +149,7 @@ class Brakeman::Tracker
#Returns a Report with this Tracker's information
def report
Brakeman::Report.new(self)
Brakeman::Report.new(@app_tree, self)
end
def index_call_sites
......
......@@ -75,7 +75,7 @@ module Brakeman::Util
end
index += 2
end
hash << key << value
hash
......@@ -107,8 +107,8 @@ module Brakeman::Util
#Check if _exp_ represents a hash: s(:hash, {...})
#This also includes pseudo hashes params, session, and cookies.
def hash? exp
exp.is_a? Sexp and (exp.node_type == :hash or
exp.node_type == :params or
exp.is_a? Sexp and (exp.node_type == :hash or
exp.node_type == :params or
exp.node_type == :session or
exp.node_type == :cookies)
end
......@@ -315,10 +315,10 @@ module Brakeman::Util
#Return array of lines surrounding the warning location from the original
#file.
def context_for warning, tracker = nil
def context_for app_tree, warning, tracker = nil
file = file_for warning, tracker
context = []
return context unless warning.line and file and File.exist? file
return context unless warning.line and file and @app_tree.path_exists? file
current_line = 0
start_line = warning.line - 5
......@@ -369,5 +369,5 @@ module Brakeman::Util
output << CSV.generate_line(row.cells.map{|cell| cell.to_s.strip})
end
output
end
end
end
......@@ -22,10 +22,12 @@ end
class BaseCheckTests < Test::Unit::TestCase
FakeTracker = Struct.new(:config)
FakeAppTree = Struct.new(:root)
def setup
@tracker = FakeTracker.new
@check = Brakeman::BaseCheck.new @tracker
app_tree = FakeAppTree.new
@check = Brakeman::BaseCheck.new app_tree, @tracker
end
def version_between? version, high, low
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册