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 included from Util

Util::ALL_PARAMETERS, Util::COOKIES, Util::PARAMETERS, Util::PATH_PARAMETERS, Util::QUERY_PARAMETERS, Util::REQUEST_ENV, Util::REQUEST_PARAMETERS, Util::REQUEST_PARAMS, Util::SESSION

Constants inherited from SexpProcessor

SexpProcessor::VERSION

Instance Attribute Summary

Attributes inherited from AliasProcessor

#result

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

#duplicate?, #find_push_target, #join_arrays, #join_strings, #only_ivars, #process_array_access, #process_attrasgn, #process_block, #process_cdecl, #process_cvdecl, #process_default, #process_gasgn, #process_hash_access, #process_hash_merge, #process_hash_merge!, #process_iasgn, #process_if, #process_lasgn, #process_op_asgn1, #process_op_asgn2, #process_safely, #process_scope, #process_selfdef, #process_svalue, #set_line

Methods included from Util

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

Methods included from ProcessorHelper

#class_name, #process_all, #process_module

Methods inherited from SexpProcessor

#error_handler, #in_context, #process, #process_dummy, #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.



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

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



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

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

  while controller
    filters = get_before_filters(method, controller) + filters

    controller = @tracker.controllers[controller[:parent]]
  end

  filters
end

#before_filter_to_hash(args) ⇒ Object

Returns a before filter as a hash table



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
281
282
283
284
285
286
# File 'lib/brakeman/processors/controller_alias_processor.rb', line 253

def before_filter_to_hash args
  filter = {}

  #Process args for the uncommon but possible situation
  #in which some variables are used in the filter.
  args.each do |a|
    if sexp? a
      a = process_default a
    end
  end

  filter[:methods] = [args[0][1]]

  args[1..-1].each do |a|
    filter[:methods] << a[1] if a.node_type == :lit
  end

  if args[-1].node_type == :hash
    option = args[-1][1][1]
    value = args[-1][2]
    case value.node_type
    when :array
      filter[option] = value[1..-1].map {|v| v[1] }
    when :lit, :str
      filter[option] = value[1]
    else
      Brakeman.debug "[Notice] Unknown before_filter value: #{option} => #{value}"
    end
  else
    filter[:all] = true
  end

  filter
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.



293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
# File 'lib/brakeman/processors/controller_alias_processor.rb', line 293

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[:public][method_name]
    method ||= controller[:private][method_name]
    method ||= controller[:protected][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 }
    end
  else
    nil
  end
end

#get_before_filters(method, controller) ⇒ Object

Returns an array of filter names



223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
# File 'lib/brakeman/processors/controller_alias_processor.rb', line 223

def get_before_filters method, controller
  return [] unless controller[:options] and controller[:options][:before_filters]

  filters = []

  if controller[:before_filter_cache].nil?
    filter_cache = []

    controller[:options][:before_filters].each do |filter|
      filter_cache << before_filter_to_hash(filter)
    end

    controller[:before_filter_cache] = filter_cache
  end

  controller[:before_filter_cache].each do |f|
    if f[:all] or 
      (f[:only] == 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)

      filters.concat f[:methods]
    end
  end

  filters
end

#layout_nameObject

Determines default layout name



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

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?



135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
# File 'lib/brakeman/processors/controller_alias_processor.rb', line 135

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)

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

def process_call exp
  exp = super

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

#process_call_with_block(exp) ⇒ Object

Check for respond_to



122
123
124
125
126
127
128
129
130
# File 'lib/brakeman/processors/controller_alias_processor.rb', line 122

def process_call_with_block exp
  process_default exp

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

  exp
end

#process_class(exp) ⇒ Object

Processes a class which is probably a controller. (This method should be retired - only classes should ever be processed and @current_module will never be set, leading to inaccurate class names)



68
69
70
71
72
73
74
75
# File 'lib/brakeman/processors/controller_alias_processor.rb', line 68

def process_class exp
  @current_class = class_name(exp.class_name)
  if @current_module
    @current_class = ("#@current_module::#@current_class").to_sym
  end

  process_default exp
end

#process_controller(name, src) ⇒ Object



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

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

    process_default src

    process_mixins
  end
end

#process_default_render(exp) ⇒ Object

Processes the default template for the current action



164
165
166
167
# File 'lib/brakeman/processors/controller_alias_processor.rb', line 164

def process_default_render exp
  process_layout
  process_template template_name, nil
end

#process_methdef(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_methdef exp
  meth_name = exp.method_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

  env.scope do
    set_env_defaults

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

    process exp.body

    if is_route and not @rendered
      process_default_render exp
    end
  end

  @current_method = other_method
  exp
end

#process_mixinsObject

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



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

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[: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)
      method = mixin[:public][name]

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

      #Then process it like any other method in the controller
      process method
    end
  end
end

#process_template(name, args) ⇒ Object

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



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

def process_template name, args
  super name, args, ["#@current_class##@current_method"]
end

#route?(method) ⇒ Boolean

Returns true if the given method name is also a route

Returns:

  • (Boolean)


202
203
204
205
206
# File 'lib/brakeman/processors/controller_alias_processor.rb', line 202

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

#template_name(name = nil) ⇒ Object

Turns a method name into a template name



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

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