Class: Brakeman::Rails2RoutesProcessor

Inherits:
BasicProcessor show all
Includes:
RouteHelper
Defined in:
lib/brakeman/processors/lib/rails2_route_processor.rb

Overview

Processes the Sexp from routes.rb. Stores results in tracker.routes.

Note that it is only interested in determining what methods on which controllers are used as routes, not the generated URLs for routes.

Constant Summary

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 collapse

Attributes inherited from SexpProcessor

#context, #env, #expected

Instance Method Summary collapse

Methods included from RouteHelper

#add_resource_routes, #add_resources_routes, #add_route, #current_controller=, #prefix

Methods inherited from BasicProcessor

#process_default

Methods included from Util

#array?, #block?, #call?, #camelize, #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, #regexp?, #relative_path, #request_env?, #request_value?, #result?, #set_env_defaults, #sexp?, #string?, #symbol?, #table_to_csv, #template_path_to_name, #true?, #truncate_table, #underscore

Methods included from ProcessorHelper

#class_name, #process_all, #process_all!, #process_call_args, #process_class, #process_module

Methods inherited from SexpProcessor

#error_handler, #in_context, #process, #process_dummy, #scope

Constructor Details

#initialize(tracker) ⇒ Rails2RoutesProcessor

Returns a new instance of Rails2RoutesProcessor.


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

def initialize tracker
  super
  @map = Sexp.new(:lvar, :map)
  @nested = nil  #used for identifying nested targets
  @prefix = [] #Controller name prefix (a module name, usually)
  @current_controller = nil
  @with_options = nil #For use inside map.with_options
end

Instance Attribute Details

#current_controllerObject (readonly)

Returns the value of attribute current_controller


10
11
12
# File 'lib/brakeman/processors/lib/rails2_route_processor.rb', line 10

def current_controller
  @current_controller
end

#mapObject (readonly)

Returns the value of attribute map


10
11
12
# File 'lib/brakeman/processors/lib/rails2_route_processor.rb', line 10

def map
  @map
end

#nestedObject (readonly)

Returns the value of attribute nested


10
11
12
# File 'lib/brakeman/processors/lib/rails2_route_processor.rb', line 10

def nested
  @nested
end

Instance Method Details

#process_call(exp) ⇒ Object

Looking for mapping of routes


30
31
32
33
34
35
36
37
38
39
40
# File 'lib/brakeman/processors/lib/rails2_route_processor.rb', line 30

def process_call exp
  target = exp.target

  if target == map or (not target.nil? and target == nested)
    process_map exp
  else
    process_default exp
  end

  exp
end

#process_collection(exp) ⇒ Object

Process collection option :collection => { :some_action => :http_actions }


256
257
258
259
260
261
262
263
# File 'lib/brakeman/processors/lib/rails2_route_processor.rb', line 256

def process_collection exp
  return unless exp.node_type == :hash
  routes = @tracker.routes[@current_controller]

  hash_iterate(exp) do |action, type|
    routes << action.value
  end
end

#process_connect(exp) ⇒ Object

Process map.connect '/something', :controller => 'blah', :action => 'whatever'


181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
# File 'lib/brakeman/processors/lib/rails2_route_processor.rb', line 181

def process_connect exp
  return if exp.empty?

  controller = check_for_controller_name exp
  self.current_controller = controller if controller
  
  #Check for default route
  if string? exp.first
    if exp.first.value == ":controller/:action/:id"
      @tracker.routes[:allow_all_actions] = exp.first
    elsif exp.first.value.include? ":action"
      @tracker.routes[@current_controller] = [:allow_all_actions, exp.line]
      return
    end
  end

  #This -seems- redundant, but people might connect actions
  #to a controller which already allows them all
  return if @tracker.routes[@current_controller].is_a? Array and @tracker.routes[@current_controller][0] == :allow_all_actions

  exp.last.each_with_index do |e,i|
    if symbol? e and e.value == :action
      action = exp.last[i + 1]
      
      if node_type? action, :lit
        @tracker.routes[@current_controller] << action.value.to_sym
      end

      return
    end
  end
end

#process_iter(exp) ⇒ Object

Look for map calls that take a block. Otherwise, just do the default processing.


63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/brakeman/processors/lib/rails2_route_processor.rb', line 63

def process_iter exp
  target = exp.block_call.target

  if target == map or target == nested
    method = exp.block_call.method
    case method
    when :namespace
      process_namespace exp
    when :resources, :resource
      process_resources exp.block_call.args
      process_default exp.block if exp.block
    when :with_options
      process_with_options exp
    end
    exp
  else
    process_default exp
  end
end

#process_map(exp) ⇒ Object

Process a map.something call based on the method used


44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/brakeman/processors/lib/rails2_route_processor.rb', line 44

def process_map exp
  args = exp.args

  case exp.method
  when :resource
    process_resource args
  when :resources
    process_resources args
  when :connect, :root
    process_connect args
  else
    process_named_route args
  end

  exp
end

#process_named_route(exp) ⇒ Object

map.something_abnormal '/blah', :controller => 'something', :action => 'wohoo'


250
251
252
# File 'lib/brakeman/processors/lib/rails2_route_processor.rb', line 250

def process_named_route exp
  process_connect exp
end

#process_namespace(exp) ⇒ Object

map.namespace :something do |something|

something.resources :blah

end


233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
# File 'lib/brakeman/processors/lib/rails2_route_processor.rb', line 233

def process_namespace exp
  call = exp.block_call
  formal_args = exp.block_args
  block = exp.block

  @prefix << camelize(call.first_arg.value)

  if formal_args
    @nested = Sexp.new(:lvar, formal_args.value)
  end

  process block

  @prefix.pop
end

#process_option_except(exp) ⇒ Object

Process route option :except => …


153
154
155
156
157
158
159
160
# File 'lib/brakeman/processors/lib/rails2_route_processor.rb', line 153

def process_option_except exp
  return unless exp.node_type == :array
  routes = @tracker.routes[@current_controller]

  exp[1..-1].each do |e|
    routes.delete e.value
  end
end

#process_option_only(exp) ⇒ Object

Process route option :only => …


139
140
141
142
143
144
145
146
147
148
149
150
# File 'lib/brakeman/processors/lib/rails2_route_processor.rb', line 139

def process_option_only exp
  routes = @tracker.routes[@current_controller]
  [:index, :new, :create, :show, :edit, :update, :destroy].each do |r|
    routes.delete r
  end

  if exp.node_type == :array
    exp[1..-1].each do |e|
      routes << e.value
    end
  end
end

#process_resource(exp) ⇒ Object

map.resource :x, ..


163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
# File 'lib/brakeman/processors/lib/rails2_route_processor.rb', line 163

def process_resource exp
  controller = check_for_controller_name exp
  if controller
    self.current_controller = controller
    process_resource_options exp.last
  else
    exp.each do |argument|
      if node_type? argument, :lit
        self.current_controller = pluralize(exp.first.value.to_s)
        add_resource_routes
        process_resource_options exp.last
      end
    end
  end
end

#process_resource_options(exp) ⇒ Object

Process all the options that might be in the hash passed to map.resource, et al.


104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/brakeman/processors/lib/rails2_route_processor.rb', line 104

def process_resource_options exp
  if exp.nil? and @with_options
    exp = @with_options
  elsif @with_options
    exp = exp.concat @with_options[1..-1]
  end
  return unless exp.node_type == :hash

  hash_iterate(exp) do |option, value|
    case option[1]
    when :controller, :requirements, :singular, :path_prefix, :as,
      :path_names, :shallow, :name_prefix, :member_path, :nested_member_path,
      :belongs_to, :conditions, :active_scaffold
      #should be able to skip
    when :collection, :member, :new
      process_collection value
    when :has_one
      save_controller = current_controller
      process_resource value[1..-1] #Verify this is proper behavior
      self.current_controller = save_controller
    when :has_many
      save_controller = current_controller
      process_resources value[1..-1]
      self.current_controller = save_controller
    when :only
      process_option_only value
    when :except
      process_option_except value
    else
      Brakeman.notify "[Notice] Unhandled resource option, please report: #{option}"
    end
  end
end

#process_resources(exp) ⇒ Object

Process map.resources :x, :controller => :y, :member => … etc.


86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/brakeman/processors/lib/rails2_route_processor.rb', line 86

def process_resources exp
  controller = check_for_controller_name exp
  if controller
    self.current_controller = controller
    process_resource_options exp[-1]
  else
    exp.each do |argument|
      if node_type? argument, :lit
        self.current_controller = exp.first.value
        add_resources_routes
        process_resource_options exp.last
      end
    end
  end
end

#process_routes(exp) ⇒ Object

Call this with parsed route file information.

This method first calls RouteAliasProcessor#process_safely on the exp, so it does not modify the exp.


25
26
27
# File 'lib/brakeman/processors/lib/rails2_route_processor.rb', line 25

def process_routes exp
  process Brakeman::RouteAliasProcessor.new.process_safely(exp)
end

#process_with_options(exp) ⇒ Object

map.with_options :controller => 'something' do |something|

something.resources :blah

end


217
218
219
220
221
222
223
224
225
226
227
228
# File 'lib/brakeman/processors/lib/rails2_route_processor.rb', line 217

def process_with_options exp
  @with_options = exp.block_call.last_arg
  @nested = Sexp.new(:lvar, exp.block_args.value)

  self.current_controller = check_for_controller_name exp.block_call.args
  
  #process block
  process exp.block

  @with_options = nil
  @nested = nil
end