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.
- checksums.yaml +7 -0
- data/CHANGES +872 -0
- data/FEATURES +16 -0
- data/README.md +169 -0
- data/WARNING_TYPES +95 -0
- data/bin/brakeman +89 -0
- data/lib/brakeman.rb +495 -0
- data/lib/brakeman/app_tree.rb +161 -0
- data/lib/brakeman/brakeman.rake +17 -0
- data/lib/brakeman/call_index.rb +219 -0
- data/lib/brakeman/checks.rb +191 -0
- data/lib/brakeman/checks/base_check.rb +518 -0
- data/lib/brakeman/checks/check_basic_auth.rb +88 -0
- data/lib/brakeman/checks/check_basic_auth_timing_attack.rb +33 -0
- data/lib/brakeman/checks/check_content_tag.rb +160 -0
- data/lib/brakeman/checks/check_create_with.rb +75 -0
- data/lib/brakeman/checks/check_cross_site_scripting.rb +385 -0
- data/lib/brakeman/checks/check_default_routes.rb +86 -0
- data/lib/brakeman/checks/check_deserialize.rb +57 -0
- data/lib/brakeman/checks/check_detailed_exceptions.rb +55 -0
- data/lib/brakeman/checks/check_digest_dos.rb +38 -0
- data/lib/brakeman/checks/check_dynamic_finders.rb +49 -0
- data/lib/brakeman/checks/check_escape_function.rb +21 -0
- data/lib/brakeman/checks/check_evaluation.rb +36 -0
- data/lib/brakeman/checks/check_execute.rb +167 -0
- data/lib/brakeman/checks/check_file_access.rb +63 -0
- data/lib/brakeman/checks/check_file_disclosure.rb +35 -0
- data/lib/brakeman/checks/check_filter_skipping.rb +31 -0
- data/lib/brakeman/checks/check_forgery_setting.rb +74 -0
- data/lib/brakeman/checks/check_header_dos.rb +31 -0
- data/lib/brakeman/checks/check_i18n_xss.rb +48 -0
- data/lib/brakeman/checks/check_jruby_xml.rb +38 -0
- data/lib/brakeman/checks/check_json_encoding.rb +47 -0
- data/lib/brakeman/checks/check_json_parsing.rb +107 -0
- data/lib/brakeman/checks/check_link_to.rb +132 -0
- data/lib/brakeman/checks/check_link_to_href.rb +115 -0
- data/lib/brakeman/checks/check_mail_to.rb +49 -0
- data/lib/brakeman/checks/check_mass_assignment.rb +198 -0
- data/lib/brakeman/checks/check_mime_type_dos.rb +39 -0
- data/lib/brakeman/checks/check_model_attr_accessible.rb +55 -0
- data/lib/brakeman/checks/check_model_attributes.rb +119 -0
- data/lib/brakeman/checks/check_model_serialize.rb +67 -0
- data/lib/brakeman/checks/check_nested_attributes.rb +38 -0
- data/lib/brakeman/checks/check_nested_attributes_bypass.rb +58 -0
- data/lib/brakeman/checks/check_number_to_currency.rb +74 -0
- data/lib/brakeman/checks/check_quote_table_name.rb +40 -0
- data/lib/brakeman/checks/check_redirect.rb +215 -0
- data/lib/brakeman/checks/check_regex_dos.rb +69 -0
- data/lib/brakeman/checks/check_render.rb +92 -0
- data/lib/brakeman/checks/check_render_dos.rb +37 -0
- data/lib/brakeman/checks/check_render_inline.rb +54 -0
- data/lib/brakeman/checks/check_response_splitting.rb +21 -0
- data/lib/brakeman/checks/check_route_dos.rb +42 -0
- data/lib/brakeman/checks/check_safe_buffer_manipulation.rb +31 -0
- data/lib/brakeman/checks/check_sanitize_methods.rb +79 -0
- data/lib/brakeman/checks/check_secrets.rb +40 -0
- data/lib/brakeman/checks/check_select_tag.rb +60 -0
- data/lib/brakeman/checks/check_select_vulnerability.rb +60 -0
- data/lib/brakeman/checks/check_send.rb +48 -0
- data/lib/brakeman/checks/check_send_file.rb +19 -0
- data/lib/brakeman/checks/check_session_manipulation.rb +36 -0
- data/lib/brakeman/checks/check_session_settings.rb +170 -0
- data/lib/brakeman/checks/check_simple_format.rb +59 -0
- data/lib/brakeman/checks/check_single_quotes.rb +101 -0
- data/lib/brakeman/checks/check_skip_before_filter.rb +60 -0
- data/lib/brakeman/checks/check_sql.rb +660 -0
- data/lib/brakeman/checks/check_sql_cves.rb +101 -0
- data/lib/brakeman/checks/check_ssl_verify.rb +49 -0
- data/lib/brakeman/checks/check_strip_tags.rb +89 -0
- data/lib/brakeman/checks/check_symbol_dos.rb +64 -0
- data/lib/brakeman/checks/check_symbol_dos_cve.rb +30 -0
- data/lib/brakeman/checks/check_translate_bug.rb +45 -0
- data/lib/brakeman/checks/check_unsafe_reflection.rb +51 -0
- data/lib/brakeman/checks/check_unscoped_find.rb +41 -0
- data/lib/brakeman/checks/check_validation_regex.rb +116 -0
- data/lib/brakeman/checks/check_weak_hash.rb +151 -0
- data/lib/brakeman/checks/check_without_protection.rb +80 -0
- data/lib/brakeman/checks/check_xml_dos.rb +51 -0
- data/lib/brakeman/checks/check_yaml_parsing.rb +121 -0
- data/lib/brakeman/differ.rb +66 -0
- data/lib/brakeman/file_parser.rb +50 -0
- data/lib/brakeman/format/style.css +133 -0
- data/lib/brakeman/options.rb +301 -0
- data/lib/brakeman/parsers/rails2_erubis.rb +6 -0
- data/lib/brakeman/parsers/rails2_xss_plugin_erubis.rb +48 -0
- data/lib/brakeman/parsers/rails3_erubis.rb +74 -0
- data/lib/brakeman/parsers/template_parser.rb +89 -0
- data/lib/brakeman/processor.rb +102 -0
- data/lib/brakeman/processors/alias_processor.rb +1013 -0
- data/lib/brakeman/processors/base_processor.rb +277 -0
- data/lib/brakeman/processors/config_processor.rb +14 -0
- data/lib/brakeman/processors/controller_alias_processor.rb +273 -0
- data/lib/brakeman/processors/controller_processor.rb +326 -0
- data/lib/brakeman/processors/erb_template_processor.rb +80 -0
- data/lib/brakeman/processors/erubis_template_processor.rb +104 -0
- data/lib/brakeman/processors/gem_processor.rb +57 -0
- data/lib/brakeman/processors/haml_template_processor.rb +190 -0
- data/lib/brakeman/processors/lib/basic_processor.rb +37 -0
- data/lib/brakeman/processors/lib/find_all_calls.rb +223 -0
- data/lib/brakeman/processors/lib/find_call.rb +183 -0
- data/lib/brakeman/processors/lib/find_return_value.rb +134 -0
- data/lib/brakeman/processors/lib/processor_helper.rb +75 -0
- data/lib/brakeman/processors/lib/rails2_config_processor.rb +145 -0
- data/lib/brakeman/processors/lib/rails2_route_processor.rb +313 -0
- data/lib/brakeman/processors/lib/rails3_config_processor.rb +132 -0
- data/lib/brakeman/processors/lib/rails3_route_processor.rb +308 -0
- data/lib/brakeman/processors/lib/render_helper.rb +181 -0
- data/lib/brakeman/processors/lib/render_path.rb +107 -0
- data/lib/brakeman/processors/lib/route_helper.rb +68 -0
- data/lib/brakeman/processors/lib/safe_call_helper.rb +16 -0
- data/lib/brakeman/processors/library_processor.rb +119 -0
- data/lib/brakeman/processors/model_processor.rb +191 -0
- data/lib/brakeman/processors/output_processor.rb +171 -0
- data/lib/brakeman/processors/route_processor.rb +17 -0
- data/lib/brakeman/processors/slim_template_processor.rb +107 -0
- data/lib/brakeman/processors/template_alias_processor.rb +116 -0
- data/lib/brakeman/processors/template_processor.rb +74 -0
- data/lib/brakeman/report.rb +78 -0
- data/lib/brakeman/report/config/remediation.yml +71 -0
- data/lib/brakeman/report/ignore/config.rb +135 -0
- data/lib/brakeman/report/ignore/interactive.rb +311 -0
- data/lib/brakeman/report/renderer.rb +24 -0
- data/lib/brakeman/report/report_base.rb +286 -0
- data/lib/brakeman/report/report_codeclimate.rb +70 -0
- data/lib/brakeman/report/report_csv.rb +55 -0
- data/lib/brakeman/report/report_hash.rb +23 -0
- data/lib/brakeman/report/report_html.rb +216 -0
- data/lib/brakeman/report/report_json.rb +42 -0
- data/lib/brakeman/report/report_markdown.rb +156 -0
- data/lib/brakeman/report/report_table.rb +107 -0
- data/lib/brakeman/report/report_tabs.rb +17 -0
- data/lib/brakeman/report/templates/controller_overview.html.erb +22 -0
- data/lib/brakeman/report/templates/controller_warnings.html.erb +21 -0
- data/lib/brakeman/report/templates/error_overview.html.erb +29 -0
- data/lib/brakeman/report/templates/header.html.erb +58 -0
- data/lib/brakeman/report/templates/ignored_warnings.html.erb +25 -0
- data/lib/brakeman/report/templates/model_warnings.html.erb +21 -0
- data/lib/brakeman/report/templates/overview.html.erb +38 -0
- data/lib/brakeman/report/templates/security_warnings.html.erb +23 -0
- data/lib/brakeman/report/templates/template_overview.html.erb +21 -0
- data/lib/brakeman/report/templates/view_warnings.html.erb +34 -0
- data/lib/brakeman/report/templates/warning_overview.html.erb +17 -0
- data/lib/brakeman/rescanner.rb +483 -0
- data/lib/brakeman/scanner.rb +317 -0
- data/lib/brakeman/tracker.rb +347 -0
- data/lib/brakeman/tracker/collection.rb +93 -0
- data/lib/brakeman/tracker/config.rb +101 -0
- data/lib/brakeman/tracker/constants.rb +101 -0
- data/lib/brakeman/tracker/controller.rb +161 -0
- data/lib/brakeman/tracker/library.rb +17 -0
- data/lib/brakeman/tracker/model.rb +90 -0
- data/lib/brakeman/tracker/template.rb +33 -0
- data/lib/brakeman/util.rb +481 -0
- data/lib/brakeman/version.rb +3 -0
- data/lib/brakeman/warning.rb +255 -0
- data/lib/brakeman/warning_codes.rb +111 -0
- data/lib/ruby_parser/bm_sexp.rb +610 -0
- data/lib/ruby_parser/bm_sexp_processor.rb +116 -0
- metadata +362 -0
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
require 'brakeman/processors/lib/basic_processor'
|
|
2
|
+
|
|
3
|
+
#Processes Gemfile and Gemfile.lock
|
|
4
|
+
class Brakeman::GemProcessor < Brakeman::BasicProcessor
|
|
5
|
+
|
|
6
|
+
def initialize *args
|
|
7
|
+
super
|
|
8
|
+
@gem_name_version = /^\s*([-_+.A-Za-z0-9]+) \((\w(\.\w+)*)\)/
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def process_gems gem_files
|
|
12
|
+
@gem_files = gem_files
|
|
13
|
+
@gemfile = gem_files[:gemfile][:file]
|
|
14
|
+
process gem_files[:gemfile][:src]
|
|
15
|
+
|
|
16
|
+
if gem_files[:gemlock]
|
|
17
|
+
process_gem_lock
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
@tracker.config.set_rails_version
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def process_call exp
|
|
24
|
+
if exp.target == nil and exp.method == :gem
|
|
25
|
+
gem_name = exp.first_arg
|
|
26
|
+
return exp unless string? gem_name
|
|
27
|
+
|
|
28
|
+
gem_version = exp.second_arg
|
|
29
|
+
|
|
30
|
+
version = if string? gem_version
|
|
31
|
+
gem_version.value
|
|
32
|
+
else
|
|
33
|
+
nil
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
@tracker.config.add_gem gem_name.value, version, @gemfile, exp.line
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
exp
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def process_gem_lock
|
|
43
|
+
line_num = 1
|
|
44
|
+
file = @gem_files[:gemlock][:file]
|
|
45
|
+
@gem_files[:gemlock][:src].each_line do |line|
|
|
46
|
+
set_gem_version_and_file line, file, line_num
|
|
47
|
+
line_num += 1
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Supports .rc2 but not ~>, >=, or <=
|
|
52
|
+
def set_gem_version_and_file line, file, line_num
|
|
53
|
+
if line =~ @gem_name_version
|
|
54
|
+
@tracker.config.add_gem $1, $2, file, line_num
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
require 'brakeman/processors/template_processor'
|
|
2
|
+
|
|
3
|
+
#Processes HAML templates.
|
|
4
|
+
class Brakeman::HamlTemplateProcessor < Brakeman::TemplateProcessor
|
|
5
|
+
HAML_FORMAT_METHOD = /format_script_(true|false)_(true|false)_(true|false)_(true|false)_(true|false)_(true|false)_(true|false)/
|
|
6
|
+
HAML_HELPERS = s(:colon2, s(:const, :Haml), :Helpers)
|
|
7
|
+
JAVASCRIPT_FILTER = s(:colon2, s(:colon2, s(:const, :Haml), :Filters), :Javascript)
|
|
8
|
+
COFFEE_FILTER = s(:colon2, s(:colon2, s(:const, :Haml), :Filters), :Coffee)
|
|
9
|
+
|
|
10
|
+
#Processes call, looking for template output
|
|
11
|
+
def process_call exp
|
|
12
|
+
target = exp.target
|
|
13
|
+
if sexp? target
|
|
14
|
+
target = process target
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
method = exp.method
|
|
18
|
+
|
|
19
|
+
if (call? target and target.method == :_hamlout)
|
|
20
|
+
res = case method
|
|
21
|
+
when :adjust_tabs, :rstrip!, :attributes #Check attributes, maybe?
|
|
22
|
+
ignore
|
|
23
|
+
when :options, :buffer
|
|
24
|
+
exp
|
|
25
|
+
when :open_tag
|
|
26
|
+
process_call_args exp
|
|
27
|
+
else
|
|
28
|
+
arg = exp.first_arg
|
|
29
|
+
|
|
30
|
+
if arg
|
|
31
|
+
@inside_concat = true
|
|
32
|
+
exp.first_arg = process(arg)
|
|
33
|
+
out = normalize_output(exp.first_arg)
|
|
34
|
+
@inside_concat = false
|
|
35
|
+
else
|
|
36
|
+
raise "Empty _hamlout.#{method}()?"
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
if string? out
|
|
40
|
+
ignore
|
|
41
|
+
else
|
|
42
|
+
r = case method.to_s
|
|
43
|
+
when "push_text"
|
|
44
|
+
build_output_from_push_text(out)
|
|
45
|
+
when HAML_FORMAT_METHOD
|
|
46
|
+
if $4 == "true"
|
|
47
|
+
if string_interp? out
|
|
48
|
+
build_output_from_push_text(out, :escaped_output)
|
|
49
|
+
else
|
|
50
|
+
Sexp.new :format_escaped, out
|
|
51
|
+
end
|
|
52
|
+
else
|
|
53
|
+
if string_interp? out
|
|
54
|
+
build_output_from_push_text(out)
|
|
55
|
+
else
|
|
56
|
+
Sexp.new :format, out
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
else
|
|
61
|
+
raise "Unrecognized action on _hamlout: #{method}"
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
@javascript = false
|
|
65
|
+
r
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
res.line(exp.line)
|
|
70
|
+
res
|
|
71
|
+
|
|
72
|
+
#_hamlout.buffer <<
|
|
73
|
+
#This seems to be used rarely, but directly appends args to output buffer.
|
|
74
|
+
#Has something to do with values of blocks?
|
|
75
|
+
elsif sexp? target and method == :<< and is_buffer_target? target
|
|
76
|
+
@inside_concat = true
|
|
77
|
+
exp.first_arg = process(exp.first_arg)
|
|
78
|
+
out = normalize_output(exp.first_arg)
|
|
79
|
+
@inside_concat = false
|
|
80
|
+
|
|
81
|
+
if out.node_type == :str #ignore plain strings
|
|
82
|
+
ignore
|
|
83
|
+
else
|
|
84
|
+
s = Sexp.new(:output, out)
|
|
85
|
+
@current_template.add_output s
|
|
86
|
+
s.line(exp.line)
|
|
87
|
+
s
|
|
88
|
+
end
|
|
89
|
+
elsif target == nil and method == :render
|
|
90
|
+
#Process call to render()
|
|
91
|
+
exp.arglist = process exp.arglist
|
|
92
|
+
make_render_in_view exp
|
|
93
|
+
elsif target == nil and method == :find_and_preserve and exp.first_arg
|
|
94
|
+
process exp.first_arg
|
|
95
|
+
elsif method == :render_with_options
|
|
96
|
+
if target == JAVASCRIPT_FILTER or target == COFFEE_FILTER
|
|
97
|
+
@javascript = true
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
process exp.first_arg
|
|
101
|
+
else
|
|
102
|
+
exp.target = target
|
|
103
|
+
exp.arglist = process exp.arglist
|
|
104
|
+
exp
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
#If inside an output stream, only return the final expression
|
|
109
|
+
def process_block exp
|
|
110
|
+
exp = exp.dup
|
|
111
|
+
exp.shift
|
|
112
|
+
if @inside_concat
|
|
113
|
+
@inside_concat = false
|
|
114
|
+
exp[0..-2].each do |e|
|
|
115
|
+
process e
|
|
116
|
+
end
|
|
117
|
+
@inside_concat = true
|
|
118
|
+
process exp[-1]
|
|
119
|
+
else
|
|
120
|
+
exp.map! do |e|
|
|
121
|
+
res = process e
|
|
122
|
+
if res.empty?
|
|
123
|
+
nil
|
|
124
|
+
else
|
|
125
|
+
res
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
Sexp.new(:rlist).concat(exp).compact
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
#Checks if the buffer is the target in a method call Sexp.
|
|
133
|
+
#TODO: Test this
|
|
134
|
+
def is_buffer_target? exp
|
|
135
|
+
exp.node_type == :call and
|
|
136
|
+
node_type? exp.target, :lvar and
|
|
137
|
+
exp.target.value == :_hamlout and
|
|
138
|
+
exp.method == :buffer
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
#HAML likes to put interpolated values into _hamlout.push_text
|
|
142
|
+
#but we want to handle those individually
|
|
143
|
+
def build_output_from_push_text exp, default = :output
|
|
144
|
+
if string_interp? exp
|
|
145
|
+
exp.map! do |e|
|
|
146
|
+
if sexp? e
|
|
147
|
+
if node_type? e, :evstr and e[1]
|
|
148
|
+
e = e.value
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
get_pushed_value e, default
|
|
152
|
+
else
|
|
153
|
+
e
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
#Gets outputs from values interpolated into _hamlout.push_text
|
|
160
|
+
def get_pushed_value exp, default = :output
|
|
161
|
+
return exp unless sexp? exp
|
|
162
|
+
|
|
163
|
+
case exp.node_type
|
|
164
|
+
when :format
|
|
165
|
+
exp.node_type = :output
|
|
166
|
+
@current_template.add_output exp
|
|
167
|
+
exp
|
|
168
|
+
when :format_escaped
|
|
169
|
+
exp.node_type = :escaped_output
|
|
170
|
+
@current_template.add_output exp
|
|
171
|
+
exp
|
|
172
|
+
when :str, :ignore, :output, :escaped_output
|
|
173
|
+
exp
|
|
174
|
+
when :block, :rlist, :dstr
|
|
175
|
+
exp.map! { |e| get_pushed_value e }
|
|
176
|
+
else
|
|
177
|
+
if call? exp and exp.target == HAML_HELPERS and exp.method == :html_escape
|
|
178
|
+
s = Sexp.new(:escaped_output, exp.first_arg)
|
|
179
|
+
elsif @javascript and call? exp and (exp.method == :j or exp.method == :escape_javascript)
|
|
180
|
+
s = Sexp.new(:escaped_output, exp.first_arg)
|
|
181
|
+
else
|
|
182
|
+
s = Sexp.new(default, exp)
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
s.line(exp.line)
|
|
186
|
+
@current_template.add_output s
|
|
187
|
+
s
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
require 'brakeman/processors/lib/processor_helper'
|
|
2
|
+
require 'brakeman/processors/lib/safe_call_helper'
|
|
3
|
+
require 'brakeman/util'
|
|
4
|
+
|
|
5
|
+
class Brakeman::BasicProcessor < Brakeman::SexpProcessor
|
|
6
|
+
include Brakeman::ProcessorHelper
|
|
7
|
+
include Brakeman::SafeCallHelper
|
|
8
|
+
include Brakeman::Util
|
|
9
|
+
|
|
10
|
+
def initialize tracker
|
|
11
|
+
super()
|
|
12
|
+
@tracker = tracker
|
|
13
|
+
@current_template = @current_module = @current_class = @current_method = nil
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def process_default exp
|
|
17
|
+
process_all exp
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def process_if exp
|
|
21
|
+
condition = exp.condition
|
|
22
|
+
|
|
23
|
+
process condition
|
|
24
|
+
|
|
25
|
+
if true? condition
|
|
26
|
+
process exp.then_clause
|
|
27
|
+
elsif false? condition
|
|
28
|
+
process exp.else_clause
|
|
29
|
+
else
|
|
30
|
+
[exp.then_clause, exp.else_clause].compact.map do |e|
|
|
31
|
+
process e
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
exp
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
require 'brakeman/processors/lib/basic_processor'
|
|
2
|
+
|
|
3
|
+
class Brakeman::FindAllCalls < Brakeman::BasicProcessor
|
|
4
|
+
attr_reader :calls
|
|
5
|
+
|
|
6
|
+
def initialize tracker
|
|
7
|
+
super
|
|
8
|
+
@current_class = nil
|
|
9
|
+
@current_method = nil
|
|
10
|
+
@in_target = false
|
|
11
|
+
@calls = []
|
|
12
|
+
@cache = {}
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
#Process the given source. Provide either class and method being searched
|
|
16
|
+
#or the template. These names are used when reporting results.
|
|
17
|
+
def process_source exp, opts
|
|
18
|
+
@current_class = opts[:class]
|
|
19
|
+
@current_method = opts[:method]
|
|
20
|
+
@current_template = opts[:template]
|
|
21
|
+
@current_file = opts[:file]
|
|
22
|
+
process exp
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
#Process body of method
|
|
26
|
+
def process_defn exp
|
|
27
|
+
return exp unless @current_method
|
|
28
|
+
process_all exp.body
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
#Process body of method
|
|
32
|
+
def process_defs exp
|
|
33
|
+
return exp unless @current_method
|
|
34
|
+
process_all exp.body
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
#Process body of block
|
|
38
|
+
def process_rlist exp
|
|
39
|
+
process_all exp
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def process_call exp
|
|
43
|
+
@calls << create_call_hash(exp)
|
|
44
|
+
exp
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def process_iter exp
|
|
48
|
+
call = exp.block_call
|
|
49
|
+
|
|
50
|
+
if call.node_type == :call
|
|
51
|
+
call_hash = create_call_hash(call)
|
|
52
|
+
|
|
53
|
+
call_hash[:block] = exp.block
|
|
54
|
+
call_hash[:block_args] = exp.block_args
|
|
55
|
+
|
|
56
|
+
@calls << call_hash
|
|
57
|
+
|
|
58
|
+
process exp.block
|
|
59
|
+
else
|
|
60
|
+
#Probably a :render call with block
|
|
61
|
+
process call
|
|
62
|
+
process exp.block
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
exp
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
#Calls to render() are converted to s(:render, ...) but we would
|
|
69
|
+
#like them in the call cache still for speed
|
|
70
|
+
def process_render exp
|
|
71
|
+
process exp.last if sexp? exp.last
|
|
72
|
+
|
|
73
|
+
@calls << { :target => nil,
|
|
74
|
+
:method => :render,
|
|
75
|
+
:call => exp,
|
|
76
|
+
:nested => false,
|
|
77
|
+
:location => make_location }
|
|
78
|
+
|
|
79
|
+
exp
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
#Technically, `` is call to Kernel#`
|
|
83
|
+
#But we just need them in the call cache for speed
|
|
84
|
+
def process_dxstr exp
|
|
85
|
+
process exp.last if sexp? exp.last
|
|
86
|
+
|
|
87
|
+
@calls << { :target => nil,
|
|
88
|
+
:method => :`,
|
|
89
|
+
:call => exp,
|
|
90
|
+
:nested => false,
|
|
91
|
+
:location => make_location }
|
|
92
|
+
|
|
93
|
+
exp
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
#:"string" is equivalent to "string".to_sym
|
|
97
|
+
def process_dsym exp
|
|
98
|
+
exp.each { |arg| process arg if sexp? arg }
|
|
99
|
+
|
|
100
|
+
@calls << { :target => nil,
|
|
101
|
+
:method => :literal_to_sym,
|
|
102
|
+
:call => exp,
|
|
103
|
+
:nested => false,
|
|
104
|
+
:location => make_location }
|
|
105
|
+
|
|
106
|
+
exp
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# Process a dynamic regex like a call
|
|
110
|
+
def process_dregx exp
|
|
111
|
+
exp.each { |arg| process arg if sexp? arg }
|
|
112
|
+
|
|
113
|
+
@calls << { :target => nil,
|
|
114
|
+
:method => :brakeman_regex_interp,
|
|
115
|
+
:call => exp,
|
|
116
|
+
:nested => false,
|
|
117
|
+
:location => make_location }
|
|
118
|
+
|
|
119
|
+
exp
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
#Process an assignment like a call
|
|
123
|
+
def process_attrasgn exp
|
|
124
|
+
process_call exp
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
private
|
|
128
|
+
|
|
129
|
+
#Gets the target of a call as a Symbol
|
|
130
|
+
#if possible
|
|
131
|
+
def get_target exp, include_calls = false
|
|
132
|
+
if sexp? exp
|
|
133
|
+
case exp.node_type
|
|
134
|
+
when :ivar, :lvar, :const, :lit
|
|
135
|
+
exp.value
|
|
136
|
+
when :true, :false
|
|
137
|
+
exp[0]
|
|
138
|
+
when :colon2
|
|
139
|
+
class_name exp
|
|
140
|
+
when :self
|
|
141
|
+
@current_class || @current_module || nil
|
|
142
|
+
when :params, :session, :cookies
|
|
143
|
+
exp.node_type
|
|
144
|
+
when :call, :safe_call
|
|
145
|
+
if include_calls
|
|
146
|
+
if exp.target.nil?
|
|
147
|
+
exp.method
|
|
148
|
+
else
|
|
149
|
+
t = get_target(exp.target, :include_calls)
|
|
150
|
+
if t.is_a? Symbol
|
|
151
|
+
:"#{t}.#{exp.method}"
|
|
152
|
+
else
|
|
153
|
+
exp
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
else
|
|
157
|
+
exp
|
|
158
|
+
end
|
|
159
|
+
else
|
|
160
|
+
exp
|
|
161
|
+
end
|
|
162
|
+
else
|
|
163
|
+
exp
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
#Returns method chain as an array
|
|
168
|
+
#For example, User.human.alive.all would return [:User, :human, :alive, :all]
|
|
169
|
+
def get_chain call
|
|
170
|
+
if node_type? call, :call, :attrasgn, :safe_call, :safe_attrasgn
|
|
171
|
+
get_chain(call.target) + [call.method]
|
|
172
|
+
elsif call.nil?
|
|
173
|
+
[]
|
|
174
|
+
else
|
|
175
|
+
[get_target(call)]
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def make_location
|
|
180
|
+
if @current_template
|
|
181
|
+
key = [@current_template, @current_file]
|
|
182
|
+
cached = @cache[key]
|
|
183
|
+
return cached if cached
|
|
184
|
+
|
|
185
|
+
@cache[key] = { :type => :template,
|
|
186
|
+
:template => @current_template,
|
|
187
|
+
:file => @current_file }
|
|
188
|
+
else
|
|
189
|
+
key = [@current_class, @current_method, @current_file]
|
|
190
|
+
cached = @cache[key]
|
|
191
|
+
return cached if cached
|
|
192
|
+
@cache[key] = { :type => :class,
|
|
193
|
+
:class => @current_class,
|
|
194
|
+
:method => @current_method,
|
|
195
|
+
:file => @current_file }
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
#Return info hash for a call Sexp
|
|
201
|
+
def create_call_hash exp
|
|
202
|
+
target = get_target exp.target
|
|
203
|
+
|
|
204
|
+
if call? target
|
|
205
|
+
already_in_target = @in_target
|
|
206
|
+
@in_target = true
|
|
207
|
+
process target
|
|
208
|
+
@in_target = already_in_target
|
|
209
|
+
|
|
210
|
+
target = get_target(target, :include_calls)
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
method = exp.method
|
|
214
|
+
process_call_args exp
|
|
215
|
+
|
|
216
|
+
{ :target => target,
|
|
217
|
+
:method => method,
|
|
218
|
+
:call => exp,
|
|
219
|
+
:nested => @in_target,
|
|
220
|
+
:chain => get_chain(exp),
|
|
221
|
+
:location => make_location }
|
|
222
|
+
end
|
|
223
|
+
end
|