class Brakeman::Tracker

The Tracker keeps track of all the processed information.

Constants

UNKNOWN_MODEL

Place holder when there should be a model, but it is not clear what model it will be.

Attributes

app_tree[RW]
checks[RW]
config[RW]
constants[RW]
controllers[RW]
duration[RW]
end_time[RW]
errors[RW]
filter_cache[RW]
ignored_filter[RW]
initializers[RW]
libs[RW]
models[RW]
options[RW]
processor[RW]
routes[RW]
start_time[RW]
template_cache[RW]
templates[RW]

Public Class Methods

new(app_tree, processor = nil, options = {}) click to toggle source

Creates a new Tracker.

The Processor argument is only used by other Processors that might need to access it.

# File lib/brakeman/tracker.rb, line 25
def initialize(app_tree, processor = nil, options = {})
  @app_tree = app_tree
  @processor = processor
  @options = options

  @config = Brakeman::Config.new(self)
  @templates = {}
  @controllers = {}
  #Initialize models with the unknown model so
  #we can match models later without knowing precisely what
  #class they are.
  @models = {}
  @models[UNKNOWN_MODEL] = Brakeman::Model.new(UNKNOWN_MODEL, nil, @app_tree.file_path("NOT_REAL.rb"), nil, self)
  @method_cache = {}
  @routes = {}
  @initializers = {}
  @errors = []
  @libs = {}
  @constants = Brakeman::Constants.new
  @checks = nil
  @processed = nil
  @template_cache = Set.new
  @filter_cache = {}
  @call_index = nil
  @start_time = Time.now
  @end_time = nil
  @duration = nil
end

Public Instance Methods

add_constant(name, value, context = nil) click to toggle source
# File lib/brakeman/tracker.rb, line 204
def add_constant name, value, context = nil
  @constants.add name, value, context unless @options[:disable_constant_tracking]
end
add_errors(exceptions) click to toggle source
# File lib/brakeman/tracker.rb, line 72
def add_errors exceptions
  exceptions.each do |e|
    error(e)
  end
end
app_path() click to toggle source
# File lib/brakeman/tracker.rb, line 88
def app_path
  @app_path ||= File.expand_path @options[:app_path]
end
check_initializers(target, method) click to toggle source

Searches the initializers for a method call

# File lib/brakeman/tracker.rb, line 170
def check_initializers target, method
  finder = Brakeman::FindCall.new target, method, self

  initializers.sort.each do |name, initializer|
    finder.process_source initializer
  end

  finder.matches
end
constant_lookup(name) click to toggle source

This method does not return all constants at this time, just ones with “simple” values.

# File lib/brakeman/tracker.rb, line 210
def constant_lookup name
  @constants.get_simple_value name unless @options[:disable_constant_tracking]
end
each_class() { |src, set_name, file| ... } click to toggle source
# File lib/brakeman/tracker.rb, line 127
def each_class
  classes = [self.controllers, self.models]

  if @options[:index_libs]
    classes << self.libs
  end

  classes.each do |set|
    set.each do |set_name, collection|
      collection.src.each do |file, src|
        yield src, set_name, file
      end
    end
  end
end
each_method() { |src, set_name, method_name, file| ... } click to toggle source

Iterate over all methods in controllers and models.

# File lib/brakeman/tracker.rb, line 93
def each_method
  classes = [self.controllers, self.models]

  if @options[:index_libs]
    classes << self.libs
  end

  classes.each do |set|
    set.each do |set_name, collection|
      collection.each_method do |method_name, definition|
        src = definition.src
        yield src, set_name, method_name, definition.file
      end
    end
  end
end
each_template() { |k, templates| ... } click to toggle source

Iterates over each template, yielding the name and the template. Prioritizes templates which have been rendered.

# File lib/brakeman/tracker.rb, line 112
def each_template
  if @processed.nil?
    @processed, @rest = templates.keys.sort_by{|template| template.to_s}.partition { |k| k.to_s.include? "." }
  end

  @processed.each do |k|
    yield k, templates[k]
  end

  @rest.each do |k|
    yield k, templates[k]
  end
end
error(exception, backtrace = nil) click to toggle source

Add an error to the list. If no backtrace is given, the one from the exception will be used.

# File lib/brakeman/tracker.rb, line 56
def error exception, backtrace = nil
  backtrace ||= exception.backtrace
  unless backtrace.is_a? Array
    backtrace = [ backtrace ]
  end

  Brakeman.debug exception
  Brakeman.debug backtrace

  @errors << {
    :exception => exception,
    :error => exception.to_s.gsub("\n", " "),
    :backtrace => backtrace
  }
end
filtered_warnings() click to toggle source
# File lib/brakeman/tracker.rb, line 189
def filtered_warnings
  if self.ignored_filter
    self.warnings.reject do |w|
      self.ignored_filter.ignored? w
    end
  else
    self.warnings
  end
end
find_call(options) click to toggle source

Find a method call.

Options:

* :target => target name(s)
* :method => method name(s)
* :chained => search in method chains

If :target => false or :target => nil, searches for methods without a target. Targets and methods can be specified as a symbol, an array of symbols, or a regular expression.

If :chained => true, matches target at head of method chain and method at end.

For example:

find_call :target => User, :method => :all, :chained => true

could match

User.human.active.all(...)
# File lib/brakeman/tracker.rb, line 164
def find_call options
  index_call_sites unless @call_index
  @call_index.find_calls options
end
find_class(name) click to toggle source
# File lib/brakeman/tracker.rb, line 214
def find_class name
  [@controllers, @models, @libs].each do |collection|
    if c = collection[name]
      return c
    end
  end

  nil
end
find_method(method_name, class_name, method_type = :instance) click to toggle source
# File lib/brakeman/tracker.rb, line 224
def find_method method_name, class_name, method_type = :instance
  return nil unless method_name.is_a? Symbol

  klass = find_class(class_name)
  return nil unless klass

  cache_key = [klass, method_name, method_type]

  if method = @method_cache[cache_key]
    return method
  end

  if method = klass.get_method(method_name, method_type)
    return method
  else
    # Check modules included for method definition
    # TODO: only for instance methods, otherwise check extends!
    klass.includes.each do |included_name|
      if method = find_method(method_name, included_name, method_type)
        return (@method_cache[cache_key] = method)
      end
    end

    # Not in any included modules, check the parent
    @method_cache[cache_key] = find_method(method_name, klass.parent, method_type)
  end
end
index_call_sites() click to toggle source
# File lib/brakeman/tracker.rb, line 252
def index_call_sites
  finder = Brakeman::FindAllCalls.new self

  self.each_method do |definition, set_name, method_name, file|
    finder.process_source definition, :class => set_name, :method => method_name, :file => file
  end

  self.each_class do |definition, set_name, file|
    finder.process_source definition, :class => set_name, :file => file
  end

  self.each_template do |_name, template|
    finder.process_source template.src, :template => template, :file => template.file
  end

  self.initializers.each do |file_name, src|
    finder.process_all_source src, :file => file_name
  end

  @call_index = Brakeman::CallIndex.new finder.calls
end
reindex_call_sites(locations) click to toggle source

Reindex call sites

Takes a set of symbols which can include :templates, :models, or :controllers

This will limit reindexing to the given sets

# File lib/brakeman/tracker.rb, line 280
def reindex_call_sites locations
  #If reindexing templates, models, controllers,
  #just redo everything.
  if locations.length == 3
    return index_call_sites
  end

  if locations.include? :templates
    @call_index.remove_template_indexes
  end

  classes_to_reindex = Set.new
  method_sets = []

  if locations.include? :models
    classes_to_reindex.merge self.models.keys
    method_sets << self.models
  end

  if locations.include? :controllers
    classes_to_reindex.merge self.controllers.keys
    method_sets << self.controllers
  end

  if locations.include? :initializers
    self.initializers.each do |file_name, src|
      @call_index.remove_indexes_by_file file_name
    end
  end

  @call_index.remove_indexes_by_class classes_to_reindex

  finder = Brakeman::FindAllCalls.new self

  method_sets.each do |set|
    set.each do |set_name, info|
      info.each_method do |method_name, definition|
        src = definition.src
        finder.process_source src, :class => set_name, :method => method_name, :file => definition.file
      end
    end
  end

  if locations.include? :templates
    self.each_template do |_name, template|
      finder.process_source template.src, :template => template, :file => template.file
    end
  end

  if locations.include? :initializers
    self.initializers.each do |file_name, src|
      finder.process_all_source src, :file => file_name
    end
  end

  @call_index.index_calls finder.calls
end
report() click to toggle source

Returns a Report with this Tracker’s information

# File lib/brakeman/tracker.rb, line 181
def report
  Brakeman::Report.new(self)
end
reset_controller(path) click to toggle source
# File lib/brakeman/tracker.rb, line 391
def reset_controller path
  controller_name = nil

  #Remove from controller
  @controllers.each do |name, controller|
    if controller.files.include?(path)
      controller_name = name

      #Remove templates rendered from this controller
      @templates.each do |template_name, template|
        if template.render_path and template.render_path.include_controller? name
          reset_template template_name
          @call_index.remove_template_indexes template_name
        end
      end

      #Remove calls indexed from this controller
      @call_index.remove_indexes_by_class [name]
      break
    end
  end
  @controllers.delete controller_name
end
reset_initializer(path) click to toggle source
# File lib/brakeman/tracker.rb, line 420
def reset_initializer path
  @initializers.delete_if do |file, src|
    path.relative.include? file
  end

  @call_index.remove_indexes_by_file path
end
reset_lib(path) click to toggle source

Clear information related to model

# File lib/brakeman/tracker.rb, line 378
def reset_lib path
  lib_name = nil

  @libs.each do |name, lib|
    if lib.files.include?(path)
      lib_name = name
      break
    end
  end

  @libs.delete lib_name
end
reset_model(path) click to toggle source

Clear information related to model

# File lib/brakeman/tracker.rb, line 364
def reset_model path
  model_name = nil

  @models.each do |name, model|
    if model.files.include?(path)
      model_name = name
      break
    end
  end

  @models.delete(model_name)
end
reset_routes() click to toggle source

Clear information about routes

# File lib/brakeman/tracker.rb, line 416
def reset_routes
  @routes = {}
end
reset_template(name) click to toggle source

Clear information related to template

# File lib/brakeman/tracker.rb, line 355
def reset_template name
  name = name.to_sym
  @templates.delete name
  @processed = nil
  @rest = nil
  @template_cache.clear
end
reset_templates(options = { :only_rendered => false }) click to toggle source

Clear information related to templates. If :only_rendered => true, will delete templates rendered from controllers (but not those rendered from other templates)

# File lib/brakeman/tracker.rb, line 341
def reset_templates options = { :only_rendered => false }
  if options[:only_rendered]
    @templates.delete_if do |_name, template|
      template.rendered_from_controller?
    end
  else
    @templates = {}
  end
  @processed = nil
  @rest = nil
  @template_cache.clear
end
run_checks() click to toggle source

Run a set of checks on the current information. Results will be stored in Tracker#checks.

# File lib/brakeman/tracker.rb, line 80
def run_checks
  @checks = Brakeman::Checks.run_checks(self)

  @end_time = Time.now
  @duration = @end_time - @start_time
  @checks
end
unused_fingerprints() click to toggle source
# File lib/brakeman/tracker.rb, line 199
def unused_fingerprints
  return [] unless self.ignored_filter
  self.ignored_filter.obsolete_fingerprints
end
warnings() click to toggle source
# File lib/brakeman/tracker.rb, line 185
def warnings
  self.checks.all_warnings
end