brakeman-min 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. data/FEATURES +16 -0
  2. data/README.md +118 -0
  3. data/WARNING_TYPES +69 -0
  4. data/bin/brakeman +269 -0
  5. data/lib/checks.rb +67 -0
  6. data/lib/checks/base_check.rb +353 -0
  7. data/lib/checks/check_cross_site_scripting.rb +324 -0
  8. data/lib/checks/check_default_routes.rb +29 -0
  9. data/lib/checks/check_evaluation.rb +27 -0
  10. data/lib/checks/check_execute.rb +110 -0
  11. data/lib/checks/check_file_access.rb +46 -0
  12. data/lib/checks/check_forgery_setting.rb +42 -0
  13. data/lib/checks/check_mail_to.rb +48 -0
  14. data/lib/checks/check_mass_assignment.rb +72 -0
  15. data/lib/checks/check_model_attributes.rb +36 -0
  16. data/lib/checks/check_nested_attributes.rb +34 -0
  17. data/lib/checks/check_redirect.rb +98 -0
  18. data/lib/checks/check_render.rb +65 -0
  19. data/lib/checks/check_send_file.rb +15 -0
  20. data/lib/checks/check_session_settings.rb +36 -0
  21. data/lib/checks/check_sql.rb +124 -0
  22. data/lib/checks/check_validation_regex.rb +60 -0
  23. data/lib/format/style.css +105 -0
  24. data/lib/processor.rb +83 -0
  25. data/lib/processors/alias_processor.rb +384 -0
  26. data/lib/processors/base_processor.rb +237 -0
  27. data/lib/processors/config_processor.rb +146 -0
  28. data/lib/processors/controller_alias_processor.rb +237 -0
  29. data/lib/processors/controller_processor.rb +202 -0
  30. data/lib/processors/erb_template_processor.rb +84 -0
  31. data/lib/processors/erubis_template_processor.rb +62 -0
  32. data/lib/processors/haml_template_processor.rb +131 -0
  33. data/lib/processors/lib/find_call.rb +176 -0
  34. data/lib/processors/lib/find_model_call.rb +39 -0
  35. data/lib/processors/lib/processor_helper.rb +36 -0
  36. data/lib/processors/lib/render_helper.rb +137 -0
  37. data/lib/processors/library_processor.rb +118 -0
  38. data/lib/processors/model_processor.rb +125 -0
  39. data/lib/processors/output_processor.rb +233 -0
  40. data/lib/processors/params_processor.rb +77 -0
  41. data/lib/processors/route_processor.rb +338 -0
  42. data/lib/processors/template_alias_processor.rb +86 -0
  43. data/lib/processors/template_processor.rb +55 -0
  44. data/lib/report.rb +651 -0
  45. data/lib/scanner.rb +215 -0
  46. data/lib/scanner_erubis.rb +43 -0
  47. data/lib/tracker.rb +144 -0
  48. data/lib/util.rb +141 -0
  49. data/lib/version.rb +1 -0
  50. data/lib/warning.rb +97 -0
  51. metadata +141 -0
@@ -0,0 +1,202 @@
1
+ require 'ruby_parser'
2
+ require 'processors/base_processor'
3
+
4
+ #Processes controller. Results are put in tracker.controllers
5
+ class ControllerProcessor < BaseProcessor
6
+ FORMAT_HTML = Sexp.new(:call, Sexp.new(:lvar, :format), :html, Sexp.new(:arglist))
7
+
8
+ def initialize tracker
9
+ super
10
+ @controller = nil
11
+ @current_method = nil
12
+ @current_module = nil
13
+ @visibility = :public
14
+ @file_name = nil
15
+ end
16
+
17
+ #Use this method to process a Controller
18
+ def process_controller src, file_name = nil
19
+ @file_name = file_name
20
+ process src
21
+ end
22
+
23
+ #s(:class, NAME, PARENT, s(:scope ...))
24
+ def process_class exp
25
+ if @controller
26
+ warn "[Notice] Skipping inner class: #{class_name exp[1]}" if OPTIONS[:debug]
27
+ return ignore
28
+ end
29
+
30
+ name = class_name(exp[1])
31
+ if @current_module
32
+ name = (@current_module + "::" + name.to_s).to_sym
33
+ end
34
+ @controller = { :name => name,
35
+ :parent => class_name(exp[2]),
36
+ :includes => [],
37
+ :public => {},
38
+ :private => {},
39
+ :protected => {},
40
+ :options => {},
41
+ :src => exp,
42
+ :file => @file_name }
43
+ @tracker.controllers[@controller[:name]] = @controller
44
+ exp[3] = process exp[3]
45
+ set_layout_name
46
+ @controller = nil
47
+ exp
48
+ end
49
+
50
+ #Look for specific calls inside the controller
51
+ def process_call exp
52
+ target = exp[1]
53
+ if sexp? target
54
+ target = process target
55
+ end
56
+
57
+ method = exp[2]
58
+ args = exp[3]
59
+
60
+ #Methods called inside class definition
61
+ #like attr_* and other settings
62
+ if @current_method.nil? and target.nil?
63
+ if args.length == 1 #actually, empty
64
+ case method
65
+ when :private, :protected, :public
66
+ @visibility = method
67
+ when :protect_from_forgery
68
+ @controller[:options][:protect_from_forgery] = true
69
+ else
70
+ #??
71
+ end
72
+ else
73
+ case method
74
+ when :include
75
+ @controller[:includes] << class_name(args[1]) if @controller
76
+ when :before_filter
77
+ @controller[:options][:before_filters] ||= []
78
+ @controller[:options][:before_filters] << args[1..-1]
79
+ when :layout
80
+ if string? args[-1]
81
+ #layout "some_layout"
82
+
83
+ name = args[-1][1].to_s
84
+ unless Dir.glob("#{OPTIONS[:app_path]}/app/views/layouts/#{name}.html.{erb,haml}").empty?
85
+ @controller[:layout] = "layouts/#{name}"
86
+ else
87
+ warn "[Notice] Layout not found: #{name}" if OPTIONS[:debug]
88
+ end
89
+ elsif sexp? args[-1] and (args[-1][0] == :nil or args[-1][0] == :false)
90
+ #layout :false or layout nil
91
+ @controller[:layout] = false
92
+ end
93
+ end
94
+ end
95
+ ignore
96
+ elsif target == nil and method == :render
97
+ make_render exp
98
+ elsif exp == FORMAT_HTML and context[1] != :iter
99
+ #This is an empty call to
100
+ # format.html
101
+ #Which renders the default template if no arguments
102
+ #Need to make more generic, though.
103
+ call = Sexp.new :render, :default, @current_method
104
+ call.line(exp.line)
105
+ call
106
+ else
107
+ call = Sexp.new :call, target, method, process(args)
108
+ call.line(exp.line)
109
+ call
110
+ end
111
+ end
112
+
113
+ #Process method definition and store in Tracker
114
+ def process_defn exp
115
+ name = exp[1]
116
+ @current_method = name
117
+ res = Sexp.new :methdef, name, process(exp[2]), process(exp[3][1])
118
+ res.line(exp.line)
119
+ @current_method = nil
120
+ @controller[@visibility][name] = res unless @controller.nil?
121
+
122
+ res
123
+ end
124
+
125
+ #Process self.method definition and store in Tracker
126
+ def process_defs exp
127
+ name = exp[2]
128
+
129
+ if exp[1].node_type == :self
130
+ target = @controller[:name]
131
+ else
132
+ target = class_name exp[1]
133
+ end
134
+
135
+ @current_method = name
136
+ res = Sexp.new :selfdef, target, name, process(exp[3]), process(exp[4][1])
137
+ res.line(exp.line)
138
+ @current_method = nil
139
+ @controller[@visibility][name] = res unless @controller.nil?
140
+
141
+ res
142
+ end
143
+
144
+ #Look for before_filters and add fake ones if necessary
145
+ def process_iter exp
146
+ if exp[1][2] == :before_filter
147
+ add_fake_filter exp
148
+ else
149
+ super
150
+ end
151
+ end
152
+
153
+ #Sets default layout for renders inside Controller
154
+ def set_layout_name
155
+ return if @controller[:layout]
156
+
157
+ name = underscore(@controller[:name].to_s.split("::")[-1].gsub("Controller", ''))
158
+
159
+ #There is a layout for this Controller
160
+ unless Dir.glob("#{OPTIONS[:app_path]}/app/views/layouts/#{name}.html.{erb,haml}").empty?
161
+ @controller[:layout] = "layouts/#{name}"
162
+ end
163
+ end
164
+
165
+ #This is to handle before_filter do |controller| ... end
166
+ #
167
+ #We build a new method and process that the same way as usual
168
+ #methods and filters.
169
+ def add_fake_filter exp
170
+ filter_name = ("fake_filter" + rand.to_s[/\d+$/]).to_sym
171
+ args = exp[1][3]
172
+ args.insert(1, Sexp.new(:lit, filter_name))
173
+ before_filter_call = Sexp.new(:call, nil, :before_filter, args)
174
+
175
+ if exp[2]
176
+ block_variable = exp[2][1]
177
+ else
178
+ block_variable = :temp
179
+ end
180
+
181
+ if sexp? exp[3] and exp[3].node_type == :block
182
+ block_inner = exp[3][1..-1]
183
+ else
184
+ block_inner = [exp[3]]
185
+ end
186
+
187
+ #Build Sexp for filter method
188
+ body = Sexp.new(:scope,
189
+ Sexp.new(:block,
190
+ Sexp.new(:lasgn, block_variable,
191
+ Sexp.new(:call, Sexp.new(:const, @controller[:name]), :new, Sexp.new(:arglist)))).concat(block_inner))
192
+
193
+ filter_method = Sexp.new(:defn, filter_name, Sexp.new(:args), body).line(exp.line)
194
+
195
+ vis = @visibility
196
+ @visibility = :private
197
+ process_defn filter_method
198
+ @visibility = vis
199
+ process before_filter_call
200
+ exp
201
+ end
202
+ end
@@ -0,0 +1,84 @@
1
+ require 'processors/template_processor'
2
+
3
+ #Processes ERB templates
4
+ #(those ending in .html.erb or .rthml).
5
+ class ErbTemplateProcessor < TemplateProcessor
6
+
7
+ #s(:call, TARGET, :method, s(:arglist))
8
+ def process_call exp
9
+ target = exp[1]
10
+ if sexp? target
11
+ target = process target
12
+ end
13
+ method = exp[2]
14
+
15
+ #_erbout is the default output variable for erb
16
+ if target and target[1] == :_erbout
17
+ if method == :concat
18
+ @inside_concat = true
19
+ args = exp[3] = process(exp[3])
20
+ @inside_concat = false
21
+
22
+ if args.length > 2
23
+ raise Exception.new("Did not expect more than a single argument to _erbout.concat")
24
+ end
25
+
26
+ args = args[1]
27
+
28
+ if args.node_type == :call and args[2] == :to_s #erb always calls to_s on output
29
+ args = args[1]
30
+ end
31
+
32
+ if args.node_type == :str #ignore plain strings
33
+ ignore
34
+ else
35
+ s = Sexp.new :output, args
36
+ s.line(exp.line)
37
+ @current_template[:outputs] << s
38
+ s
39
+ end
40
+ elsif method == :force_encoding
41
+ ignore
42
+ else
43
+ abort "Unrecognized action on _erbout: #{method}"
44
+ end
45
+ elsif target == nil and method == :render
46
+ exp[3] = process(exp[3])
47
+ make_render exp
48
+ else
49
+ args = exp[3] = process(exp[3])
50
+ call = Sexp.new :call, target, method, args
51
+ call.line(exp.line)
52
+ call
53
+ end
54
+ end
55
+
56
+ #Process block, removing irrelevant expressions
57
+ def process_block exp
58
+ exp.shift
59
+ if @inside_concat
60
+ @inside_concat = false
61
+ exp[0..-2].each do |e|
62
+ process e
63
+ end
64
+ @inside_concat = true
65
+ process exp[-1]
66
+ else
67
+ exp.map! do |e|
68
+ res = process e
69
+ if res.empty? or res == ignore
70
+ nil
71
+ elsif sexp? res and res.node_type == :lvar and res[1] == :_erbout
72
+ nil
73
+
74
+ else
75
+ res
76
+ end
77
+ end
78
+ block = Sexp.new(:rlist).concat(exp).compact
79
+ block.line(exp.line)
80
+ block
81
+ end
82
+ end
83
+
84
+ end
@@ -0,0 +1,62 @@
1
+ require 'processors/template_processor'
2
+
3
+ #Processes ERB templates using Erubis instead of erb.
4
+ class ErubisTemplateProcessor < TemplateProcessor
5
+
6
+ #s(:call, TARGET, :method, s(:arglist))
7
+ def process_call exp
8
+ target = exp[1]
9
+ if sexp? target
10
+ target = process target
11
+ end
12
+ method = exp[2]
13
+
14
+ #_buf is the default output variable for Erubis
15
+ if target and target[1] == :_buf
16
+ if method == :<<
17
+ args = exp[3][1] = process(exp[3][1])
18
+
19
+ if args.node_type == :call and args[2] == :to_s #just calling to_s on inner code
20
+ args = args[1]
21
+ end
22
+
23
+ if args.node_type == :str #ignore plain strings
24
+ ignore
25
+ else
26
+ s = Sexp.new :output, args
27
+ s.line(exp.line)
28
+ @current_template[:outputs] << s
29
+ s
30
+ end
31
+ elsif method == :to_s
32
+ ignore
33
+ else
34
+ abort "Unrecognized action on _buf: #{method}"
35
+ end
36
+ elsif target == nil and method == :render
37
+ exp[3] = process exp[3]
38
+ make_render exp
39
+ else
40
+ args = exp[3] = process(exp[3])
41
+ call = Sexp.new :call, target, method, args
42
+ call.line(exp.line)
43
+ call
44
+ end
45
+ end
46
+
47
+ #Process blocks, ignoring :ignore exps
48
+ def process_block exp
49
+ exp.shift
50
+ exp.map! do |e|
51
+ res = process e
52
+ if res.empty? or res == ignore
53
+ nil
54
+ else
55
+ res
56
+ end
57
+ end
58
+ block = Sexp.new(:rlist).concat(exp).compact
59
+ block.line(exp.line)
60
+ block
61
+ end
62
+ end
@@ -0,0 +1,131 @@
1
+ require 'processors/template_processor'
2
+
3
+ #Processes HAML templates.
4
+ class HamlTemplateProcessor < TemplateProcessor
5
+ HAML_FORMAT_METHOD = /format_script_(true|false)_(true|false)_(true|false)_(true|false)_(true|false)_(true|false)_(true|false)/
6
+
7
+ def initialize *args
8
+ super
9
+
10
+ @tracker.libs.each do |name, lib|
11
+ if name.to_s =~ /^Haml::Filters/
12
+ begin
13
+ require lib[:file]
14
+ rescue Exception => e
15
+ if OPTIONS[:debug]
16
+ raise e
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+
23
+ #Processes call, looking for template output
24
+ def process_call exp
25
+ target = exp[1]
26
+ if sexp? target
27
+ target = process target
28
+ end
29
+
30
+ method = exp[2]
31
+
32
+ if (sexp? target and target[2] == :_hamlout) or target == :_hamlout
33
+ res = case method
34
+ when :adjust_tabs, :rstrip!
35
+ ignore
36
+ when :options
37
+ Sexp.new :call, :_hamlout, :options, exp[3]
38
+ when :buffer
39
+ Sexp.new :call, :_hamlout, :buffer, exp[3]
40
+ when :open_tag
41
+ Sexp.new(:tag, process(exp[3]))
42
+ else
43
+ arg = exp[3][1]
44
+
45
+ if arg
46
+ @inside_concat = true
47
+ out = exp[3][1] = process(arg)
48
+ @inside_concat = false
49
+ else
50
+ raise Exception.new("Empty _hamlout.#{method}()?")
51
+ end
52
+
53
+ if string? out
54
+ ignore
55
+ else
56
+ case method.to_s
57
+ when "push_text"
58
+ s = Sexp.new(:output, out)
59
+ @current_template[:outputs] << s
60
+ s
61
+ when HAML_FORMAT_METHOD
62
+ if $4 == "true"
63
+ Sexp.new :format_escaped, out
64
+ else
65
+ Sexp.new :format, out
66
+ end
67
+ else
68
+ raise Exception.new("Unrecognized action on _hamlout: #{method}")
69
+ end
70
+ end
71
+
72
+ end
73
+
74
+ res.line(exp.line)
75
+ res
76
+
77
+ #_hamlout.buffer <<
78
+ #This seems to be used rarely, but directly appends args to output buffer
79
+ elsif sexp? target and method == :<< and is_buffer_target? target
80
+ @inside_concat = true
81
+ out = exp[3][1] = process(exp[3][1])
82
+ @inside_concat = false
83
+
84
+ if out.node_type == :str #ignore plain strings
85
+ ignore
86
+ else
87
+ s = Sexp.new(:output, out)
88
+ @current_template[:outputs] << s
89
+ s.line(exp.line)
90
+ s
91
+ end
92
+ elsif target == nil and method == :render
93
+ #Process call to render()
94
+ exp[3] = process exp[3]
95
+ make_render exp
96
+ else
97
+ args = process exp[3]
98
+ call = Sexp.new :call, target, method, args
99
+ call.line(exp.line)
100
+ call
101
+ end
102
+ end
103
+
104
+ #If inside an output stream, only return the final expression
105
+ def process_block exp
106
+ exp.shift
107
+ if @inside_concat
108
+ @inside_concat = false
109
+ exp[0..-2].each do |e|
110
+ process e
111
+ end
112
+ @inside_concat = true
113
+ process exp[-1]
114
+ else
115
+ exp.map! do |e|
116
+ res = process e
117
+ if res.empty?
118
+ nil
119
+ else
120
+ res
121
+ end
122
+ end
123
+ Sexp.new(:rlist).concat(exp).compact
124
+ end
125
+ end
126
+
127
+ #Checks if the buffer is the target in a method call Sexp.
128
+ def is_buffer_target? exp
129
+ exp.node_type == :call and exp[1] == :_hamlout and exp[2] == :buffer
130
+ end
131
+ end