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.
- checksums.yaml +7 -0
- data/CHANGES.md +1091 -0
- data/FEATURES +16 -0
- data/README.md +174 -0
- data/bin/railroader +8 -0
- data/lib/railroader/app_tree.rb +191 -0
- data/lib/railroader/call_index.rb +219 -0
- data/lib/railroader/checks/base_check.rb +505 -0
- data/lib/railroader/checks/check_basic_auth.rb +88 -0
- data/lib/railroader/checks/check_basic_auth_timing_attack.rb +33 -0
- data/lib/railroader/checks/check_content_tag.rb +200 -0
- data/lib/railroader/checks/check_create_with.rb +74 -0
- data/lib/railroader/checks/check_cross_site_scripting.rb +381 -0
- data/lib/railroader/checks/check_default_routes.rb +86 -0
- data/lib/railroader/checks/check_deserialize.rb +56 -0
- data/lib/railroader/checks/check_detailed_exceptions.rb +55 -0
- data/lib/railroader/checks/check_digest_dos.rb +38 -0
- data/lib/railroader/checks/check_divide_by_zero.rb +42 -0
- data/lib/railroader/checks/check_dynamic_finders.rb +48 -0
- data/lib/railroader/checks/check_escape_function.rb +21 -0
- data/lib/railroader/checks/check_evaluation.rb +35 -0
- data/lib/railroader/checks/check_execute.rb +189 -0
- data/lib/railroader/checks/check_file_access.rb +71 -0
- data/lib/railroader/checks/check_file_disclosure.rb +35 -0
- data/lib/railroader/checks/check_filter_skipping.rb +31 -0
- data/lib/railroader/checks/check_forgery_setting.rb +81 -0
- data/lib/railroader/checks/check_header_dos.rb +31 -0
- data/lib/railroader/checks/check_i18n_xss.rb +48 -0
- data/lib/railroader/checks/check_jruby_xml.rb +36 -0
- data/lib/railroader/checks/check_json_encoding.rb +47 -0
- data/lib/railroader/checks/check_json_parsing.rb +107 -0
- data/lib/railroader/checks/check_link_to.rb +132 -0
- data/lib/railroader/checks/check_link_to_href.rb +146 -0
- data/lib/railroader/checks/check_mail_to.rb +49 -0
- data/lib/railroader/checks/check_mass_assignment.rb +196 -0
- data/lib/railroader/checks/check_mime_type_dos.rb +39 -0
- data/lib/railroader/checks/check_model_attr_accessible.rb +55 -0
- data/lib/railroader/checks/check_model_attributes.rb +119 -0
- data/lib/railroader/checks/check_model_serialize.rb +67 -0
- data/lib/railroader/checks/check_nested_attributes.rb +38 -0
- data/lib/railroader/checks/check_nested_attributes_bypass.rb +58 -0
- data/lib/railroader/checks/check_number_to_currency.rb +74 -0
- data/lib/railroader/checks/check_permit_attributes.rb +43 -0
- data/lib/railroader/checks/check_quote_table_name.rb +40 -0
- data/lib/railroader/checks/check_redirect.rb +256 -0
- data/lib/railroader/checks/check_regex_dos.rb +68 -0
- data/lib/railroader/checks/check_render.rb +97 -0
- data/lib/railroader/checks/check_render_dos.rb +37 -0
- data/lib/railroader/checks/check_render_inline.rb +53 -0
- data/lib/railroader/checks/check_response_splitting.rb +21 -0
- data/lib/railroader/checks/check_route_dos.rb +42 -0
- data/lib/railroader/checks/check_safe_buffer_manipulation.rb +31 -0
- data/lib/railroader/checks/check_sanitize_methods.rb +112 -0
- data/lib/railroader/checks/check_secrets.rb +40 -0
- data/lib/railroader/checks/check_select_tag.rb +59 -0
- data/lib/railroader/checks/check_select_vulnerability.rb +60 -0
- data/lib/railroader/checks/check_send.rb +47 -0
- data/lib/railroader/checks/check_send_file.rb +19 -0
- data/lib/railroader/checks/check_session_manipulation.rb +35 -0
- data/lib/railroader/checks/check_session_settings.rb +176 -0
- data/lib/railroader/checks/check_simple_format.rb +58 -0
- data/lib/railroader/checks/check_single_quotes.rb +101 -0
- data/lib/railroader/checks/check_skip_before_filter.rb +60 -0
- data/lib/railroader/checks/check_sql.rb +700 -0
- data/lib/railroader/checks/check_sql_cves.rb +106 -0
- data/lib/railroader/checks/check_ssl_verify.rb +48 -0
- data/lib/railroader/checks/check_strip_tags.rb +89 -0
- data/lib/railroader/checks/check_symbol_dos.rb +71 -0
- data/lib/railroader/checks/check_symbol_dos_cve.rb +30 -0
- data/lib/railroader/checks/check_translate_bug.rb +45 -0
- data/lib/railroader/checks/check_unsafe_reflection.rb +50 -0
- data/lib/railroader/checks/check_unscoped_find.rb +57 -0
- data/lib/railroader/checks/check_validation_regex.rb +116 -0
- data/lib/railroader/checks/check_weak_hash.rb +148 -0
- data/lib/railroader/checks/check_without_protection.rb +80 -0
- data/lib/railroader/checks/check_xml_dos.rb +45 -0
- data/lib/railroader/checks/check_yaml_parsing.rb +121 -0
- data/lib/railroader/checks.rb +209 -0
- data/lib/railroader/codeclimate/engine_configuration.rb +97 -0
- data/lib/railroader/commandline.rb +179 -0
- data/lib/railroader/differ.rb +66 -0
- data/lib/railroader/file_parser.rb +54 -0
- data/lib/railroader/format/style.css +133 -0
- data/lib/railroader/options.rb +339 -0
- data/lib/railroader/parsers/rails2_erubis.rb +6 -0
- data/lib/railroader/parsers/rails2_xss_plugin_erubis.rb +48 -0
- data/lib/railroader/parsers/rails3_erubis.rb +81 -0
- data/lib/railroader/parsers/template_parser.rb +108 -0
- data/lib/railroader/processor.rb +102 -0
- data/lib/railroader/processors/alias_processor.rb +1229 -0
- data/lib/railroader/processors/base_processor.rb +295 -0
- data/lib/railroader/processors/config_processor.rb +14 -0
- data/lib/railroader/processors/controller_alias_processor.rb +278 -0
- data/lib/railroader/processors/controller_processor.rb +249 -0
- data/lib/railroader/processors/erb_template_processor.rb +77 -0
- data/lib/railroader/processors/erubis_template_processor.rb +92 -0
- data/lib/railroader/processors/gem_processor.rb +64 -0
- data/lib/railroader/processors/haml_template_processor.rb +191 -0
- data/lib/railroader/processors/lib/basic_processor.rb +37 -0
- data/lib/railroader/processors/lib/call_conversion_helper.rb +90 -0
- data/lib/railroader/processors/lib/find_all_calls.rb +224 -0
- data/lib/railroader/processors/lib/find_call.rb +183 -0
- data/lib/railroader/processors/lib/find_return_value.rb +166 -0
- data/lib/railroader/processors/lib/module_helper.rb +111 -0
- data/lib/railroader/processors/lib/processor_helper.rb +88 -0
- data/lib/railroader/processors/lib/rails2_config_processor.rb +145 -0
- data/lib/railroader/processors/lib/rails2_route_processor.rb +313 -0
- data/lib/railroader/processors/lib/rails3_config_processor.rb +132 -0
- data/lib/railroader/processors/lib/rails3_route_processor.rb +308 -0
- data/lib/railroader/processors/lib/render_helper.rb +181 -0
- data/lib/railroader/processors/lib/render_path.rb +107 -0
- data/lib/railroader/processors/lib/route_helper.rb +68 -0
- data/lib/railroader/processors/lib/safe_call_helper.rb +16 -0
- data/lib/railroader/processors/library_processor.rb +74 -0
- data/lib/railroader/processors/model_processor.rb +91 -0
- data/lib/railroader/processors/output_processor.rb +144 -0
- data/lib/railroader/processors/route_processor.rb +17 -0
- data/lib/railroader/processors/slim_template_processor.rb +111 -0
- data/lib/railroader/processors/template_alias_processor.rb +118 -0
- data/lib/railroader/processors/template_processor.rb +85 -0
- data/lib/railroader/report/config/remediation.yml +71 -0
- data/lib/railroader/report/ignore/config.rb +153 -0
- data/lib/railroader/report/ignore/interactive.rb +362 -0
- data/lib/railroader/report/pager.rb +112 -0
- data/lib/railroader/report/renderer.rb +24 -0
- data/lib/railroader/report/report_base.rb +292 -0
- data/lib/railroader/report/report_codeclimate.rb +79 -0
- data/lib/railroader/report/report_csv.rb +55 -0
- data/lib/railroader/report/report_hash.rb +23 -0
- data/lib/railroader/report/report_html.rb +216 -0
- data/lib/railroader/report/report_json.rb +45 -0
- data/lib/railroader/report/report_markdown.rb +107 -0
- data/lib/railroader/report/report_table.rb +117 -0
- data/lib/railroader/report/report_tabs.rb +17 -0
- data/lib/railroader/report/report_text.rb +198 -0
- data/lib/railroader/report/templates/controller_overview.html.erb +22 -0
- data/lib/railroader/report/templates/controller_warnings.html.erb +21 -0
- data/lib/railroader/report/templates/error_overview.html.erb +29 -0
- data/lib/railroader/report/templates/header.html.erb +58 -0
- data/lib/railroader/report/templates/ignored_warnings.html.erb +25 -0
- data/lib/railroader/report/templates/model_warnings.html.erb +21 -0
- data/lib/railroader/report/templates/overview.html.erb +38 -0
- data/lib/railroader/report/templates/security_warnings.html.erb +23 -0
- data/lib/railroader/report/templates/template_overview.html.erb +21 -0
- data/lib/railroader/report/templates/view_warnings.html.erb +34 -0
- data/lib/railroader/report/templates/warning_overview.html.erb +17 -0
- data/lib/railroader/report.rb +88 -0
- data/lib/railroader/rescanner.rb +483 -0
- data/lib/railroader/scanner.rb +321 -0
- data/lib/railroader/tracker/collection.rb +93 -0
- data/lib/railroader/tracker/config.rb +154 -0
- data/lib/railroader/tracker/constants.rb +171 -0
- data/lib/railroader/tracker/controller.rb +161 -0
- data/lib/railroader/tracker/library.rb +17 -0
- data/lib/railroader/tracker/model.rb +90 -0
- data/lib/railroader/tracker/template.rb +33 -0
- data/lib/railroader/tracker.rb +362 -0
- data/lib/railroader/util.rb +503 -0
- data/lib/railroader/version.rb +3 -0
- data/lib/railroader/warning.rb +294 -0
- data/lib/railroader/warning_codes.rb +117 -0
- data/lib/railroader.rb +544 -0
- data/lib/ruby_parser/bm_sexp.rb +626 -0
- data/lib/ruby_parser/bm_sexp_processor.rb +116 -0
- 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
|