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

Constants included from Util

Util::ALL_PARAMETERS, Util::COOKIES, Util::COOKIES_SEXP, Util::PARAMETERS, Util::PARAMS_SEXP, Util::PATH_PARAMETERS, Util::QUERY_PARAMETERS, Util::REQUEST_ENV, Util::REQUEST_PARAMETERS, Util::REQUEST_PARAMS, 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_include_all_literals?, #assign_args, #collapse_send_call, #duplicate?, #find_push_target, #get_call_value, #get_rhs, #join_arrays, #join_strings, #merge_if_branch, #meth_env, #only_ivars, #only_request_vars, #process_array_access, #process_attrasgn, #process_block, #process_cdecl, #process_cvdecl, #process_default, #process_defs, #process_gasgn, #process_hash_access, #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, #replace, #same_value?, #self_assign?, #self_assign_target?, #self_assign_var?, #set_value, #too_deep?, #top_target, #value_from_if

Methods included from Util

#array?, #block?, #call?, #camelize, #class_name, #contains_class?, #context_for, #cookies?, #false?, #file_by_name, #file_for, #github_url, #hash?, #hash_access, #hash_insert, #hash_iterate, #integer?, #make_call, #node_type?, #number?, #params?, #pluralize, #rails_version, #regexp?, #relative_path, #request_env?, #request_value?, #result?, #set_env_defaults, #sexp?, #string?, #string_interp?, #symbol?, #table_to_csv, #template_path_to_name, #true?, #truncate_table, #underscore

Methods included from ProcessorHelper

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

Methods inherited from SexpProcessor

#in_context, #process, processors, #scope

Constructor Details

#initialize(app_tree, 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 app_tree, tracker, only_method = nil
  super tracker
  @app_tree = 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



227
228
229
230
231
232
233
234
235
# File 'lib/brakeman/processors/controller_alias_processor.rb', line 227

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.



242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
# File 'lib/brakeman/processors/controller_alias_processor.rb', line 242

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



203
204
205
206
207
208
209
210
211
212
213
214
# File 'lib/brakeman/processors/controller_alias_processor.rb', line 203

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?



140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
# File 'lib/brakeman/processors/controller_alias_processor.rb', line 140

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()



109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/brakeman/processors/controller_alias_processor.rb', line 109

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

  method = exp.method

  if method == :head
    @rendered = true
  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



70
71
72
# File 'lib/brakeman/processors/controller_alias_processor.rb', line 70

def process_class exp
  exp
end

#process_controller(name, src, 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, 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
    @file = file

    process_default src

    process_mixins
  end
end

#process_default_render(exp) ⇒ Object

Processes the default template for the current action



169
170
171
172
# File 'lib/brakeman/processors/controller_alias_processor.rb', line 169

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.



76
77
78
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
# File 'lib/brakeman/processors/controller_alias_processor.rb', line 76

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



127
128
129
130
131
132
133
134
135
# File 'lib/brakeman/processors/controller_alias_processor.rb', line 127

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
# File 'lib/brakeman/processors/controller_alias_processor.rb', line 38

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

  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(@app_tree, @tracker)
      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

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

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

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



175
176
177
178
179
180
181
182
183
184
185
186
187
# File 'lib/brakeman/processors/controller_alias_processor.rb', line 175

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)
      line = meth[:src] && meth[:src].last && meth[:src].last.line
      line += 1
    end
  end

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

#route?(method) ⇒ Boolean

Returns true if the given method name is also a route

Returns:

  • (Boolean)


217
218
219
220
221
222
223
224
# File 'lib/brakeman/processors/controller_alias_processor.rb', line 217

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



190
191
192
193
194
195
196
197
198
199
200
# File 'lib/brakeman/processors/controller_alias_processor.rb', line 190

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