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,295 @@
|
|
|
1
|
+
require 'railroader/processors/lib/processor_helper'
|
|
2
|
+
require 'railroader/processors/lib/safe_call_helper'
|
|
3
|
+
require 'railroader/util'
|
|
4
|
+
|
|
5
|
+
#Base processor for most processors.
|
|
6
|
+
class Railroader::BaseProcessor < Railroader::SexpProcessor
|
|
7
|
+
include Railroader::ProcessorHelper
|
|
8
|
+
include Railroader::SafeCallHelper
|
|
9
|
+
include Railroader::Util
|
|
10
|
+
|
|
11
|
+
IGNORE = Sexp.new :ignore
|
|
12
|
+
|
|
13
|
+
#Return a new Processor.
|
|
14
|
+
def initialize tracker
|
|
15
|
+
super()
|
|
16
|
+
@last = nil
|
|
17
|
+
@tracker = tracker
|
|
18
|
+
@current_template = @current_module = @current_class = @current_method = @file_name = nil
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def process_file exp, file_name
|
|
22
|
+
@file_name = file_name
|
|
23
|
+
process exp
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def ignore
|
|
27
|
+
IGNORE
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
#Process a new scope. Removes expressions that are set to nil.
|
|
31
|
+
def process_scope exp
|
|
32
|
+
#NOPE?
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
#Default processing.
|
|
36
|
+
def process_default exp
|
|
37
|
+
exp = exp.dup
|
|
38
|
+
|
|
39
|
+
exp.each_with_index do |e, i|
|
|
40
|
+
exp[i] = process e if sexp? e and not e.empty?
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
exp
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
#Process an if statement.
|
|
47
|
+
def process_if exp
|
|
48
|
+
exp = exp.dup
|
|
49
|
+
condition = exp[1] = process exp.condition
|
|
50
|
+
|
|
51
|
+
if true? condition
|
|
52
|
+
exp[2] = process exp.then_clause if exp.then_clause
|
|
53
|
+
exp[3] = nil
|
|
54
|
+
elsif false? condition
|
|
55
|
+
exp[2] = nil
|
|
56
|
+
exp[3] = process exp.else_clause if exp.else_clause
|
|
57
|
+
else
|
|
58
|
+
exp[2] = process exp.then_clause if exp.then_clause
|
|
59
|
+
exp[3] = process exp.else_clause if exp.else_clause
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
exp
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
#Processes calls with blocks.
|
|
66
|
+
#
|
|
67
|
+
#s(:iter, CALL, {:lasgn|:masgn}, BLOCK)
|
|
68
|
+
def process_iter exp
|
|
69
|
+
exp = exp.dup
|
|
70
|
+
call = process exp.block_call
|
|
71
|
+
#deal with assignments somehow
|
|
72
|
+
if exp.block
|
|
73
|
+
block = process exp.block
|
|
74
|
+
block = nil if block.empty?
|
|
75
|
+
else
|
|
76
|
+
block = nil
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
call = Sexp.new(:iter, call, exp.block_args, block).compact
|
|
80
|
+
call.line(exp.line)
|
|
81
|
+
call
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
#String with interpolation.
|
|
85
|
+
def process_dstr exp
|
|
86
|
+
exp = exp.dup
|
|
87
|
+
exp.shift
|
|
88
|
+
exp.map! do |e|
|
|
89
|
+
if e.is_a? String
|
|
90
|
+
e
|
|
91
|
+
else
|
|
92
|
+
res = process e
|
|
93
|
+
if res.empty?
|
|
94
|
+
nil
|
|
95
|
+
else
|
|
96
|
+
res
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end.compact!
|
|
100
|
+
|
|
101
|
+
exp.unshift :dstr
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
#Processes a block. Changes Sexp node type to :rlist
|
|
105
|
+
def process_block exp
|
|
106
|
+
exp = exp.dup
|
|
107
|
+
exp.shift
|
|
108
|
+
|
|
109
|
+
exp.map! do |e|
|
|
110
|
+
process e
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
exp.unshift :rlist
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
#Processes the inside of an interpolated String.
|
|
117
|
+
def process_evstr exp
|
|
118
|
+
exp = exp.dup
|
|
119
|
+
if exp[1]
|
|
120
|
+
exp[1] = process exp[1]
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
exp
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
#Processes a hash
|
|
127
|
+
def process_hash exp
|
|
128
|
+
exp = exp.dup
|
|
129
|
+
exp.shift
|
|
130
|
+
exp.map! do |e|
|
|
131
|
+
if sexp? e
|
|
132
|
+
process e
|
|
133
|
+
else
|
|
134
|
+
e
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
exp.unshift :hash
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
#Processes the values in an argument list
|
|
142
|
+
def process_arglist exp
|
|
143
|
+
exp = exp.dup
|
|
144
|
+
exp.shift
|
|
145
|
+
exp.map! do |e|
|
|
146
|
+
process e
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
exp.unshift :arglist
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
#Processes a local assignment
|
|
153
|
+
def process_lasgn exp
|
|
154
|
+
exp = exp.dup
|
|
155
|
+
exp.rhs = process exp.rhs
|
|
156
|
+
exp
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
alias :process_iasgn :process_lasgn
|
|
160
|
+
|
|
161
|
+
#Processes an instance variable assignment
|
|
162
|
+
def process_iasgn exp
|
|
163
|
+
exp = exp.dup
|
|
164
|
+
exp.rhs = process exp.rhs
|
|
165
|
+
exp
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
#Processes an attribute assignment, which can be either x.y = 1 or x[:y] = 1
|
|
169
|
+
def process_attrasgn exp
|
|
170
|
+
exp = exp.dup
|
|
171
|
+
exp.target = process exp.target
|
|
172
|
+
exp.arglist = process exp.arglist
|
|
173
|
+
exp
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
#Ignore ignore Sexps
|
|
177
|
+
def process_ignore exp
|
|
178
|
+
exp
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
def process_cdecl exp
|
|
182
|
+
if @tracker
|
|
183
|
+
@tracker.add_constant exp.lhs,
|
|
184
|
+
exp.rhs,
|
|
185
|
+
:file => current_file_name,
|
|
186
|
+
:module => @current_module,
|
|
187
|
+
:class => @current_class,
|
|
188
|
+
:method => @current_method
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
exp
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
#Convenience method for `make_render exp, true`
|
|
195
|
+
def make_render_in_view exp
|
|
196
|
+
make_render exp, true
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
#Generates :render node from call to render.
|
|
200
|
+
def make_render exp, in_view = false
|
|
201
|
+
render_type, value, rest = find_render_type exp, in_view
|
|
202
|
+
rest = process rest
|
|
203
|
+
result = Sexp.new(:render, render_type, value, rest)
|
|
204
|
+
result.line(exp.line)
|
|
205
|
+
result
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
#Determines the type of a call to render.
|
|
209
|
+
#
|
|
210
|
+
#Possible types are:
|
|
211
|
+
#:action, :default, :file, :inline, :js, :json, :nothing, :partial,
|
|
212
|
+
#:template, :text, :update, :xml
|
|
213
|
+
#
|
|
214
|
+
#And also :layout for inside templates
|
|
215
|
+
def find_render_type call, in_view = false
|
|
216
|
+
rest = Sexp.new(:hash)
|
|
217
|
+
type = nil
|
|
218
|
+
value = nil
|
|
219
|
+
first_arg = call.first_arg
|
|
220
|
+
|
|
221
|
+
if call.second_arg.nil? and first_arg == Sexp.new(:lit, :update)
|
|
222
|
+
return :update, nil, Sexp.new(:arglist, *call.args[0..-2]) #TODO HUH?
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
#Look for render :action, ... or render "action", ...
|
|
226
|
+
if string? first_arg or symbol? first_arg
|
|
227
|
+
if @current_template and @tracker.options[:rails3]
|
|
228
|
+
type = :partial
|
|
229
|
+
value = first_arg
|
|
230
|
+
else
|
|
231
|
+
type = :action
|
|
232
|
+
value = first_arg
|
|
233
|
+
end
|
|
234
|
+
elsif first_arg.is_a? Symbol or first_arg.is_a? String
|
|
235
|
+
type = :action
|
|
236
|
+
value = Sexp.new(:lit, first_arg.to_sym)
|
|
237
|
+
elsif first_arg.nil?
|
|
238
|
+
type = :default
|
|
239
|
+
elsif not hash? first_arg
|
|
240
|
+
type = :action
|
|
241
|
+
value = first_arg
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
types_in_hash = Set[:action, :file, :inline, :js, :json, :nothing, :partial, :template, :text, :update, :xml]
|
|
245
|
+
|
|
246
|
+
#render :layout => "blah" means something else when in a template
|
|
247
|
+
if in_view
|
|
248
|
+
types_in_hash << :layout
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
last_arg = call.last_arg
|
|
252
|
+
|
|
253
|
+
#Look for "type" of render in options hash
|
|
254
|
+
#For example, render :file => "blah"
|
|
255
|
+
if hash? last_arg
|
|
256
|
+
hash_iterate(last_arg) do |key, val|
|
|
257
|
+
if symbol? key and types_in_hash.include? key.value
|
|
258
|
+
type = key.value
|
|
259
|
+
value = val
|
|
260
|
+
else
|
|
261
|
+
rest << key << val
|
|
262
|
+
end
|
|
263
|
+
end
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
type ||= :default
|
|
267
|
+
value ||= :default
|
|
268
|
+
|
|
269
|
+
if type == :inline and string? value and not hash_access(rest, :type)
|
|
270
|
+
value, rest = make_inline_render(value, rest)
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
return type, value, rest
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
def make_inline_render value, options
|
|
277
|
+
require 'railroader/parsers/template_parser'
|
|
278
|
+
|
|
279
|
+
class_or_module = (@current_class || @current_module)
|
|
280
|
+
|
|
281
|
+
class_or_module = if class_or_module.nil?
|
|
282
|
+
"Unknown"
|
|
283
|
+
else
|
|
284
|
+
class_or_module.name
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
template_name = "#@current_method/inline@#{value.line}:#{class_or_module}".to_sym
|
|
288
|
+
type, ast = Railroader::TemplateParser.parse_inline_erb(@tracker, value.value)
|
|
289
|
+
ast = ast.deep_clone(value.line)
|
|
290
|
+
@tracker.processor.process_template(template_name, ast, type, nil, @file_name)
|
|
291
|
+
@tracker.processor.process_template_alias(@tracker.templates[template_name])
|
|
292
|
+
|
|
293
|
+
return s(:lit, template_name), options
|
|
294
|
+
end
|
|
295
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
require 'railroader/processors/base_processor'
|
|
2
|
+
require 'railroader/processors/alias_processor'
|
|
3
|
+
require 'railroader/processors/lib/rails3_config_processor.rb'
|
|
4
|
+
require 'railroader/processors/lib/rails2_config_processor.rb'
|
|
5
|
+
|
|
6
|
+
class Railroader::ConfigProcessor
|
|
7
|
+
def self.new tracker
|
|
8
|
+
if tracker.options[:rails3]
|
|
9
|
+
Railroader::Rails3ConfigProcessor.new tracker
|
|
10
|
+
else
|
|
11
|
+
Railroader::Rails2ConfigProcessor.new tracker
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
require 'railroader/processors/alias_processor'
|
|
2
|
+
require 'railroader/processors/lib/render_helper'
|
|
3
|
+
require 'railroader/processors/lib/render_path'
|
|
4
|
+
require 'railroader/processors/lib/find_return_value'
|
|
5
|
+
|
|
6
|
+
#Processes aliasing in controllers, but includes following
|
|
7
|
+
#renders in routes and putting variables into templates
|
|
8
|
+
class Railroader::ControllerAliasProcessor < Railroader::AliasProcessor
|
|
9
|
+
include Railroader::RenderHelper
|
|
10
|
+
|
|
11
|
+
#If only_method is specified, only that method will be processed,
|
|
12
|
+
#other methods will be skipped.
|
|
13
|
+
#This is for rescanning just a single action.
|
|
14
|
+
def initialize app_tree, tracker, only_method = nil
|
|
15
|
+
super tracker
|
|
16
|
+
@app_tree = app_tree
|
|
17
|
+
@only_method = only_method
|
|
18
|
+
@rendered = false
|
|
19
|
+
@current_class = @current_module = @current_method = nil
|
|
20
|
+
@method_cache = {} #Cache method lookups
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def process_controller name, src, file_name
|
|
24
|
+
if not node_type? src, :class
|
|
25
|
+
Railroader.debug "#{name} is not a class, it's a #{src.node_type}"
|
|
26
|
+
return
|
|
27
|
+
else
|
|
28
|
+
@current_class = name
|
|
29
|
+
@file_name = file_name
|
|
30
|
+
|
|
31
|
+
process_default src
|
|
32
|
+
|
|
33
|
+
process_mixins
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
#Process modules mixed into the controller, in case they contain actions.
|
|
38
|
+
def process_mixins
|
|
39
|
+
controller = @tracker.controllers[@current_class]
|
|
40
|
+
|
|
41
|
+
controller.includes.each do |i|
|
|
42
|
+
mixin = @tracker.libs[i]
|
|
43
|
+
|
|
44
|
+
next unless mixin
|
|
45
|
+
|
|
46
|
+
#Process methods in alphabetical order for consistency
|
|
47
|
+
methods = mixin.methods_public.keys.map { |n| n.to_s }.sort.map { |n| n.to_sym }
|
|
48
|
+
|
|
49
|
+
methods.each do |name|
|
|
50
|
+
#Need to process the method like it was in a controller in order
|
|
51
|
+
#to get the renders set
|
|
52
|
+
processor = Railroader::ControllerProcessor.new(@app_tree, @tracker)
|
|
53
|
+
method = mixin.get_method(name)[:src].deep_clone
|
|
54
|
+
|
|
55
|
+
if node_type? method, :defn
|
|
56
|
+
method = processor.process_defn method
|
|
57
|
+
else
|
|
58
|
+
#Should be a defn, but this will catch other cases
|
|
59
|
+
method = processor.process method
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
@file_name = mixin.file
|
|
63
|
+
#Then process it like any other method in the controller
|
|
64
|
+
process method
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
#Skip it, must be an inner class
|
|
70
|
+
def process_class exp
|
|
71
|
+
exp
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
#Processes a method definition, which may include
|
|
75
|
+
#processing any rendered templates.
|
|
76
|
+
def process_defn exp
|
|
77
|
+
meth_name = exp.method_name
|
|
78
|
+
|
|
79
|
+
Railroader.debug "Processing #{@current_class}##{meth_name}"
|
|
80
|
+
|
|
81
|
+
#Skip if instructed to only process a specific method
|
|
82
|
+
#(but don't skip if this method was called from elsewhere)
|
|
83
|
+
return exp if @current_method.nil? and @only_method and @only_method != meth_name
|
|
84
|
+
|
|
85
|
+
is_route = route? meth_name
|
|
86
|
+
other_method = @current_method
|
|
87
|
+
@current_method = meth_name
|
|
88
|
+
@rendered = false if is_route
|
|
89
|
+
|
|
90
|
+
meth_env do
|
|
91
|
+
if is_route
|
|
92
|
+
before_filter_list(@current_method, @current_class).each do |f|
|
|
93
|
+
process_before_filter f
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
process_all exp.body
|
|
98
|
+
|
|
99
|
+
if is_route and not @rendered
|
|
100
|
+
process_default_render exp
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
@current_method = other_method
|
|
105
|
+
exp
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
#Look for calls to head()
|
|
109
|
+
def process_call exp
|
|
110
|
+
exp = super
|
|
111
|
+
return exp unless call? exp
|
|
112
|
+
|
|
113
|
+
method = exp.method
|
|
114
|
+
|
|
115
|
+
if method == :head
|
|
116
|
+
@rendered = true
|
|
117
|
+
elsif exp.target.nil? and method == :template_exists?
|
|
118
|
+
env[exp.first_arg] = Sexp.new(:lit, :"railroader:existing_template")
|
|
119
|
+
elsif @tracker.options[:interprocedural] and
|
|
120
|
+
@current_method and (exp.target.nil? or exp.target.node_type == :self)
|
|
121
|
+
|
|
122
|
+
exp = get_call_value(exp)
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
exp
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
#Check for +respond_to+
|
|
129
|
+
def process_iter exp
|
|
130
|
+
super
|
|
131
|
+
|
|
132
|
+
if call? exp.block_call and exp.block_call.method == :respond_to
|
|
133
|
+
@rendered = true
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
exp
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
#Processes a call to a before filter.
|
|
140
|
+
#Basically, adds any instance variable assignments to the environment.
|
|
141
|
+
#TODO: method arguments?
|
|
142
|
+
def process_before_filter name
|
|
143
|
+
filter = find_method name, @current_class
|
|
144
|
+
|
|
145
|
+
if filter.nil?
|
|
146
|
+
Railroader.debug "[Notice] Could not find filter #{name}"
|
|
147
|
+
return
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
method = filter[:method]
|
|
151
|
+
|
|
152
|
+
if ivars = @tracker.filter_cache[[filter[:controller], name]]
|
|
153
|
+
ivars.each do |variable, value|
|
|
154
|
+
env[variable] = value
|
|
155
|
+
end
|
|
156
|
+
else
|
|
157
|
+
processor = Railroader::AliasProcessor.new @tracker
|
|
158
|
+
processor.process_safely(method.body_list, only_ivars(:include_request_vars))
|
|
159
|
+
|
|
160
|
+
ivars = processor.only_ivars(:include_request_vars).all
|
|
161
|
+
|
|
162
|
+
@tracker.filter_cache[[filter[:controller], name]] = ivars
|
|
163
|
+
|
|
164
|
+
ivars.each do |variable, value|
|
|
165
|
+
env[variable] = value
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
#Processes the default template for the current action
|
|
171
|
+
def process_default_render exp
|
|
172
|
+
process_layout
|
|
173
|
+
process_template template_name, nil, nil, nil
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
#Process template and add the current class and method name as called_from info
|
|
177
|
+
def process_template name, args, _, line
|
|
178
|
+
# If line is null, assume implicit render and set the end of the action
|
|
179
|
+
# method as the line number
|
|
180
|
+
if line.nil? and controller = @tracker.controllers[@current_class]
|
|
181
|
+
if meth = controller.get_method(@current_method)
|
|
182
|
+
if line = meth[:src] && meth[:src].last && meth[:src].last.line
|
|
183
|
+
line += 1
|
|
184
|
+
else
|
|
185
|
+
line = 1
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
render_path = Railroader::RenderPath.new.add_controller_render(@current_class, @current_method, line, relative_path(@file_name))
|
|
191
|
+
super name, args, render_path, line
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
#Turns a method name into a template name
|
|
195
|
+
def template_name name = nil
|
|
196
|
+
name ||= @current_method
|
|
197
|
+
name = name.to_s
|
|
198
|
+
if name.include? "/"
|
|
199
|
+
name
|
|
200
|
+
else
|
|
201
|
+
controller = @current_class.to_s.gsub("Controller", "")
|
|
202
|
+
controller.gsub!("::", "/")
|
|
203
|
+
underscore(controller + "/" + name.to_s)
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
#Determines default layout name
|
|
208
|
+
def layout_name
|
|
209
|
+
controller = @tracker.controllers[@current_class]
|
|
210
|
+
|
|
211
|
+
return controller.layout if controller.layout
|
|
212
|
+
return false if controller.layout == false
|
|
213
|
+
|
|
214
|
+
app_controller = @tracker.controllers[:ApplicationController]
|
|
215
|
+
|
|
216
|
+
return app_controller.layout if app_controller and app_controller.layout
|
|
217
|
+
|
|
218
|
+
nil
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
#Returns true if the given method name is also a route
|
|
222
|
+
def route? method
|
|
223
|
+
if @tracker.routes[:allow_all_actions] or @tracker.options[:assume_all_routes]
|
|
224
|
+
true
|
|
225
|
+
else
|
|
226
|
+
routes = @tracker.routes[@current_class]
|
|
227
|
+
routes and (routes.include? :allow_all_actions or routes.include? method)
|
|
228
|
+
end
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
#Get list of filters, including those that are inherited
|
|
232
|
+
def before_filter_list method, klass
|
|
233
|
+
controller = @tracker.controllers[klass]
|
|
234
|
+
|
|
235
|
+
if controller
|
|
236
|
+
controller.before_filter_list self, method
|
|
237
|
+
else
|
|
238
|
+
[]
|
|
239
|
+
end
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
#Finds a method in the given class or a parent class
|
|
243
|
+
#
|
|
244
|
+
#Returns nil if the method could not be found.
|
|
245
|
+
#
|
|
246
|
+
#If found, returns hash table with controller name and method sexp.
|
|
247
|
+
def find_method method_name, klass
|
|
248
|
+
return nil if sexp? method_name
|
|
249
|
+
method_name = method_name.to_sym
|
|
250
|
+
|
|
251
|
+
if method = @method_cache[method_name]
|
|
252
|
+
return method
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
controller = @tracker.controllers[klass]
|
|
256
|
+
controller ||= @tracker.libs[klass]
|
|
257
|
+
|
|
258
|
+
if klass and controller
|
|
259
|
+
method = controller.get_method method_name
|
|
260
|
+
|
|
261
|
+
if method.nil?
|
|
262
|
+
controller.includes.each do |included|
|
|
263
|
+
method = find_method method_name, included
|
|
264
|
+
if method
|
|
265
|
+
@method_cache[method_name] = method
|
|
266
|
+
return method
|
|
267
|
+
end
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
@method_cache[method_name] = find_method method_name, controller.parent
|
|
271
|
+
else
|
|
272
|
+
@method_cache[method_name] = { :controller => controller.name, :method => method[:src] }
|
|
273
|
+
end
|
|
274
|
+
else
|
|
275
|
+
nil
|
|
276
|
+
end
|
|
277
|
+
end
|
|
278
|
+
end
|