brakeman-lib 3.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (159) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGES +872 -0
  3. data/FEATURES +16 -0
  4. data/README.md +169 -0
  5. data/WARNING_TYPES +95 -0
  6. data/bin/brakeman +89 -0
  7. data/lib/brakeman.rb +495 -0
  8. data/lib/brakeman/app_tree.rb +161 -0
  9. data/lib/brakeman/brakeman.rake +17 -0
  10. data/lib/brakeman/call_index.rb +219 -0
  11. data/lib/brakeman/checks.rb +191 -0
  12. data/lib/brakeman/checks/base_check.rb +518 -0
  13. data/lib/brakeman/checks/check_basic_auth.rb +88 -0
  14. data/lib/brakeman/checks/check_basic_auth_timing_attack.rb +33 -0
  15. data/lib/brakeman/checks/check_content_tag.rb +160 -0
  16. data/lib/brakeman/checks/check_create_with.rb +75 -0
  17. data/lib/brakeman/checks/check_cross_site_scripting.rb +385 -0
  18. data/lib/brakeman/checks/check_default_routes.rb +86 -0
  19. data/lib/brakeman/checks/check_deserialize.rb +57 -0
  20. data/lib/brakeman/checks/check_detailed_exceptions.rb +55 -0
  21. data/lib/brakeman/checks/check_digest_dos.rb +38 -0
  22. data/lib/brakeman/checks/check_dynamic_finders.rb +49 -0
  23. data/lib/brakeman/checks/check_escape_function.rb +21 -0
  24. data/lib/brakeman/checks/check_evaluation.rb +36 -0
  25. data/lib/brakeman/checks/check_execute.rb +167 -0
  26. data/lib/brakeman/checks/check_file_access.rb +63 -0
  27. data/lib/brakeman/checks/check_file_disclosure.rb +35 -0
  28. data/lib/brakeman/checks/check_filter_skipping.rb +31 -0
  29. data/lib/brakeman/checks/check_forgery_setting.rb +74 -0
  30. data/lib/brakeman/checks/check_header_dos.rb +31 -0
  31. data/lib/brakeman/checks/check_i18n_xss.rb +48 -0
  32. data/lib/brakeman/checks/check_jruby_xml.rb +38 -0
  33. data/lib/brakeman/checks/check_json_encoding.rb +47 -0
  34. data/lib/brakeman/checks/check_json_parsing.rb +107 -0
  35. data/lib/brakeman/checks/check_link_to.rb +132 -0
  36. data/lib/brakeman/checks/check_link_to_href.rb +115 -0
  37. data/lib/brakeman/checks/check_mail_to.rb +49 -0
  38. data/lib/brakeman/checks/check_mass_assignment.rb +198 -0
  39. data/lib/brakeman/checks/check_mime_type_dos.rb +39 -0
  40. data/lib/brakeman/checks/check_model_attr_accessible.rb +55 -0
  41. data/lib/brakeman/checks/check_model_attributes.rb +119 -0
  42. data/lib/brakeman/checks/check_model_serialize.rb +67 -0
  43. data/lib/brakeman/checks/check_nested_attributes.rb +38 -0
  44. data/lib/brakeman/checks/check_nested_attributes_bypass.rb +58 -0
  45. data/lib/brakeman/checks/check_number_to_currency.rb +74 -0
  46. data/lib/brakeman/checks/check_quote_table_name.rb +40 -0
  47. data/lib/brakeman/checks/check_redirect.rb +215 -0
  48. data/lib/brakeman/checks/check_regex_dos.rb +69 -0
  49. data/lib/brakeman/checks/check_render.rb +92 -0
  50. data/lib/brakeman/checks/check_render_dos.rb +37 -0
  51. data/lib/brakeman/checks/check_render_inline.rb +54 -0
  52. data/lib/brakeman/checks/check_response_splitting.rb +21 -0
  53. data/lib/brakeman/checks/check_route_dos.rb +42 -0
  54. data/lib/brakeman/checks/check_safe_buffer_manipulation.rb +31 -0
  55. data/lib/brakeman/checks/check_sanitize_methods.rb +79 -0
  56. data/lib/brakeman/checks/check_secrets.rb +40 -0
  57. data/lib/brakeman/checks/check_select_tag.rb +60 -0
  58. data/lib/brakeman/checks/check_select_vulnerability.rb +60 -0
  59. data/lib/brakeman/checks/check_send.rb +48 -0
  60. data/lib/brakeman/checks/check_send_file.rb +19 -0
  61. data/lib/brakeman/checks/check_session_manipulation.rb +36 -0
  62. data/lib/brakeman/checks/check_session_settings.rb +170 -0
  63. data/lib/brakeman/checks/check_simple_format.rb +59 -0
  64. data/lib/brakeman/checks/check_single_quotes.rb +101 -0
  65. data/lib/brakeman/checks/check_skip_before_filter.rb +60 -0
  66. data/lib/brakeman/checks/check_sql.rb +660 -0
  67. data/lib/brakeman/checks/check_sql_cves.rb +101 -0
  68. data/lib/brakeman/checks/check_ssl_verify.rb +49 -0
  69. data/lib/brakeman/checks/check_strip_tags.rb +89 -0
  70. data/lib/brakeman/checks/check_symbol_dos.rb +64 -0
  71. data/lib/brakeman/checks/check_symbol_dos_cve.rb +30 -0
  72. data/lib/brakeman/checks/check_translate_bug.rb +45 -0
  73. data/lib/brakeman/checks/check_unsafe_reflection.rb +51 -0
  74. data/lib/brakeman/checks/check_unscoped_find.rb +41 -0
  75. data/lib/brakeman/checks/check_validation_regex.rb +116 -0
  76. data/lib/brakeman/checks/check_weak_hash.rb +151 -0
  77. data/lib/brakeman/checks/check_without_protection.rb +80 -0
  78. data/lib/brakeman/checks/check_xml_dos.rb +51 -0
  79. data/lib/brakeman/checks/check_yaml_parsing.rb +121 -0
  80. data/lib/brakeman/differ.rb +66 -0
  81. data/lib/brakeman/file_parser.rb +50 -0
  82. data/lib/brakeman/format/style.css +133 -0
  83. data/lib/brakeman/options.rb +301 -0
  84. data/lib/brakeman/parsers/rails2_erubis.rb +6 -0
  85. data/lib/brakeman/parsers/rails2_xss_plugin_erubis.rb +48 -0
  86. data/lib/brakeman/parsers/rails3_erubis.rb +74 -0
  87. data/lib/brakeman/parsers/template_parser.rb +89 -0
  88. data/lib/brakeman/processor.rb +102 -0
  89. data/lib/brakeman/processors/alias_processor.rb +1013 -0
  90. data/lib/brakeman/processors/base_processor.rb +277 -0
  91. data/lib/brakeman/processors/config_processor.rb +14 -0
  92. data/lib/brakeman/processors/controller_alias_processor.rb +273 -0
  93. data/lib/brakeman/processors/controller_processor.rb +326 -0
  94. data/lib/brakeman/processors/erb_template_processor.rb +80 -0
  95. data/lib/brakeman/processors/erubis_template_processor.rb +104 -0
  96. data/lib/brakeman/processors/gem_processor.rb +57 -0
  97. data/lib/brakeman/processors/haml_template_processor.rb +190 -0
  98. data/lib/brakeman/processors/lib/basic_processor.rb +37 -0
  99. data/lib/brakeman/processors/lib/find_all_calls.rb +223 -0
  100. data/lib/brakeman/processors/lib/find_call.rb +183 -0
  101. data/lib/brakeman/processors/lib/find_return_value.rb +134 -0
  102. data/lib/brakeman/processors/lib/processor_helper.rb +75 -0
  103. data/lib/brakeman/processors/lib/rails2_config_processor.rb +145 -0
  104. data/lib/brakeman/processors/lib/rails2_route_processor.rb +313 -0
  105. data/lib/brakeman/processors/lib/rails3_config_processor.rb +132 -0
  106. data/lib/brakeman/processors/lib/rails3_route_processor.rb +308 -0
  107. data/lib/brakeman/processors/lib/render_helper.rb +181 -0
  108. data/lib/brakeman/processors/lib/render_path.rb +107 -0
  109. data/lib/brakeman/processors/lib/route_helper.rb +68 -0
  110. data/lib/brakeman/processors/lib/safe_call_helper.rb +16 -0
  111. data/lib/brakeman/processors/library_processor.rb +119 -0
  112. data/lib/brakeman/processors/model_processor.rb +191 -0
  113. data/lib/brakeman/processors/output_processor.rb +171 -0
  114. data/lib/brakeman/processors/route_processor.rb +17 -0
  115. data/lib/brakeman/processors/slim_template_processor.rb +107 -0
  116. data/lib/brakeman/processors/template_alias_processor.rb +116 -0
  117. data/lib/brakeman/processors/template_processor.rb +74 -0
  118. data/lib/brakeman/report.rb +78 -0
  119. data/lib/brakeman/report/config/remediation.yml +71 -0
  120. data/lib/brakeman/report/ignore/config.rb +135 -0
  121. data/lib/brakeman/report/ignore/interactive.rb +311 -0
  122. data/lib/brakeman/report/renderer.rb +24 -0
  123. data/lib/brakeman/report/report_base.rb +286 -0
  124. data/lib/brakeman/report/report_codeclimate.rb +70 -0
  125. data/lib/brakeman/report/report_csv.rb +55 -0
  126. data/lib/brakeman/report/report_hash.rb +23 -0
  127. data/lib/brakeman/report/report_html.rb +216 -0
  128. data/lib/brakeman/report/report_json.rb +42 -0
  129. data/lib/brakeman/report/report_markdown.rb +156 -0
  130. data/lib/brakeman/report/report_table.rb +107 -0
  131. data/lib/brakeman/report/report_tabs.rb +17 -0
  132. data/lib/brakeman/report/templates/controller_overview.html.erb +22 -0
  133. data/lib/brakeman/report/templates/controller_warnings.html.erb +21 -0
  134. data/lib/brakeman/report/templates/error_overview.html.erb +29 -0
  135. data/lib/brakeman/report/templates/header.html.erb +58 -0
  136. data/lib/brakeman/report/templates/ignored_warnings.html.erb +25 -0
  137. data/lib/brakeman/report/templates/model_warnings.html.erb +21 -0
  138. data/lib/brakeman/report/templates/overview.html.erb +38 -0
  139. data/lib/brakeman/report/templates/security_warnings.html.erb +23 -0
  140. data/lib/brakeman/report/templates/template_overview.html.erb +21 -0
  141. data/lib/brakeman/report/templates/view_warnings.html.erb +34 -0
  142. data/lib/brakeman/report/templates/warning_overview.html.erb +17 -0
  143. data/lib/brakeman/rescanner.rb +483 -0
  144. data/lib/brakeman/scanner.rb +317 -0
  145. data/lib/brakeman/tracker.rb +347 -0
  146. data/lib/brakeman/tracker/collection.rb +93 -0
  147. data/lib/brakeman/tracker/config.rb +101 -0
  148. data/lib/brakeman/tracker/constants.rb +101 -0
  149. data/lib/brakeman/tracker/controller.rb +161 -0
  150. data/lib/brakeman/tracker/library.rb +17 -0
  151. data/lib/brakeman/tracker/model.rb +90 -0
  152. data/lib/brakeman/tracker/template.rb +33 -0
  153. data/lib/brakeman/util.rb +481 -0
  154. data/lib/brakeman/version.rb +3 -0
  155. data/lib/brakeman/warning.rb +255 -0
  156. data/lib/brakeman/warning_codes.rb +111 -0
  157. data/lib/ruby_parser/bm_sexp.rb +610 -0
  158. data/lib/ruby_parser/bm_sexp_processor.rb +116 -0
  159. metadata +362 -0
@@ -0,0 +1,313 @@
1
+ require 'brakeman/processors/lib/basic_processor'
2
+
3
+ #Processes the Sexp from routes.rb. Stores results in tracker.routes.
4
+ #
5
+ #Note that it is only interested in determining what methods on which
6
+ #controllers are used as routes, not the generated URLs for routes.
7
+ class Brakeman::Rails2RoutesProcessor < Brakeman::BasicProcessor
8
+ include Brakeman::RouteHelper
9
+
10
+ attr_reader :map, :nested, :current_controller
11
+
12
+ def initialize tracker
13
+ super
14
+ @map = Sexp.new(:lvar, :map)
15
+ @nested = nil #used for identifying nested targets
16
+ @prefix = [] #Controller name prefix (a module name, usually)
17
+ @current_controller = nil
18
+ @with_options = nil #For use inside map.with_options
19
+ @file_name = "config/routes.rb"
20
+ end
21
+
22
+ #Call this with parsed route file information.
23
+ #
24
+ #This method first calls RouteAliasProcessor#process_safely on the +exp+,
25
+ #so it does not modify the +exp+.
26
+ def process_routes exp
27
+ process Brakeman::RouteAliasProcessor.new.process_safely(exp, nil, @file_name)
28
+ end
29
+
30
+ #Looking for mapping of routes
31
+ def process_call exp
32
+ target = exp.target
33
+
34
+ if target == map or (not target.nil? and target == nested)
35
+ process_map exp
36
+ else
37
+ process_default exp
38
+ end
39
+
40
+ exp
41
+ end
42
+
43
+ #Process a map.something call
44
+ #based on the method used
45
+ def process_map exp
46
+ args = exp.args
47
+
48
+ case exp.method
49
+ when :resource
50
+ process_resource args
51
+ when :resources
52
+ process_resources args
53
+ when :connect, :root
54
+ process_connect args
55
+ else
56
+ process_named_route args
57
+ end
58
+
59
+ exp
60
+ end
61
+
62
+ #Look for map calls that take a block.
63
+ #Otherwise, just do the default processing.
64
+ def process_iter exp
65
+ target = exp.block_call.target
66
+
67
+ if target == map or target == nested
68
+ method = exp.block_call.method
69
+ case method
70
+ when :namespace
71
+ process_namespace exp
72
+ when :resources, :resource
73
+ process_resources exp.block_call.args
74
+ process_default exp.block if exp.block
75
+ when :with_options
76
+ process_with_options exp
77
+ end
78
+ exp
79
+ else
80
+ process_default exp
81
+ end
82
+ end
83
+
84
+ #Process
85
+ # map.resources :x, :controller => :y, :member => ...
86
+ #etc.
87
+ def process_resources exp
88
+ controller = check_for_controller_name exp
89
+ if controller
90
+ self.current_controller = controller
91
+ process_resource_options exp[-1]
92
+ else
93
+ exp.each do |argument|
94
+ if node_type? argument, :lit
95
+ self.current_controller = exp.first.value
96
+ add_resources_routes
97
+ process_resource_options exp.last
98
+ end
99
+ end
100
+ end
101
+ end
102
+
103
+ #Process all the options that might be in the hash passed to
104
+ #map.resource, et al.
105
+ def process_resource_options exp
106
+ if exp.nil? and @with_options
107
+ exp = @with_options
108
+ elsif @with_options
109
+ exp = exp.concat @with_options[1..-1]
110
+ end
111
+ return unless exp.node_type == :hash
112
+
113
+ hash_iterate(exp) do |option, value|
114
+ case option[1]
115
+ when :controller, :requirements, :singular, :path_prefix, :as,
116
+ :path_names, :shallow, :name_prefix, :member_path, :nested_member_path,
117
+ :belongs_to, :conditions, :active_scaffold
118
+ #should be able to skip
119
+ when :collection, :member, :new
120
+ process_collection value
121
+ when :has_one
122
+ save_controller = current_controller
123
+ process_resource value[1..-1] #Verify this is proper behavior
124
+ self.current_controller = save_controller
125
+ when :has_many
126
+ save_controller = current_controller
127
+ process_resources value[1..-1]
128
+ self.current_controller = save_controller
129
+ when :only
130
+ process_option_only value
131
+ when :except
132
+ process_option_except value
133
+ else
134
+ Brakeman.notify "[Notice] Unhandled resource option, please report: #{option}"
135
+ end
136
+ end
137
+ end
138
+
139
+ #Process route option :only => ...
140
+ def process_option_only exp
141
+ routes = @tracker.routes[@current_controller]
142
+ [:index, :new, :create, :show, :edit, :update, :destroy].each do |r|
143
+ routes.delete r
144
+ end
145
+
146
+ if exp.node_type == :array
147
+ exp[1..-1].each do |e|
148
+ routes << e.value
149
+ end
150
+ end
151
+ end
152
+
153
+ #Process route option :except => ...
154
+ def process_option_except exp
155
+ return unless exp.node_type == :array
156
+ routes = @tracker.routes[@current_controller]
157
+
158
+ exp[1..-1].each do |e|
159
+ routes.delete e.value
160
+ end
161
+ end
162
+
163
+ # map.resource :x, ..
164
+ def process_resource exp
165
+ controller = check_for_controller_name exp
166
+ if controller
167
+ self.current_controller = controller
168
+ process_resource_options exp.last
169
+ else
170
+ exp.each do |argument|
171
+ if node_type? argument, :lit
172
+ self.current_controller = pluralize(exp.first.value.to_s)
173
+ add_resource_routes
174
+ process_resource_options exp.last
175
+ end
176
+ end
177
+ end
178
+ end
179
+
180
+ #Process
181
+ # map.connect '/something', :controller => 'blah', :action => 'whatever'
182
+ def process_connect exp
183
+ return if exp.empty?
184
+
185
+ controller = check_for_controller_name exp
186
+ self.current_controller = controller if controller
187
+
188
+ #Check for default route
189
+ if string? exp.first
190
+ if exp.first.value == ":controller/:action/:id"
191
+ @tracker.routes[:allow_all_actions] = exp.first
192
+ elsif exp.first.value.include? ":action"
193
+ @tracker.routes[@current_controller] = [:allow_all_actions, exp.line]
194
+ return
195
+ end
196
+ end
197
+
198
+ #This -seems- redundant, but people might connect actions
199
+ #to a controller which already allows them all
200
+ return if @tracker.routes[@current_controller].is_a? Array and @tracker.routes[@current_controller][0] == :allow_all_actions
201
+
202
+ exp.last.each_with_index do |e,i|
203
+ if symbol? e and e.value == :action
204
+ action = exp.last[i + 1]
205
+
206
+ if node_type? action, :lit
207
+ @tracker.routes[@current_controller] << action.value.to_sym
208
+ end
209
+
210
+ return
211
+ end
212
+ end
213
+ end
214
+
215
+ # map.with_options :controller => 'something' do |something|
216
+ # something.resources :blah
217
+ # end
218
+ def process_with_options exp
219
+ @with_options = exp.block_call.last_arg
220
+ @nested = Sexp.new(:lvar, exp.block_args.value)
221
+
222
+ self.current_controller = check_for_controller_name exp.block_call.args
223
+
224
+ #process block
225
+ process exp.block
226
+
227
+ @with_options = nil
228
+ @nested = nil
229
+ end
230
+
231
+ # map.namespace :something do |something|
232
+ # something.resources :blah
233
+ # end
234
+ def process_namespace exp
235
+ call = exp.block_call
236
+ formal_args = exp.block_args
237
+ block = exp.block
238
+
239
+ @prefix << camelize(call.first_arg.value)
240
+
241
+ if formal_args
242
+ @nested = Sexp.new(:lvar, formal_args.value)
243
+ end
244
+
245
+ process block
246
+
247
+ @prefix.pop
248
+ end
249
+
250
+ # map.something_abnormal '/blah', :controller => 'something', :action => 'wohoo'
251
+ def process_named_route exp
252
+ process_connect exp
253
+ end
254
+
255
+ #Process collection option
256
+ # :collection => { :some_action => :http_actions }
257
+ def process_collection exp
258
+ return unless exp.node_type == :hash
259
+ routes = @tracker.routes[@current_controller]
260
+
261
+ hash_iterate(exp) do |action, type|
262
+ routes << action.value
263
+ end
264
+ end
265
+
266
+ private
267
+
268
+ #Checks an argument list for a hash that has a key :controller.
269
+ #If it does, returns the value.
270
+ #
271
+ #Otherwise, returns nil.
272
+ def check_for_controller_name args
273
+ args.each do |a|
274
+ if hash? a and value = hash_access(a, :controller)
275
+ return value.value if string? value or symbol? value
276
+ end
277
+ end
278
+
279
+ nil
280
+ end
281
+ end
282
+
283
+ #This is for a really specific case where a hash is used as arguments
284
+ #to one of the map methods.
285
+ class Brakeman::RouteAliasProcessor < Brakeman::AliasProcessor
286
+
287
+ #This replaces
288
+ # { :some => :hash }.keys
289
+ #with
290
+ # [:some]
291
+ def process_call exp
292
+ process_default exp
293
+
294
+ if hash? exp.target and exp.method == :keys
295
+ keys = get_keys exp.target
296
+ exp.clear
297
+ keys.each_with_index do |e,i|
298
+ exp[i] = e
299
+ end
300
+ end
301
+ exp
302
+ end
303
+
304
+ #Returns an array Sexp containing the keys from the hash
305
+ def get_keys hash
306
+ keys = Sexp.new(:array)
307
+ hash_iterate(hash) do |key, value|
308
+ keys << key
309
+ end
310
+
311
+ keys
312
+ end
313
+ end
@@ -0,0 +1,132 @@
1
+
2
+ require 'brakeman/processors/lib/basic_processor'
3
+
4
+ #Processes configuration. Results are put in tracker.config.
5
+ #
6
+ #Configuration of Rails via Rails::Initializer are stored in tracker.config.rails.
7
+ #For example:
8
+ #
9
+ # MyApp::Application.configure do
10
+ # config.active_record.whitelist_attributes = true
11
+ # end
12
+ #
13
+ #will be stored in
14
+ #
15
+ # tracker.config.rails[:active_record][:whitelist_attributes]
16
+ #
17
+ #Values for tracker.config.rails will still be Sexps.
18
+ class Brakeman::Rails3ConfigProcessor < Brakeman::BasicProcessor
19
+ RAILS_CONFIG = Sexp.new(:call, nil, :config)
20
+
21
+ def initialize *args
22
+ super
23
+ @inside_config = false
24
+ end
25
+
26
+ #Use this method to process configuration file
27
+ def process_config src, file_name
28
+ @file_name = file_name
29
+ res = Brakeman::AliasProcessor.new(@tracker).process_safely(src, nil, @file_name)
30
+ process res
31
+ end
32
+
33
+ #Look for MyApp::Application.configure do ... end
34
+ def process_iter exp
35
+ call = exp.block_call
36
+
37
+ if node_type?(call.target, :colon2) and
38
+ call.target.rhs == :Application and
39
+ call.method == :configure
40
+
41
+ @inside_config = true
42
+ process exp.block if sexp? exp.block
43
+ @inside_config = false
44
+ end
45
+
46
+ exp
47
+ end
48
+
49
+ #Look for class Application < Rails::Application
50
+ def process_class exp
51
+ if exp.class_name == :Application
52
+ @inside_config = true
53
+ process_all exp.body if sexp? exp.body
54
+ @inside_config = false
55
+ end
56
+
57
+ exp
58
+ end
59
+
60
+ #Look for configuration settings
61
+ def process_attrasgn exp
62
+ return exp unless @inside_config
63
+
64
+ if exp.target == RAILS_CONFIG
65
+ #Get rid of '=' at end
66
+ attribute = exp.method.to_s[0..-2].to_sym
67
+ if exp.args.length > 1
68
+ #Multiple arguments?...not sure if this will ever happen
69
+ @tracker.config.rails[attribute] = exp.args
70
+ else
71
+ @tracker.config.rails[attribute] = exp.first_arg
72
+ end
73
+ elsif include_rails_config? exp
74
+ options = get_rails_config exp
75
+ level = @tracker.config.rails
76
+ options[0..-2].each do |o|
77
+ level[o] ||= {}
78
+
79
+ option = level[o]
80
+
81
+ if not option.is_a? Hash
82
+ Brakeman.debug "[Notice] Skipping config setting: #{options.map(&:to_s).join(".")}"
83
+ return exp
84
+ end
85
+
86
+ level = level[o]
87
+ end
88
+
89
+ level[options.last] = exp.first_arg
90
+ end
91
+
92
+ exp
93
+ end
94
+
95
+ #Check if an expression includes a call to set Rails config
96
+ def include_rails_config? exp
97
+ target = exp.target
98
+ if call? target
99
+ if target.target == RAILS_CONFIG
100
+ true
101
+ else
102
+ include_rails_config? target
103
+ end
104
+ elsif target == RAILS_CONFIG
105
+ true
106
+ else
107
+ false
108
+ end
109
+ end
110
+
111
+ #Returns an array of symbols for each 'level' in the config
112
+ #
113
+ # config.action_controller.session_store = :cookie
114
+ #
115
+ #becomes
116
+ #
117
+ # [:action_controller, :session_store]
118
+ def get_rails_config exp
119
+ if node_type? exp, :attrasgn
120
+ attribute = exp.method.to_s[0..-2].to_sym
121
+ get_rails_config(exp.target) << attribute
122
+ elsif call? exp
123
+ if exp.target == RAILS_CONFIG
124
+ [exp.method]
125
+ else
126
+ get_rails_config(exp.target) << exp.method
127
+ end
128
+ else
129
+ raise "WHAT"
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,308 @@
1
+ require 'brakeman/processors/lib/basic_processor'
2
+
3
+ #Processes the Sexp from routes.rb. Stores results in tracker.routes.
4
+ #
5
+ #Note that it is only interested in determining what methods on which
6
+ #controllers are used as routes, not the generated URLs for routes.
7
+ class Brakeman::Rails3RoutesProcessor < Brakeman::BasicProcessor
8
+ include Brakeman::RouteHelper
9
+
10
+ attr_reader :map, :nested, :current_controller
11
+
12
+ def initialize tracker
13
+ super
14
+ @map = Sexp.new(:lvar, :map)
15
+ @nested = nil #used for identifying nested targets
16
+ @prefix = [] #Controller name prefix (a module name, usually)
17
+ @current_controller = nil
18
+ @with_options = nil #For use inside map.with_options
19
+ @controller_block = false
20
+ @file_name = "config/routes.rb"
21
+ end
22
+
23
+ def process_routes exp
24
+ process Brakeman::AliasProcessor.new.process_safely(exp, nil, @file_name)
25
+ end
26
+
27
+ def process_call exp
28
+ case exp.method
29
+ when :resources
30
+ process_resources exp
31
+ when :resource
32
+ process_resource exp
33
+ when :root
34
+ process_root exp
35
+ when :member
36
+ process_default exp
37
+ when :get, :put, :post, :delete
38
+ process_verb exp
39
+ when :match
40
+ process_match exp
41
+ else
42
+ exp
43
+ end
44
+ end
45
+
46
+ def process_iter exp
47
+ case exp.block_call.method
48
+ when :namespace
49
+ process_namespace exp
50
+ when :resource
51
+ process_resource_block exp
52
+ when :resources
53
+ process_resources_block exp
54
+ when :scope
55
+ process_scope_block exp
56
+ when :controller
57
+ process_controller_block exp
58
+ else
59
+ process_default exp
60
+ end
61
+ end
62
+
63
+ def process_namespace exp
64
+ arg = exp.block_call.first_arg
65
+ return exp unless symbol? arg or string? arg
66
+
67
+ name = arg.value
68
+ block = exp.block
69
+
70
+ @prefix << camelize(name)
71
+
72
+ process block
73
+
74
+ @prefix.pop
75
+
76
+ exp
77
+ end
78
+
79
+ #TODO: Need test for this
80
+ def process_root exp
81
+ if value = hash_access(exp.first_arg, :to)
82
+ if string? value
83
+ add_route_from_string value
84
+ end
85
+ end
86
+
87
+ exp
88
+ end
89
+
90
+ def process_match exp
91
+ first_arg = exp.first_arg
92
+ second_arg = exp.second_arg
93
+ last_arg = exp.last_arg
94
+
95
+ if string? first_arg
96
+
97
+ matcher = first_arg.value
98
+ if matcher == ':controller(/:action(/:id(.:format)))' or
99
+ matcher.include? ':controller' and action_route?(matcher) #Default routes
100
+ @tracker.routes[:allow_all_actions] = first_arg
101
+ return exp
102
+ elsif action_route?(first_arg)
103
+ if hash? second_arg and controller_name = hash_access(second_arg, :controller)
104
+ loose_action(controller_name, "matched") #TODO: Parse verbs
105
+ end
106
+ elsif second_arg.nil? and in_controller_block? and not matcher.include? ":"
107
+ add_route matcher
108
+ end
109
+ end
110
+
111
+ if hash? last_arg
112
+ hash_iterate last_arg do |k, v|
113
+ if string? k
114
+ if string? v
115
+ add_route_from_string v
116
+ elsif in_controller_block? and symbol? v
117
+ add_route v
118
+ end
119
+ elsif symbol? k
120
+ case k.value
121
+ when :action
122
+ if string? v
123
+ add_route_from_string v
124
+ else
125
+ add_route v
126
+ end
127
+
128
+ when :to
129
+ if string? v
130
+ add_route_from_string v[1]
131
+ elsif in_controller_block? and symbol? v
132
+ add_route v
133
+ end
134
+ end
135
+ end
136
+ end
137
+ end
138
+
139
+ @current_controller = nil unless in_controller_block?
140
+ exp
141
+ end
142
+
143
+ def add_route_from_string value
144
+ value = value[1] if string? value
145
+
146
+ controller, action = extract_action value
147
+
148
+ if action
149
+ add_route action, controller
150
+ elsif in_controller_block?
151
+ add_route value
152
+ end
153
+ end
154
+
155
+ def process_verb exp
156
+ first_arg = exp.first_arg
157
+ second_arg = exp.second_arg
158
+
159
+ if symbol? first_arg and not hash? second_arg
160
+ add_route first_arg
161
+ elsif hash? second_arg
162
+ hash_iterate second_arg do |k, v|
163
+ if symbol? k and k.value == :to
164
+ if string? v
165
+ add_route_from_string v
166
+ elsif in_controller_block? and symbol? v
167
+ add_route v
168
+ end
169
+ elsif action_route?(first_arg)
170
+ if hash? second_arg and controller_name = hash_access(second_arg, :controller)
171
+ loose_action(controller_name, exp.method)
172
+ end
173
+ end
174
+ end
175
+ elsif string? first_arg
176
+ if first_arg.value.include? ':controller' and action_route?(first_arg) #Default routes
177
+ @tracker.routes[:allow_all_actions] = first_arg
178
+ end
179
+
180
+ route = first_arg.value.split "/"
181
+ if route.length != 2
182
+ add_route route[0]
183
+ else
184
+ add_route route[1], route[0]
185
+ end
186
+ elsif in_controller_block? and symbol? first_arg
187
+ add_route first_arg
188
+ else hash? first_arg
189
+ hash_iterate first_arg do |k, v|
190
+ if string? k
191
+ if string? v
192
+ add_route_from_string v
193
+ elsif in_controller_block?
194
+ add_route v
195
+ end
196
+ end
197
+ end
198
+ end
199
+
200
+ @current_controller = nil unless in_controller_block?
201
+ exp
202
+ end
203
+
204
+ def process_resources exp
205
+ first_arg = exp.first_arg
206
+ second_arg = exp.second_arg
207
+
208
+ return exp unless symbol? first_arg or string? first_arg
209
+
210
+ if second_arg and second_arg.node_type == :hash
211
+ self.current_controller = first_arg.value
212
+ #handle hash
213
+ add_resources_routes
214
+ elsif exp.args.all? { |s| symbol? s }
215
+ exp.each_arg do |s|
216
+ self.current_controller = s.value
217
+ add_resources_routes
218
+ end
219
+ end
220
+
221
+ @current_controller = nil unless in_controller_block?
222
+ exp
223
+ end
224
+
225
+ def process_resource exp
226
+ #Does resource even take more than one controller name?
227
+ exp.each_arg do |s|
228
+ if symbol? s
229
+ self.current_controller = pluralize(s.value.to_s)
230
+ add_resource_routes
231
+ else
232
+ #handle something else, like options
233
+ #or something?
234
+ end
235
+ end
236
+
237
+ @current_controller = nil unless in_controller_block?
238
+ exp
239
+ end
240
+
241
+ def process_resources_block exp
242
+ in_controller_block do
243
+ process_resources exp.block_call
244
+ process exp.block
245
+ end
246
+
247
+ @current_controller = nil
248
+ exp
249
+ end
250
+
251
+ def process_resource_block exp
252
+ in_controller_block do
253
+ process_resource exp.block_call
254
+ process exp.block
255
+ end
256
+
257
+ @current_controller = nil
258
+ exp
259
+ end
260
+
261
+ def process_scope_block exp
262
+ #How to deal with options?
263
+ process exp.block
264
+ exp
265
+ end
266
+
267
+ def process_controller_block exp
268
+ if string? exp or symbol? exp
269
+ self.current_controller = exp.block_call.first_arg.value
270
+
271
+ in_controller_block do
272
+ process exp[-1] if exp[-1]
273
+ end
274
+
275
+ @current_controller = nil
276
+ end
277
+
278
+ exp
279
+ end
280
+
281
+ def extract_action str
282
+ str.split "#"
283
+ end
284
+
285
+ def in_controller_block?
286
+ @controller_block
287
+ end
288
+
289
+ def in_controller_block
290
+ prev_block = @controller_block
291
+ @controller_block = true
292
+ yield
293
+ @controller_block = prev_block
294
+ end
295
+
296
+ def action_route? arg
297
+ if string? arg
298
+ arg = arg.value
299
+ end
300
+
301
+ arg.is_a? String and (arg.include? ":action" or arg.include? "*action")
302
+ end
303
+
304
+ def loose_action controller_name, verb = "any"
305
+ self.current_controller = controller_name.value
306
+ @tracker.routes[@current_controller] = [:allow_all_actions, {:allow_verb => verb}]
307
+ end
308
+ end