Class: Brakeman::ControllerAliasProcessor

Inherits:
AliasProcessor show all
Includes:
RenderHelper
Defined in:
lib/brakeman/processors/controller_alias_processor.rb

Overview

Processes aliasing in controllers, but includes following renders in routes and putting variables into templates

Constant Summary

Constants inherited from AliasProcessor

AliasProcessor::ARRAY_CONST, AliasProcessor::HASH_CONST, AliasProcessor::RAILS_TEST, AliasProcessor::STRING_NEW

Constants included from CallConversionHelper

Brakeman::CallConversionHelper::STRING_LENGTH_LIMIT

Constants included from Util

Util::ALL_COOKIES, Util::ALL_PARAMETERS, Util::COOKIES, Util::COOKIES_SEXP, Util::DIR_CONST, Util::LITERALS, Util::PARAMETERS, Util::PARAMS_SEXP, Util::PATH_PARAMETERS, Util::QUERY_PARAMETERS, Util::REQUEST_COOKIES, Util::REQUEST_ENV, Util::REQUEST_PARAMETERS, Util::REQUEST_PARAMS, Util::REQUEST_REQUEST_PARAMETERS, Util::SAFE_LITERAL, Util::SESSION, Util::SESSION_SEXP

Constants inherited from SexpProcessor

SexpProcessor::VERSION

Instance Attribute Summary

Attributes inherited from AliasProcessor

#result, #tracker

Attributes inherited from SexpProcessor

#context, #env, #expected

Instance Method Summary collapse

Methods included from RenderHelper

#get_class_target, #get_options, #process_action, #process_layout, #process_partial, #process_render

Methods inherited from AliasProcessor

#array_detect_all_literals?, #array_include_all_literals?, #assign_args, #collapse_send_call, #duplicate?, #early_return?, #find_push_target, #get_call_value, #get_rhs, #join_item, #merge_if_branch, #meth_env, #new_string?, #only_ivars, #only_request_vars, #process_array_join, #process_attrasgn, #process_block, #process_bracket_call, #process_case, #process_cdecl, #process_cvdecl, #process_default, #process_defs, #process_gasgn, #process_hash, #process_hash_merge, #process_hash_merge!, #process_helper_method, #process_iasgn, #process_if, #process_if_branch, #process_lasgn, #process_masgn, #process_op_asgn1, #process_op_asgn2, #process_or_simple_operation, #process_or_target, #process_safely, #process_scope, #process_svalue, #raise?, #replace, #same_value?, #self_assign?, #self_assign_target?, #self_assign_var?, #set_value, #simple_when?, #too_deep?, #top_target, #value_from_case, #value_from_if

Methods included from CallConversionHelper

#all_literals?, #join_arrays, #join_strings, #math_op, #process_array_access, #process_hash_access

Methods included from Util

#array?, #block?, #call?, #camelize, #class_name, #constant?, #contains_class?, #cookies?, #dir_glob?, #false?, #hash?, #hash_access, #hash_insert, #hash_iterate, #integer?, #kwsplat?, #literal?, #make_call, #node_type?, #number?, #params?, #pluralize, #rails_version, #regexp?, #remove_kwsplat, #request_env?, #request_value?, #result?, #safe_literal, #safe_literal?, #safe_literal_target?, #set_env_defaults, #sexp?, #string?, #string_interp?, #symbol?, #template_path_to_name, #true?, #underscore

Methods included from ProcessorHelper

#current_file, #process_all, #process_all!, #process_call_args, #process_call_defn?, #process_module

Methods inherited from SexpProcessor

#in_context, #process, processors, #scope

Constructor Details

#initialize(tracker, only_method = nil) ⇒ ControllerAliasProcessor

If only_method is specified, only that method will be processed, other methods will be skipped. This is for rescanning just a single action.


14
15
16
17
18
19
20
21
# File 'lib/brakeman/processors/controller_alias_processor.rb', line 14

def initialize tracker, only_method = nil
  super tracker
  @app_tree = tracker.app_tree
  @only_method = only_method
  @rendered = false
  @current_class = @current_module = @current_method = nil
  @method_cache = {} #Cache method lookups
end

Instance Method Details

#before_filter_list(method, klass) ⇒ Object

Get list of filters, including those that are inherited


235
236
237
238
239
240
241
242
243
# File 'lib/brakeman/processors/controller_alias_processor.rb', line 235

def before_filter_list method, klass
  controller = @tracker.controllers[klass]

  if controller
    controller.before_filter_list self, method
  else
    []
  end
end

#find_method(method_name, klass) ⇒ Object

Finds a method in the given class or a parent class

Returns nil if the method could not be found.

If found, returns hash table with controller name and method sexp.


250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
# File 'lib/brakeman/processors/controller_alias_processor.rb', line 250

def find_method method_name, klass
  return nil if sexp? method_name
  method_name = method_name.to_sym

  if method = @method_cache[method_name]
    return method
  end

  controller = @tracker.controllers[klass]
  controller ||= @tracker.libs[klass]

  if klass and controller
    method = controller.get_method method_name

    if method.nil?
      controller.includes.each do |included|
        method = find_method method_name, included
        if method
          @method_cache[method_name] = method
          return method
        end
     end

      @method_cache[method_name] = find_method method_name, controller.parent
    else
      @method_cache[method_name] = { :controller => controller.name, :method => method[:src] }
    end
  else
    nil
  end
end

#layout_nameObject

Determines default layout name


211
212
213
214
215
216
217
218
219
220
221
222
# File 'lib/brakeman/processors/controller_alias_processor.rb', line 211

def layout_name
  controller = @tracker.controllers[@current_class]

  return controller.layout if controller.layout
  return false if controller.layout == false

  app_controller = @tracker.controllers[:ApplicationController]

  return app_controller.layout if app_controller and app_controller.layout

  nil
end

#process_before_filter(name) ⇒ Object

Processes a call to a before filter. Basically, adds any instance variable assignments to the environment. TODO: method arguments?


145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
# File 'lib/brakeman/processors/controller_alias_processor.rb', line 145

def process_before_filter name
  filter = find_method name, @current_class

  if filter.nil?
    Brakeman.debug "[Notice] Could not find filter #{name}"
    return
  end

  method = filter[:method]

  if ivars = @tracker.filter_cache[[filter[:controller], name]]
    ivars.each do |variable, value|
      env[variable] = value
    end
  else
    processor = Brakeman::AliasProcessor.new @tracker
    processor.process_safely(method.body_list, only_ivars(:include_request_vars))

    ivars = processor.only_ivars(:include_request_vars).all

    @tracker.filter_cache[[filter[:controller], name]] = ivars

    ivars.each do |variable, value|
      env[variable] = value
    end
  end
end

#process_call(exp) ⇒ Object

Look for calls to head()


112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# File 'lib/brakeman/processors/controller_alias_processor.rb', line 112

def process_call exp
  exp = super
  return exp unless call? exp

  method = exp.method

  if method == :head
    @rendered = true
  elsif exp.target.nil? and method == :template_exists?
    env[exp.first_arg] = Sexp.new(:lit, :"brakeman:existing_template")
  elsif @tracker.options[:interprocedural] and
    @current_method and (exp.target.nil? or exp.target.node_type == :self)

    exp = get_call_value(exp)
  end

  exp
end

#process_class(exp) ⇒ Object

Skip it, must be an inner class


73
74
75
# File 'lib/brakeman/processors/controller_alias_processor.rb', line 73

def process_class exp
  exp
end

#process_controller(name, src, current_file) ⇒ Object


23
24
25
26
27
28
29
30
31
32
33
34
35
# File 'lib/brakeman/processors/controller_alias_processor.rb', line 23

def process_controller name, src, current_file
  if not node_type? src, :class
    Brakeman.debug "#{name} is not a class, it's a #{src.node_type}"
    return
  else
    @current_class = name
    @current_file = @app_tree.file_path(current_file)

    process_default src

    process_mixins
  end
end

#process_default_render(exp) ⇒ Object

Processes the default template for the current action


174
175
176
177
# File 'lib/brakeman/processors/controller_alias_processor.rb', line 174

def process_default_render exp
  process_layout
  process_template template_name, nil, nil, nil
end

#process_defn(exp) ⇒ Object

Processes a method definition, which may include processing any rendered templates.


79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/brakeman/processors/controller_alias_processor.rb', line 79

def process_defn exp
  meth_name = exp.method_name

  Brakeman.debug "Processing #{@current_class}##{meth_name}"

  #Skip if instructed to only process a specific method
  #(but don't skip if this method was called from elsewhere)
  return exp if @current_method.nil? and @only_method and @only_method != meth_name

  is_route = route? meth_name
  other_method = @current_method
  @current_method = meth_name
  @rendered = false if is_route

  meth_env do
    if is_route
      before_filter_list(@current_method, @current_class).each do |f|
        process_before_filter f
      end
    end

    process_all exp.body

    if is_route and not @rendered
      process_default_render exp
    end
  end

  @current_method = other_method
  exp
end

#process_iter(exp) ⇒ Object

Check for respond_to


132
133
134
135
136
137
138
139
140
# File 'lib/brakeman/processors/controller_alias_processor.rb', line 132

def process_iter exp
  super

  if call? exp.block_call and exp.block_call.method == :respond_to
    @rendered = true
  end

  exp
end

#process_mixinsObject

Process modules mixed into the controller, in case they contain actions.


38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/brakeman/processors/controller_alias_processor.rb', line 38

def process_mixins
  controller = @tracker.controllers[@current_class]
  original_file = @current_file

  controller.includes.each do |i|
    mixin = @tracker.libs[i]

    next unless mixin

    #Process methods in alphabetical order for consistency
    methods = mixin.methods_public.keys.map { |n| n.to_s }.sort.map { |n| n.to_sym }

    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, mixin.file)
      method = mixin.get_method(name)[:src].deep_clone

      if node_type? method, :defn
        method = processor.process_defn method
      else
        #Should be a defn, but this will catch other cases
        method = processor.process method
      end

      @current_file = mixin.file
      #Then process it like any other method in the controller
      process method
    end
  end
ensure
  @current_file = original_file
end

#process_template(name, args, _, line) ⇒ Object

Process template and add the current class and method name as called_from info


180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
# File 'lib/brakeman/processors/controller_alias_processor.rb', line 180

def process_template name, args, _, line
  # If line is null, assume implicit render and set the end of the action
  # method as the line number
  if line.nil? and controller = @tracker.controllers[@current_class]
    if meth = controller.get_method(@current_method)
      if line = meth[:src] && meth[:src].last && meth[:src].last.line
        line += 1
      else
        line = 1
      end
    end
  end

  render_path = Brakeman::RenderPath.new.add_controller_render(@current_class, @current_method, line, @current_file)
  super name, args, render_path, line
end

#route?(method) ⇒ Boolean

Returns true if the given method name is also a route

Returns:

  • (Boolean)

225
226
227
228
229
230
231
232
# File 'lib/brakeman/processors/controller_alias_processor.rb', line 225

def route? method
  if @tracker.routes[:allow_all_actions] or @tracker.options[:assume_all_routes]
    true
  else
    routes = @tracker.routes[@current_class]
    routes and (routes.include? :allow_all_actions or routes.include? method)
  end
end

#template_name(name = nil) ⇒ Object

Turns a method name into a template name


198
199
200
201
202
203
204
205
206
207
208
# File 'lib/brakeman/processors/controller_alias_processor.rb', line 198

def template_name name = nil
  name ||= @current_method
  name = name.to_s
  if name.include? "/"
    name
  else
    controller = @current_class.to_s.gsub("Controller", "")
    controller.gsub!("::", "/")
    underscore(controller + "/" + name.to_s)
  end
end