railroader 4.3.4

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 (165) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGES.md +1091 -0
  3. data/FEATURES +16 -0
  4. data/README.md +174 -0
  5. data/bin/railroader +8 -0
  6. data/lib/railroader/app_tree.rb +191 -0
  7. data/lib/railroader/call_index.rb +219 -0
  8. data/lib/railroader/checks/base_check.rb +505 -0
  9. data/lib/railroader/checks/check_basic_auth.rb +88 -0
  10. data/lib/railroader/checks/check_basic_auth_timing_attack.rb +33 -0
  11. data/lib/railroader/checks/check_content_tag.rb +200 -0
  12. data/lib/railroader/checks/check_create_with.rb +74 -0
  13. data/lib/railroader/checks/check_cross_site_scripting.rb +381 -0
  14. data/lib/railroader/checks/check_default_routes.rb +86 -0
  15. data/lib/railroader/checks/check_deserialize.rb +56 -0
  16. data/lib/railroader/checks/check_detailed_exceptions.rb +55 -0
  17. data/lib/railroader/checks/check_digest_dos.rb +38 -0
  18. data/lib/railroader/checks/check_divide_by_zero.rb +42 -0
  19. data/lib/railroader/checks/check_dynamic_finders.rb +48 -0
  20. data/lib/railroader/checks/check_escape_function.rb +21 -0
  21. data/lib/railroader/checks/check_evaluation.rb +35 -0
  22. data/lib/railroader/checks/check_execute.rb +189 -0
  23. data/lib/railroader/checks/check_file_access.rb +71 -0
  24. data/lib/railroader/checks/check_file_disclosure.rb +35 -0
  25. data/lib/railroader/checks/check_filter_skipping.rb +31 -0
  26. data/lib/railroader/checks/check_forgery_setting.rb +81 -0
  27. data/lib/railroader/checks/check_header_dos.rb +31 -0
  28. data/lib/railroader/checks/check_i18n_xss.rb +48 -0
  29. data/lib/railroader/checks/check_jruby_xml.rb +36 -0
  30. data/lib/railroader/checks/check_json_encoding.rb +47 -0
  31. data/lib/railroader/checks/check_json_parsing.rb +107 -0
  32. data/lib/railroader/checks/check_link_to.rb +132 -0
  33. data/lib/railroader/checks/check_link_to_href.rb +146 -0
  34. data/lib/railroader/checks/check_mail_to.rb +49 -0
  35. data/lib/railroader/checks/check_mass_assignment.rb +196 -0
  36. data/lib/railroader/checks/check_mime_type_dos.rb +39 -0
  37. data/lib/railroader/checks/check_model_attr_accessible.rb +55 -0
  38. data/lib/railroader/checks/check_model_attributes.rb +119 -0
  39. data/lib/railroader/checks/check_model_serialize.rb +67 -0
  40. data/lib/railroader/checks/check_nested_attributes.rb +38 -0
  41. data/lib/railroader/checks/check_nested_attributes_bypass.rb +58 -0
  42. data/lib/railroader/checks/check_number_to_currency.rb +74 -0
  43. data/lib/railroader/checks/check_permit_attributes.rb +43 -0
  44. data/lib/railroader/checks/check_quote_table_name.rb +40 -0
  45. data/lib/railroader/checks/check_redirect.rb +256 -0
  46. data/lib/railroader/checks/check_regex_dos.rb +68 -0
  47. data/lib/railroader/checks/check_render.rb +97 -0
  48. data/lib/railroader/checks/check_render_dos.rb +37 -0
  49. data/lib/railroader/checks/check_render_inline.rb +53 -0
  50. data/lib/railroader/checks/check_response_splitting.rb +21 -0
  51. data/lib/railroader/checks/check_route_dos.rb +42 -0
  52. data/lib/railroader/checks/check_safe_buffer_manipulation.rb +31 -0
  53. data/lib/railroader/checks/check_sanitize_methods.rb +112 -0
  54. data/lib/railroader/checks/check_secrets.rb +40 -0
  55. data/lib/railroader/checks/check_select_tag.rb +59 -0
  56. data/lib/railroader/checks/check_select_vulnerability.rb +60 -0
  57. data/lib/railroader/checks/check_send.rb +47 -0
  58. data/lib/railroader/checks/check_send_file.rb +19 -0
  59. data/lib/railroader/checks/check_session_manipulation.rb +35 -0
  60. data/lib/railroader/checks/check_session_settings.rb +176 -0
  61. data/lib/railroader/checks/check_simple_format.rb +58 -0
  62. data/lib/railroader/checks/check_single_quotes.rb +101 -0
  63. data/lib/railroader/checks/check_skip_before_filter.rb +60 -0
  64. data/lib/railroader/checks/check_sql.rb +700 -0
  65. data/lib/railroader/checks/check_sql_cves.rb +106 -0
  66. data/lib/railroader/checks/check_ssl_verify.rb +48 -0
  67. data/lib/railroader/checks/check_strip_tags.rb +89 -0
  68. data/lib/railroader/checks/check_symbol_dos.rb +71 -0
  69. data/lib/railroader/checks/check_symbol_dos_cve.rb +30 -0
  70. data/lib/railroader/checks/check_translate_bug.rb +45 -0
  71. data/lib/railroader/checks/check_unsafe_reflection.rb +50 -0
  72. data/lib/railroader/checks/check_unscoped_find.rb +57 -0
  73. data/lib/railroader/checks/check_validation_regex.rb +116 -0
  74. data/lib/railroader/checks/check_weak_hash.rb +148 -0
  75. data/lib/railroader/checks/check_without_protection.rb +80 -0
  76. data/lib/railroader/checks/check_xml_dos.rb +45 -0
  77. data/lib/railroader/checks/check_yaml_parsing.rb +121 -0
  78. data/lib/railroader/checks.rb +209 -0
  79. data/lib/railroader/codeclimate/engine_configuration.rb +97 -0
  80. data/lib/railroader/commandline.rb +179 -0
  81. data/lib/railroader/differ.rb +66 -0
  82. data/lib/railroader/file_parser.rb +54 -0
  83. data/lib/railroader/format/style.css +133 -0
  84. data/lib/railroader/options.rb +339 -0
  85. data/lib/railroader/parsers/rails2_erubis.rb +6 -0
  86. data/lib/railroader/parsers/rails2_xss_plugin_erubis.rb +48 -0
  87. data/lib/railroader/parsers/rails3_erubis.rb +81 -0
  88. data/lib/railroader/parsers/template_parser.rb +108 -0
  89. data/lib/railroader/processor.rb +102 -0
  90. data/lib/railroader/processors/alias_processor.rb +1229 -0
  91. data/lib/railroader/processors/base_processor.rb +295 -0
  92. data/lib/railroader/processors/config_processor.rb +14 -0
  93. data/lib/railroader/processors/controller_alias_processor.rb +278 -0
  94. data/lib/railroader/processors/controller_processor.rb +249 -0
  95. data/lib/railroader/processors/erb_template_processor.rb +77 -0
  96. data/lib/railroader/processors/erubis_template_processor.rb +92 -0
  97. data/lib/railroader/processors/gem_processor.rb +64 -0
  98. data/lib/railroader/processors/haml_template_processor.rb +191 -0
  99. data/lib/railroader/processors/lib/basic_processor.rb +37 -0
  100. data/lib/railroader/processors/lib/call_conversion_helper.rb +90 -0
  101. data/lib/railroader/processors/lib/find_all_calls.rb +224 -0
  102. data/lib/railroader/processors/lib/find_call.rb +183 -0
  103. data/lib/railroader/processors/lib/find_return_value.rb +166 -0
  104. data/lib/railroader/processors/lib/module_helper.rb +111 -0
  105. data/lib/railroader/processors/lib/processor_helper.rb +88 -0
  106. data/lib/railroader/processors/lib/rails2_config_processor.rb +145 -0
  107. data/lib/railroader/processors/lib/rails2_route_processor.rb +313 -0
  108. data/lib/railroader/processors/lib/rails3_config_processor.rb +132 -0
  109. data/lib/railroader/processors/lib/rails3_route_processor.rb +308 -0
  110. data/lib/railroader/processors/lib/render_helper.rb +181 -0
  111. data/lib/railroader/processors/lib/render_path.rb +107 -0
  112. data/lib/railroader/processors/lib/route_helper.rb +68 -0
  113. data/lib/railroader/processors/lib/safe_call_helper.rb +16 -0
  114. data/lib/railroader/processors/library_processor.rb +74 -0
  115. data/lib/railroader/processors/model_processor.rb +91 -0
  116. data/lib/railroader/processors/output_processor.rb +144 -0
  117. data/lib/railroader/processors/route_processor.rb +17 -0
  118. data/lib/railroader/processors/slim_template_processor.rb +111 -0
  119. data/lib/railroader/processors/template_alias_processor.rb +118 -0
  120. data/lib/railroader/processors/template_processor.rb +85 -0
  121. data/lib/railroader/report/config/remediation.yml +71 -0
  122. data/lib/railroader/report/ignore/config.rb +153 -0
  123. data/lib/railroader/report/ignore/interactive.rb +362 -0
  124. data/lib/railroader/report/pager.rb +112 -0
  125. data/lib/railroader/report/renderer.rb +24 -0
  126. data/lib/railroader/report/report_base.rb +292 -0
  127. data/lib/railroader/report/report_codeclimate.rb +79 -0
  128. data/lib/railroader/report/report_csv.rb +55 -0
  129. data/lib/railroader/report/report_hash.rb +23 -0
  130. data/lib/railroader/report/report_html.rb +216 -0
  131. data/lib/railroader/report/report_json.rb +45 -0
  132. data/lib/railroader/report/report_markdown.rb +107 -0
  133. data/lib/railroader/report/report_table.rb +117 -0
  134. data/lib/railroader/report/report_tabs.rb +17 -0
  135. data/lib/railroader/report/report_text.rb +198 -0
  136. data/lib/railroader/report/templates/controller_overview.html.erb +22 -0
  137. data/lib/railroader/report/templates/controller_warnings.html.erb +21 -0
  138. data/lib/railroader/report/templates/error_overview.html.erb +29 -0
  139. data/lib/railroader/report/templates/header.html.erb +58 -0
  140. data/lib/railroader/report/templates/ignored_warnings.html.erb +25 -0
  141. data/lib/railroader/report/templates/model_warnings.html.erb +21 -0
  142. data/lib/railroader/report/templates/overview.html.erb +38 -0
  143. data/lib/railroader/report/templates/security_warnings.html.erb +23 -0
  144. data/lib/railroader/report/templates/template_overview.html.erb +21 -0
  145. data/lib/railroader/report/templates/view_warnings.html.erb +34 -0
  146. data/lib/railroader/report/templates/warning_overview.html.erb +17 -0
  147. data/lib/railroader/report.rb +88 -0
  148. data/lib/railroader/rescanner.rb +483 -0
  149. data/lib/railroader/scanner.rb +321 -0
  150. data/lib/railroader/tracker/collection.rb +93 -0
  151. data/lib/railroader/tracker/config.rb +154 -0
  152. data/lib/railroader/tracker/constants.rb +171 -0
  153. data/lib/railroader/tracker/controller.rb +161 -0
  154. data/lib/railroader/tracker/library.rb +17 -0
  155. data/lib/railroader/tracker/model.rb +90 -0
  156. data/lib/railroader/tracker/template.rb +33 -0
  157. data/lib/railroader/tracker.rb +362 -0
  158. data/lib/railroader/util.rb +503 -0
  159. data/lib/railroader/version.rb +3 -0
  160. data/lib/railroader/warning.rb +294 -0
  161. data/lib/railroader/warning_codes.rb +117 -0
  162. data/lib/railroader.rb +544 -0
  163. data/lib/ruby_parser/bm_sexp.rb +626 -0
  164. data/lib/ruby_parser/bm_sexp_processor.rb +116 -0
  165. metadata +386 -0
@@ -0,0 +1,321 @@
1
+ begin
2
+ Railroader.load_railroader_dependency 'ruby_parser'
3
+ require 'ruby_parser/bm_sexp.rb'
4
+ require 'ruby_parser/bm_sexp_processor.rb'
5
+ require 'railroader/processor'
6
+ require 'railroader/app_tree'
7
+ require 'railroader/file_parser'
8
+ require 'railroader/parsers/template_parser'
9
+ rescue LoadError => e
10
+ $stderr.puts e.message
11
+ $stderr.puts "Please install the appropriate dependency."
12
+ exit(-1)
13
+ end
14
+
15
+ #Scans the Rails application.
16
+ class Railroader::Scanner
17
+ attr_reader :options
18
+ RUBY_1_9 = RUBY_VERSION >= "1.9.0"
19
+
20
+ #Pass in path to the root of the Rails application
21
+ def initialize options, processor = nil
22
+ @options = options
23
+ @app_tree = Railroader::AppTree.from_options(options)
24
+
25
+ if (!@app_tree.root || !@app_tree.exists?("app")) && !options[:force_scan]
26
+ raise Railroader::NoApplication, "Please supply the path to a Rails application (looking in #{@app_tree.root})."
27
+ end
28
+
29
+ @processor = processor || Railroader::Processor.new(@app_tree, options)
30
+ end
31
+
32
+ #Returns the Tracker generated from the scan
33
+ def tracker
34
+ @processor.tracked_events
35
+ end
36
+
37
+ #Process everything in the Rails application
38
+ def process
39
+ Railroader.notify "Processing gems..."
40
+ process_gems
41
+ guess_rails_version
42
+ Railroader.notify "Processing configuration..."
43
+ process_config
44
+ Railroader.notify "Parsing files..."
45
+ parse_files
46
+ Railroader.notify "Processing initializers..."
47
+ process_initializers
48
+ Railroader.notify "Processing libs..."
49
+ process_libs
50
+ Railroader.notify "Processing routes... "
51
+ process_routes
52
+ Railroader.notify "Processing templates... "
53
+ process_templates
54
+ Railroader.notify "Processing data flow in templates..."
55
+ process_template_data_flows
56
+ Railroader.notify "Processing models... "
57
+ process_models
58
+ Railroader.notify "Processing controllers... "
59
+ process_controllers
60
+ Railroader.notify "Processing data flow in controllers..."
61
+ process_controller_data_flows
62
+ Railroader.notify "Indexing call sites... "
63
+ index_call_sites
64
+ tracker
65
+ end
66
+
67
+ def parse_files
68
+ fp = Railroader::FileParser.new tracker, @app_tree
69
+
70
+ files = {
71
+ :initializers => @app_tree.initializer_paths,
72
+ :controllers => @app_tree.controller_paths,
73
+ :models => @app_tree.model_paths
74
+ }
75
+
76
+ unless options[:skip_libs]
77
+ files[:libs] = @app_tree.lib_paths
78
+ end
79
+
80
+ files.each do |name, paths|
81
+ fp.parse_files paths, name
82
+ end
83
+
84
+ template_parser = Railroader::TemplateParser.new(tracker, fp)
85
+
86
+ fp.read_files(@app_tree.template_paths, :templates) do |path, contents|
87
+ template_parser.parse_template path, contents
88
+ end
89
+
90
+ @file_list = fp.file_list
91
+ end
92
+
93
+ #Process config/environment.rb and config/gems.rb
94
+ #
95
+ #Stores parsed information in tracker.config
96
+ def process_config
97
+ if options[:rails3] or options[:rails4] or options[:rails5]
98
+ process_config_file "application.rb"
99
+ process_config_file "environments/production.rb"
100
+ else
101
+ process_config_file "environment.rb"
102
+ process_config_file "gems.rb"
103
+ end
104
+
105
+ if @app_tree.exists?("vendor/plugins/rails_xss") or
106
+ options[:rails3] or options[:escape_html]
107
+
108
+ tracker.config.escape_html = true
109
+ Railroader.notify "[Notice] Escaping HTML by default"
110
+ end
111
+
112
+ if @app_tree.exists? ".ruby-version"
113
+ tracker.config.set_ruby_version @app_tree.read ".ruby-version"
114
+ end
115
+ end
116
+
117
+ def process_config_file file
118
+ path = "config/#{file}"
119
+
120
+ if @app_tree.exists?(path)
121
+ @processor.process_config(parse_ruby(@app_tree.read(path)), path)
122
+ end
123
+
124
+ rescue => e
125
+ Railroader.notify "[Notice] Error while processing #{path}"
126
+ tracker.error e.exception(e.message + "\nwhile processing #{path}"), e.backtrace
127
+ end
128
+
129
+ private :process_config_file
130
+
131
+ #Process Gemfile
132
+ def process_gems
133
+ gem_files = {}
134
+ if @app_tree.exists? "Gemfile"
135
+ gem_files[:gemfile] = { :src => parse_ruby(@app_tree.read("Gemfile")), :file => "Gemfile" }
136
+ elsif @app_tree.exists? "gems.rb"
137
+ gem_files[:gemfile] = { :src => parse_ruby(@app_tree.read("gems.rb")), :file => "gems.rb" }
138
+ end
139
+
140
+ if @app_tree.exists? "Gemfile.lock"
141
+ gem_files[:gemlock] = { :src => @app_tree.read("Gemfile.lock"), :file => "Gemfile.lock" }
142
+ elsif @app_tree.exists? "gems.locked"
143
+ gem_files[:gemlock] = { :src => @app_tree.read("gems.locked"), :file => "gems.locked" }
144
+ end
145
+
146
+ if gem_files[:gemfile] or gem_files[:gemlock]
147
+ @processor.process_gems gem_files
148
+ end
149
+ rescue => e
150
+ Railroader.notify "[Notice] Error while processing Gemfile."
151
+ tracker.error e.exception(e.message + "\nWhile processing Gemfile"), e.backtrace
152
+ end
153
+
154
+ #Set :rails3/:rails4 option if version was not determined from Gemfile
155
+ def guess_rails_version
156
+ unless tracker.options[:rails3] or tracker.options[:rails4]
157
+ if @app_tree.exists?("script/rails")
158
+ tracker.options[:rails3] = true
159
+ Railroader.notify "[Notice] Detected Rails 3 application"
160
+ elsif @app_tree.exists?("app/channels")
161
+ tracker.options[:rails3] = true
162
+ tracker.options[:rails4] = true
163
+ tracker.options[:rails5] = true
164
+ Railroader.notify "[Notice] Detected Rails 5 application"
165
+ elsif not @app_tree.exists?("script")
166
+ tracker.options[:rails3] = true
167
+ tracker.options[:rails4] = true
168
+ Railroader.notify "[Notice] Detected Rails 4 application"
169
+ end
170
+ end
171
+ end
172
+
173
+ #Process all the .rb files in config/initializers/
174
+ #
175
+ #Adds parsed information to tracker.initializers
176
+ def process_initializers
177
+ track_progress @file_list[:initializers] do |init|
178
+ Railroader.debug "Processing #{init[:path]}"
179
+ process_initializer init
180
+ end
181
+ end
182
+
183
+ #Process an initializer
184
+ def process_initializer init
185
+ @processor.process_initializer(init.path, init.ast)
186
+ end
187
+
188
+ #Process all .rb in lib/
189
+ #
190
+ #Adds parsed information to tracker.libs.
191
+ def process_libs
192
+ if options[:skip_libs]
193
+ Railroader.notify '[Skipping]'
194
+ return
195
+ end
196
+
197
+ track_progress @file_list[:libs] do |lib|
198
+ Railroader.debug "Processing #{lib.path}"
199
+ process_lib lib
200
+ end
201
+ end
202
+
203
+ #Process a library
204
+ def process_lib lib
205
+ @processor.process_lib lib.ast, lib.path
206
+ end
207
+
208
+ #Process config/routes.rb
209
+ #
210
+ #Adds parsed information to tracker.routes
211
+ def process_routes
212
+ if @app_tree.exists?("config/routes.rb")
213
+ begin
214
+ @processor.process_routes parse_ruby(@app_tree.read("config/routes.rb"))
215
+ rescue => e
216
+ tracker.error e.exception(e.message + "\nWhile processing routes.rb"), e.backtrace
217
+ Railroader.notify "[Notice] Error while processing routes - assuming all public controller methods are actions."
218
+ options[:assume_all_routes] = true
219
+ end
220
+ else
221
+ Railroader.notify "[Notice] No route information found"
222
+ end
223
+ end
224
+
225
+ #Process all .rb files in controllers/
226
+ #
227
+ #Adds processed controllers to tracker.controllers
228
+ def process_controllers
229
+ track_progress @file_list[:controllers] do |controller|
230
+ Railroader.debug "Processing #{controller.path}"
231
+ process_controller controller
232
+ end
233
+ end
234
+
235
+ def process_controller_data_flows
236
+ controllers = tracker.controllers.sort_by { |name, _| name.to_s }
237
+
238
+ track_progress controllers, "controllers" do |name, controller|
239
+ Railroader.debug "Processing #{name}"
240
+ controller.src.each do |file, src|
241
+ @processor.process_controller_alias name, src, nil, file
242
+ end
243
+ end
244
+
245
+ #No longer need these processed filter methods
246
+ tracker.filter_cache.clear
247
+ end
248
+
249
+ def process_controller astfile
250
+ begin
251
+ @processor.process_controller(astfile.ast, astfile.path)
252
+ rescue => e
253
+ tracker.error e.exception(e.message + "\nWhile processing #{astfile.path}"), e.backtrace
254
+ end
255
+ end
256
+
257
+ #Process all views and partials in views/
258
+ #
259
+ #Adds processed views to tracker.views
260
+ def process_templates
261
+ templates = @file_list[:templates].sort_by { |t| t[:path] }
262
+
263
+ track_progress templates, "templates" do |template|
264
+ Railroader.debug "Processing #{template[:path]}"
265
+ process_template template
266
+ end
267
+ end
268
+
269
+ def process_template template
270
+ @processor.process_template(template.name, template.ast, template.type, nil, template.path)
271
+ end
272
+
273
+ def process_template_data_flows
274
+ templates = tracker.templates.sort_by { |name, _| name.to_s }
275
+
276
+ track_progress templates, "templates" do |name, template|
277
+ Railroader.debug "Processing #{name}"
278
+ @processor.process_template_alias template
279
+ end
280
+ end
281
+
282
+ #Process all the .rb files in models/
283
+ #
284
+ #Adds the processed models to tracker.models
285
+ def process_models
286
+ track_progress @file_list[:models] do |model|
287
+ Railroader.debug "Processing #{model[:path]}"
288
+ process_model model[:path], model[:ast]
289
+ end
290
+ end
291
+
292
+ def process_model path, ast
293
+ @processor.process_model(ast, path)
294
+ end
295
+
296
+ def track_progress list, type = "files"
297
+ total = list.length
298
+ current = 0
299
+ list.each do |item|
300
+ report_progress current, total, type
301
+ current += 1
302
+ yield item
303
+ end
304
+ end
305
+
306
+ def report_progress(current, total, type = "files")
307
+ return unless @options[:report_progress]
308
+ $stderr.print " #{current}/#{total} #{type} processed\r"
309
+ end
310
+
311
+ def index_call_sites
312
+ tracker.index_call_sites
313
+ end
314
+
315
+ def parse_ruby input
316
+ RubyParser.new.parse input
317
+ end
318
+ end
319
+
320
+ # This is to allow operation without loading the Haml library
321
+ module Haml; class Error < StandardError; end; end
@@ -0,0 +1,93 @@
1
+ require 'railroader/util'
2
+
3
+ module Railroader
4
+ class Collection
5
+ include Railroader::Util
6
+
7
+ attr_reader :collection, :files, :includes, :name, :options, :parent, :src, :tracker
8
+
9
+ def initialize name, parent, file_name, src, tracker
10
+ @name = name
11
+ @parent = parent
12
+ @file_name = file_name
13
+ @files = [ file_name ]
14
+ @src = { file_name => src }
15
+ @includes = []
16
+ @methods = { :public => {}, :private => {}, :protected => {} }
17
+ @options = {}
18
+ @tracker = tracker
19
+ end
20
+
21
+ def ancestor? parent, seen={}
22
+ seen[self.name] = true
23
+
24
+ if self.parent == parent or seen[self.parent]
25
+ true
26
+ elsif parent_model = collection[self.parent]
27
+ parent_model.ancestor? parent, seen
28
+ else
29
+ false
30
+ end
31
+ end
32
+
33
+ def add_file file_name, src
34
+ @files << file_name unless @files.include? file_name
35
+ @src[file_name] = src
36
+ end
37
+
38
+ def add_include class_name
39
+ @includes << class_name
40
+ end
41
+
42
+ def add_option name, exp
43
+ @options[name] ||= []
44
+ @options[name] << exp
45
+ end
46
+
47
+ def add_method visibility, name, src, file_name
48
+ if src.node_type == :defs
49
+ name = :"#{src[1]}.#{name}"
50
+ end
51
+
52
+ @methods[visibility][name] = { :src => src, :file => file_name }
53
+ end
54
+
55
+ def each_method
56
+ @methods.each do |_vis, meths|
57
+ meths.each do |name, info|
58
+ yield name, info
59
+ end
60
+ end
61
+ end
62
+
63
+ def get_method name
64
+ each_method do |n, info|
65
+ if n == name
66
+ return info
67
+ end
68
+ end
69
+
70
+ nil
71
+ end
72
+
73
+ def file
74
+ @files.first
75
+ end
76
+
77
+ def top_line
78
+ if sexp? @src[file]
79
+ @src[file].line
80
+ else
81
+ @src.each_value do |source|
82
+ if sexp? source
83
+ return source.line
84
+ end
85
+ end
86
+ end
87
+ end
88
+
89
+ def methods_public
90
+ @methods[:public]
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,154 @@
1
+ require 'railroader/util'
2
+
3
+ module Railroader
4
+ class Config
5
+ include Util
6
+
7
+ attr_reader :rails, :tracker
8
+ attr_accessor :rails_version, :ruby_version
9
+ attr_writer :erubis, :escape_html
10
+ attr_reader :gems
11
+
12
+ def initialize tracker
13
+ @tracker = tracker
14
+ @rails = {}
15
+ @gems = {}
16
+ @settings = {}
17
+ @escape_html = nil
18
+ @erubis = nil
19
+ @ruby_version = ""
20
+ end
21
+
22
+ def allow_forgery_protection?
23
+ @rails[:action_controller] and
24
+ @rails[:action_controller][:allow_forgery_protection] == Sexp.new(:false)
25
+ end
26
+
27
+ def default_protect_from_forgery?
28
+ if version_between? "5.2.0", "9.9.9"
29
+ if @rails[:action_controller] and
30
+ @rails[:action_controller][:default_protect_from_forgery] == Sexp.new(:false)
31
+
32
+ return false
33
+ else
34
+ return true
35
+ end
36
+ end
37
+
38
+ false
39
+ end
40
+
41
+ def erubis?
42
+ @erubis
43
+ end
44
+
45
+ def escape_html?
46
+ @escape_html
47
+ end
48
+
49
+ def escape_html_entities_in_json?
50
+ #TODO add version-specific information here
51
+ @rails[:active_support] and
52
+ true? @rails[:active_support][:escape_html_entities_in_json]
53
+ end
54
+
55
+ def whitelist_attributes?
56
+ @rails[:active_record] and
57
+ @rails[:active_record][:whitelist_attributes] == Sexp.new(:true)
58
+ end
59
+
60
+ def gem_version name
61
+ @gems[name] and @gems[name][:version]
62
+ end
63
+
64
+ def add_gem name, version, file, line
65
+ name = name.to_sym
66
+ @gems[name] = {
67
+ :version => version,
68
+ :file => file,
69
+ :line => line
70
+ }
71
+ end
72
+
73
+ def has_gem? name
74
+ !!@gems[name]
75
+ end
76
+
77
+ def get_gem name
78
+ @gems[name]
79
+ end
80
+
81
+ def set_rails_version
82
+ # Ignore ~>, etc. when using values from Gemfile
83
+ version = gem_version(:rails) || gem_version(:railties)
84
+ if version and version.match(/(\d+\.\d+\.\d+.*)/)
85
+ @rails_version = $1
86
+
87
+ if tracker.options[:rails3].nil? and tracker.options[:rails4].nil?
88
+ if @rails_version.start_with? "3"
89
+ tracker.options[:rails3] = true
90
+ Railroader.notify "[Notice] Detected Rails 3 application"
91
+ elsif @rails_version.start_with? "4"
92
+ tracker.options[:rails3] = true
93
+ tracker.options[:rails4] = true
94
+ Railroader.notify "[Notice] Detected Rails 4 application"
95
+ elsif @rails_version.start_with? "5"
96
+ tracker.options[:rails3] = true
97
+ tracker.options[:rails4] = true
98
+ tracker.options[:rails5] = true
99
+ Railroader.notify "[Notice] Detected Rails 5 application"
100
+ end
101
+ end
102
+ end
103
+
104
+ if get_gem :rails_xss
105
+ @escape_html = true
106
+ Railroader.notify "[Notice] Escaping HTML by default"
107
+ end
108
+ end
109
+
110
+ def set_ruby_version version
111
+ return unless version.is_a? String
112
+
113
+ if version =~ /(\d+\.\d+\.\d+)/
114
+ self.ruby_version = $1
115
+ end
116
+ end
117
+
118
+ #Returns true if low_version <= RAILS_VERSION <= high_version
119
+ #
120
+ #If the Rails version is unknown, returns false.
121
+ def version_between? low_version, high_version, current_version = nil
122
+ current_version ||= rails_version
123
+ return false unless current_version
124
+
125
+ version = current_version.split(".").map!(&:to_i)
126
+ low_version = low_version.split(".").map!(&:to_i)
127
+ high_version = high_version.split(".").map!(&:to_i)
128
+
129
+ version.each_with_index do |v, i|
130
+ if v < low_version.fetch(i, 0)
131
+ return false
132
+ elsif v > low_version.fetch(i, 0)
133
+ break
134
+ end
135
+ end
136
+
137
+ version.each_with_index do |v, i|
138
+ if v > high_version.fetch(i, 0)
139
+ return false
140
+ elsif v < high_version.fetch(i, 0)
141
+ break
142
+ end
143
+ end
144
+
145
+ true
146
+ end
147
+
148
+ def session_settings
149
+ @rails[:action_controller] &&
150
+ @rails[:action_controller][:session]
151
+ end
152
+
153
+ end
154
+ end