brakeman 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. data/FEATURES +16 -0
  2. data/README.md +112 -0
  3. data/WARNING_TYPES +69 -0
  4. data/bin/brakeman +266 -0
  5. data/lib/checks.rb +67 -0
  6. data/lib/checks/base_check.rb +338 -0
  7. data/lib/checks/check_cross_site_scripting.rb +216 -0
  8. data/lib/checks/check_default_routes.rb +29 -0
  9. data/lib/checks/check_evaluation.rb +29 -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 +25 -0
  13. data/lib/checks/check_mass_assignment.rb +72 -0
  14. data/lib/checks/check_model_attributes.rb +36 -0
  15. data/lib/checks/check_redirect.rb +98 -0
  16. data/lib/checks/check_render.rb +65 -0
  17. data/lib/checks/check_send_file.rb +15 -0
  18. data/lib/checks/check_session_settings.rb +36 -0
  19. data/lib/checks/check_sql.rb +124 -0
  20. data/lib/checks/check_validation_regex.rb +60 -0
  21. data/lib/format/style.css +105 -0
  22. data/lib/processor.rb +83 -0
  23. data/lib/processors/alias_processor.rb +384 -0
  24. data/lib/processors/base_processor.rb +235 -0
  25. data/lib/processors/config_processor.rb +146 -0
  26. data/lib/processors/controller_alias_processor.rb +222 -0
  27. data/lib/processors/controller_processor.rb +175 -0
  28. data/lib/processors/erb_template_processor.rb +84 -0
  29. data/lib/processors/erubis_template_processor.rb +62 -0
  30. data/lib/processors/haml_template_processor.rb +115 -0
  31. data/lib/processors/lib/find_call.rb +176 -0
  32. data/lib/processors/lib/find_model_call.rb +39 -0
  33. data/lib/processors/lib/processor_helper.rb +36 -0
  34. data/lib/processors/lib/render_helper.rb +118 -0
  35. data/lib/processors/library_processor.rb +117 -0
  36. data/lib/processors/model_processor.rb +125 -0
  37. data/lib/processors/output_processor.rb +204 -0
  38. data/lib/processors/params_processor.rb +77 -0
  39. data/lib/processors/route_processor.rb +338 -0
  40. data/lib/processors/template_alias_processor.rb +86 -0
  41. data/lib/processors/template_processor.rb +55 -0
  42. data/lib/report.rb +628 -0
  43. data/lib/scanner.rb +232 -0
  44. data/lib/tracker.rb +144 -0
  45. data/lib/util.rb +141 -0
  46. data/lib/warning.rb +97 -0
  47. metadata +191 -0
@@ -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,115 @@
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
+ #Processes call, looking for template output
8
+ def process_call exp
9
+ target = exp[1]
10
+ if sexp? target
11
+ target = process target
12
+ end
13
+
14
+ method = exp[2]
15
+
16
+ if (sexp? target and target[2] == :_hamlout) or target == :_hamlout
17
+ res = case method
18
+ when :adjust_tabs, :rstrip!
19
+ ignore
20
+ when :options
21
+ Sexp.new :call, :_hamlout, :options, exp[3]
22
+ when :buffer
23
+ Sexp.new :call, :_hamlout, :buffer, exp[3]
24
+ when :open_tag
25
+ Sexp.new(:tag, process(exp[3]))
26
+ else
27
+ arg = exp[3][1]
28
+
29
+ if arg
30
+ @inside_concat = true
31
+ out = exp[3][1] = process(arg)
32
+ @inside_concat = false
33
+ else
34
+ raise Exception.new("Empty _hamlout.#{method}()?")
35
+ end
36
+
37
+ if string? out
38
+ ignore
39
+ else
40
+ case method.to_s
41
+ when "push_text"
42
+ s = Sexp.new(:output, out)
43
+ @current_template[:outputs] << s
44
+ s
45
+ when HAML_FORMAT_METHOD
46
+ if $4 == "true"
47
+ Sexp.new :format_escaped, out
48
+ else
49
+ Sexp.new :format, out
50
+ end
51
+ else
52
+ raise Exception.new("Unrecognized action on _hamlout: #{method}")
53
+ end
54
+ end
55
+
56
+ end
57
+
58
+ res.line(exp.line)
59
+ res
60
+
61
+ #_hamlout.buffer <<
62
+ #This seems to be used rarely, but directly appends args to output buffer
63
+ elsif sexp? target and method == :<< and is_buffer_target? target
64
+ @inside_concat = true
65
+ out = exp[3][1] = process(exp[3][1])
66
+ @inside_concat = false
67
+
68
+ if out.node_type == :str #ignore plain strings
69
+ ignore
70
+ else
71
+ s = Sexp.new(:output, out)
72
+ @current_template[:outputs] << s
73
+ s.line(exp.line)
74
+ s
75
+ end
76
+ elsif target == nil and method == :render
77
+ #Process call to render()
78
+ exp[3] = process exp[3]
79
+ make_render exp
80
+ else
81
+ args = process exp[3]
82
+ call = Sexp.new :call, target, method, args
83
+ call.line(exp.line)
84
+ call
85
+ end
86
+ end
87
+
88
+ #If inside an output stream, only return the final expression
89
+ def process_block exp
90
+ exp.shift
91
+ if @inside_concat
92
+ @inside_concat = false
93
+ exp[0..-2].each do |e|
94
+ process e
95
+ end
96
+ @inside_concat = true
97
+ process exp[-1]
98
+ else
99
+ exp.map! do |e|
100
+ res = process e
101
+ if res.empty?
102
+ nil
103
+ else
104
+ res
105
+ end
106
+ end
107
+ Sexp.new(:rlist).concat(exp).compact
108
+ end
109
+ end
110
+
111
+ #Checks if the buffer is the target in a method call Sexp.
112
+ def is_buffer_target? exp
113
+ exp.node_type == :call and exp[1] == :_hamlout and exp[2] == :buffer
114
+ end
115
+ end
@@ -0,0 +1,176 @@
1
+ require 'processors/base_processor'
2
+
3
+ #Finds method calls matching the given target(s).
4
+ #
5
+ #Targets/methods can be:
6
+ #
7
+ # - nil: matches anything, including nothing
8
+ # - Empty array: matches nothing
9
+ # - Symbol: matches single target/method exactly
10
+ # - Array of symbols: matches against any of the symbols
11
+ # - Regular expression: matches the expression
12
+ # - Array of regular expressions: matches any of the expressions
13
+ #
14
+ #If a target is also the name of a class, methods called on instances
15
+ #of that class will also be matched, in a very limited way.
16
+ #(Any methods called on Klass.new, basically. More useful when used
17
+ #in conjunction with AliasProcessor.)
18
+ #
19
+ #Examples:
20
+ #
21
+ # #To find any uses of this class:
22
+ # FindCall.new :FindCall, nil
23
+ #
24
+ # #Find system calls without a target
25
+ # FindCall.new [], [:system, :exec, :syscall]
26
+ #
27
+ # #Find all calls to length(), no matter the target
28
+ # FindCall.new nil, :length
29
+ #
30
+ # #Find all calls to sub, sub!, gsub, or gsub!
31
+ # FindCall.new nil, /^g?sub!?$/
32
+ class FindCall < BaseProcessor
33
+
34
+ def initialize targets, methods
35
+ super(nil)
36
+ @calls = []
37
+ @find_targets = targets
38
+ @find_methods = methods
39
+ @current_class = nil
40
+ @current_method = nil
41
+ end
42
+
43
+ #Returns a list of results.
44
+ #
45
+ #A result looks like:
46
+ #
47
+ # s(:result, :ClassName, :method_name, s(:call, ...))
48
+ #
49
+ #or
50
+ #
51
+ # s(:result, :template_name, s(:call, ...))
52
+ def matches
53
+ @calls
54
+ end
55
+
56
+ #Process the given source. Provide either class and method being searched
57
+ #or the template. These names are used when reporting results.
58
+ #
59
+ #Use FindCall#matches to retrieve results.
60
+ def process_source exp, klass = nil, method = nil, template = nil
61
+ @current_class = klass
62
+ @current_method = method
63
+ @current_template = template
64
+ process exp
65
+ end
66
+
67
+ #Process body of method
68
+ def process_methdef exp
69
+ process exp[3]
70
+ end
71
+
72
+ #Process body of method
73
+ def process_selfdef exp
74
+ process exp[4]
75
+ end
76
+
77
+ #Process body of block
78
+ def process_rlist exp
79
+ exp[1..-1].each do |e|
80
+ process e
81
+ end
82
+
83
+ exp
84
+ end
85
+
86
+ #Look for matching calls and add them to results
87
+ def process_call exp
88
+ target = get_target exp[1]
89
+ method = exp[2]
90
+
91
+ process exp[3]
92
+
93
+ if match(@find_targets, target) and match(@find_methods, method)
94
+
95
+ if @current_template
96
+ @calls << Sexp.new(:result, @current_template, exp).line(exp.line)
97
+ else
98
+ @calls << Sexp.new(:result, @current_class, @current_method, exp).line(exp.line)
99
+ end
100
+ end
101
+
102
+ exp
103
+ end
104
+
105
+ #Process an assignment like a call
106
+ def process_attrasgn exp
107
+ process_call exp
108
+ end
109
+
110
+ private
111
+
112
+ #Gets the target of a call as a Symbol
113
+ #if possible
114
+ def get_target exp
115
+ if sexp? exp
116
+ case exp.node_type
117
+ when :ivar, :lvar, :const
118
+ exp[1]
119
+ when :true, :false
120
+ exp[0]
121
+ when :lit
122
+ exp[1]
123
+ when :colon2
124
+ class_name exp
125
+ else
126
+ exp
127
+ end
128
+ else
129
+ exp
130
+ end
131
+ end
132
+
133
+ #Checks if the search terms match the given item
134
+ def match search_terms, item
135
+ case search_terms
136
+ when Symbol
137
+ if search_terms == item
138
+ true
139
+ elsif sexp? item
140
+ is_instance_of? item, search_terms
141
+ else
142
+ false
143
+ end
144
+ when Enumerable
145
+ if search_terms.empty?
146
+ item == nil
147
+ else
148
+ search_terms.each do|term|
149
+ if match(term, item)
150
+ return true
151
+ end
152
+ end
153
+ false
154
+ end
155
+ when Regexp
156
+ search_terms.match item.to_s
157
+ when nil
158
+ true
159
+ else
160
+ raise "Cannot match #{search_terms} and #{item}"
161
+ end
162
+ end
163
+
164
+ #Checks if +item+ is an instance of +klass+ by looking for Klass.new
165
+ def is_instance_of? item, klass
166
+ if call? item
167
+ if sexp? item[1]
168
+ item[2] == :new and item[1].node_type == :const and item[1][1] == klass
169
+ else
170
+ item[2] == :new and item[1] == klass
171
+ end
172
+ else
173
+ false
174
+ end
175
+ end
176
+ end
@@ -0,0 +1,39 @@
1
+ require 'processors/lib/find_call'
2
+
3
+ #This processor specifically looks for calls like
4
+ # User.active.human.find(:all, :conditions => ...)
5
+ class FindModelCall < FindCall
6
+
7
+ #Passes +targets+ to FindCall
8
+ def initialize targets
9
+ super(targets, /^(find.*|first|last|all)$/)
10
+ end
11
+
12
+ #Matches entire method chain as a target. This differs from
13
+ #FindCall#get_target, which only matches the first expression in the chain.
14
+ def get_target exp
15
+ if sexp? exp
16
+ case exp.node_type
17
+ when :ivar, :lvar, :const
18
+ exp[1]
19
+ when :true, :false
20
+ exp[0]
21
+ when :lit
22
+ exp[1]
23
+ when :colon2
24
+ class_name exp
25
+ when :call
26
+ t = get_target(exp[1])
27
+ if t and match(@find_targets, t)
28
+ t
29
+ else
30
+ process exp
31
+ end
32
+ else
33
+ process exp
34
+ end
35
+ else
36
+ exp
37
+ end
38
+ end
39
+ end