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_DEV, AliasProcessor::RAILS_TEST, AliasProcessor::STRING_NEW, AliasProcessor::TEMP_FILE_CLASS

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, Util::SIMPLE_LITERALS

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

#all_literals_when?, #array_detect_all_literals?, #array_include_all_literals?, #assign_args, #collapse_send_call, #duplicate?, #early_return?, #equality_check?, #find_method, #find_push_target, #get_call_value, #get_rhs, #hash_include_all_literals?, #hash_or_array_include_all_literals?, #in_array_all_literals?, #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_branch_with_value, #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?, #splat_array?, #temp_file_new, #temp_file_open?, #too_deep?, #top_target, #value_from_case, #value_from_if

Methods included from CallConversionHelper

#hash_values_at, #join_arrays, #join_strings, #math_op, #process_array_access, #process_hash_access

Methods included from Util

#all_literals?, #array?, #block?, #call?, #camelize, #class_name, #constant?, #contains_class?, #cookies?, #dir_glob?, #false?, #hash?, #hash_access, #hash_insert, #hash_iterate, #hash_values, #integer?, #kwsplat?, #literal?, #make_call, #node_type?, #number?, #params?, #pluralize, #rails_version, #recurse_check?, #regexp?, #remove_kwsplat, #request_headers?, #request_value?, #result?, #safe_literal, #safe_literal?, #safe_literal_target?, #set_env_defaults, #sexp?, #simple_literal?, #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.

[View source]

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

[View source]

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

#layout_nameObject

Determines default layout name

[View source]

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?

[View source]

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 = tracker.find_method name, @current_class

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

  method = filter.src

  if ivars = @tracker.filter_cache[[filter.owner, 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.owner, name]] = ivars

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

#process_call(exp) ⇒ Object

Look for calls to head()

[View source]

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

[View source]

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

[View source]

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

[View source]

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.

[View source]

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

[View source]

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.

[View source]

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

[View source]

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)
[View source]

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

[View source]

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