brakeman-min 4.3.1 → 4.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (95) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES.md +24 -1
  3. data/README.md +35 -6
  4. data/bin/brakeman +2 -0
  5. data/lib/brakeman.rb +5 -3
  6. data/lib/brakeman/app_tree.rb +15 -1
  7. data/lib/brakeman/call_index.rb +7 -4
  8. data/lib/brakeman/checks.rb +16 -8
  9. data/lib/brakeman/checks/base_check.rb +2 -19
  10. data/lib/brakeman/checks/check_basic_auth_timing_attack.rb +1 -1
  11. data/lib/brakeman/checks/check_content_tag.rb +4 -4
  12. data/lib/brakeman/checks/check_create_with.rb +1 -1
  13. data/lib/brakeman/checks/check_cross_site_scripting.rb +3 -3
  14. data/lib/brakeman/checks/check_default_routes.rb +3 -3
  15. data/lib/brakeman/checks/check_deserialize.rb +1 -1
  16. data/lib/brakeman/checks/check_detailed_exceptions.rb +1 -1
  17. data/lib/brakeman/checks/check_digest_dos.rb +4 -4
  18. data/lib/brakeman/checks/check_escape_function.rb +1 -1
  19. data/lib/brakeman/checks/check_execute.rb +5 -4
  20. data/lib/brakeman/checks/check_file_access.rb +13 -3
  21. data/lib/brakeman/checks/check_file_disclosure.rb +1 -1
  22. data/lib/brakeman/checks/check_filter_skipping.rb +1 -1
  23. data/lib/brakeman/checks/check_forgery_setting.rb +3 -3
  24. data/lib/brakeman/checks/check_header_dos.rb +3 -3
  25. data/lib/brakeman/checks/check_i18n_xss.rb +3 -3
  26. data/lib/brakeman/checks/check_jruby_xml.rb +1 -1
  27. data/lib/brakeman/checks/check_json_encoding.rb +3 -3
  28. data/lib/brakeman/checks/check_json_parsing.rb +8 -11
  29. data/lib/brakeman/checks/check_link_to.rb +3 -3
  30. data/lib/brakeman/checks/check_link_to_href.rb +2 -2
  31. data/lib/brakeman/checks/check_mail_to.rb +3 -3
  32. data/lib/brakeman/checks/check_mime_type_dos.rb +1 -1
  33. data/lib/brakeman/checks/check_model_attributes.rb +4 -4
  34. data/lib/brakeman/checks/check_model_serialize.rb +1 -1
  35. data/lib/brakeman/checks/check_nested_attributes.rb +3 -3
  36. data/lib/brakeman/checks/check_nested_attributes_bypass.rb +1 -1
  37. data/lib/brakeman/checks/check_number_to_currency.rb +4 -4
  38. data/lib/brakeman/checks/check_quote_table_name.rb +2 -2
  39. data/lib/brakeman/checks/check_regex_dos.rb +1 -1
  40. data/lib/brakeman/checks/check_render.rb +2 -2
  41. data/lib/brakeman/checks/check_render_dos.rb +1 -1
  42. data/lib/brakeman/checks/check_render_inline.rb +1 -1
  43. data/lib/brakeman/checks/check_response_splitting.rb +1 -1
  44. data/lib/brakeman/checks/check_route_dos.rb +1 -1
  45. data/lib/brakeman/checks/check_safe_buffer_manipulation.rb +1 -1
  46. data/lib/brakeman/checks/check_sanitize_methods.rb +3 -3
  47. data/lib/brakeman/checks/check_secrets.rb +1 -1
  48. data/lib/brakeman/checks/check_select_tag.rb +1 -1
  49. data/lib/brakeman/checks/check_select_vulnerability.rb +1 -1
  50. data/lib/brakeman/checks/check_session_manipulation.rb +1 -1
  51. data/lib/brakeman/checks/check_session_settings.rb +1 -1
  52. data/lib/brakeman/checks/check_simple_format.rb +2 -2
  53. data/lib/brakeman/checks/check_single_quotes.rb +14 -10
  54. data/lib/brakeman/checks/check_skip_before_filter.rb +2 -2
  55. data/lib/brakeman/checks/check_sprockets_path_traversal.rb +39 -0
  56. data/lib/brakeman/checks/check_sql.rb +1 -1
  57. data/lib/brakeman/checks/check_sql_cves.rb +2 -2
  58. data/lib/brakeman/checks/check_strip_tags.rb +10 -8
  59. data/lib/brakeman/checks/check_symbol_dos.rb +1 -1
  60. data/lib/brakeman/checks/check_symbol_dos_cve.rb +1 -1
  61. data/lib/brakeman/checks/check_translate_bug.rb +7 -7
  62. data/lib/brakeman/checks/check_unsafe_reflection.rb +1 -1
  63. data/lib/brakeman/checks/check_unscoped_find.rb +1 -1
  64. data/lib/brakeman/checks/check_validation_regex.rb +1 -1
  65. data/lib/brakeman/checks/check_weak_hash.rb +18 -19
  66. data/lib/brakeman/checks/check_xml_dos.rb +1 -1
  67. data/lib/brakeman/checks/check_yaml_parsing.rb +1 -1
  68. data/lib/brakeman/format/style.css +8 -0
  69. data/lib/brakeman/messages.rb +220 -0
  70. data/lib/brakeman/options.rb +13 -0
  71. data/lib/brakeman/parsers/template_parser.rb +2 -2
  72. data/lib/brakeman/processors/alias_processor.rb +7 -0
  73. data/lib/brakeman/processors/config_processor.rb +4 -1
  74. data/lib/brakeman/processors/gem_processor.rb +30 -2
  75. data/lib/brakeman/processors/lib/call_conversion_helper.rb +2 -1
  76. data/lib/brakeman/processors/lib/rails3_route_processor.rb +0 -2
  77. data/lib/brakeman/processors/lib/rails4_config_processor.rb +18 -0
  78. data/lib/brakeman/processors/lib/render_helper.rb +5 -0
  79. data/lib/brakeman/processors/lib/render_path.rb +15 -0
  80. data/lib/brakeman/processors/library_processor.rb +1 -1
  81. data/lib/brakeman/report/report_base.rb +17 -161
  82. data/lib/brakeman/report/report_csv.rb +17 -0
  83. data/lib/brakeman/report/report_html.rb +34 -31
  84. data/lib/brakeman/report/report_json.rb +21 -0
  85. data/lib/brakeman/report/report_markdown.rb +13 -6
  86. data/lib/brakeman/report/report_table.rb +157 -0
  87. data/lib/brakeman/report/report_tabs.rb +3 -1
  88. data/lib/brakeman/report/report_text.rb +16 -0
  89. data/lib/brakeman/scanner.rb +5 -1
  90. data/lib/brakeman/tracker/config.rb +1 -1
  91. data/lib/brakeman/util.rb +0 -17
  92. data/lib/brakeman/version.rb +1 -1
  93. data/lib/brakeman/warning.rb +9 -4
  94. data/lib/brakeman/warning_codes.rb +1 -0
  95. metadata +9 -6
@@ -13,7 +13,7 @@ class Brakeman::LibraryProcessor < Brakeman::BaseProcessor
13
13
  @alias_processor = Brakeman::AliasProcessor.new tracker
14
14
  @current_module = nil
15
15
  @current_class = nil
16
- @intializer_env = nil
16
+ @initializer_env = nil
17
17
  end
18
18
 
19
19
  def process_library src, file_name = nil
@@ -22,18 +22,25 @@ class Brakeman::Report::Base
22
22
  @warnings_summary = nil
23
23
  end
24
24
 
25
- #Generate table of how many warnings of each warning type were reported
26
- def generate_warning_overview
27
- types = warnings_summary.keys
28
- types.delete :high_confidence
29
- values = types.sort.collect{|warning_type| [warning_type, warnings_summary[warning_type]] }
30
- locals = {:types => types, :warnings_summary => warnings_summary}
25
+ #Return summary of warnings in hash and store in @warnings_summary
26
+ def warnings_summary
27
+ return @warnings_summary if @warnings_summary
28
+
29
+ summary = Hash.new(0)
30
+ high_confidence_warnings = 0
31
+
32
+ [all_warnings].each do |warnings|
33
+ warnings.each do |warning|
34
+ summary[warning.warning_type.to_s] += 1
35
+ high_confidence_warnings += 1 if warning.confidence == 0
36
+ end
37
+ end
31
38
 
32
- render_array('warning_overview', ['Warning Type', 'Total'], values, locals)
39
+ summary[:high_confidence] = high_confidence_warnings
40
+ @warnings_summary = summary
33
41
  end
34
42
 
35
- #Generate table of controllers and routes found for those controllers
36
- def generate_controllers
43
+ def controller_information
37
44
  controller_rows = []
38
45
 
39
46
  tracker.controllers.keys.map{|k| k.to_s}.sort.each do |name|
@@ -67,148 +74,7 @@ class Brakeman::Report::Base
67
74
  }
68
75
  end
69
76
 
70
- cols = ['Name', 'Parent', 'Includes', 'Routes']
71
-
72
- locals = {:controller_rows => controller_rows}
73
- values = controller_rows.collect{|row| row.values_at(*cols) }
74
- render_array('controller_overview', cols, values, locals)
75
- end
76
-
77
- #Generate table of errors or return nil if no errors
78
- def generate_errors
79
- values = tracker.errors.collect{|error| [error[:error], error[:backtrace][0]]}
80
- render_array('error_overview', ['Error', 'Location'], values, {:tracker => tracker})
81
- end
82
-
83
- def generate_obsolete
84
- values = tracker.unused_fingerprints.collect{|fingerprint| [fingerprint] }
85
- render_array('obsolete_ignore_entries', ['fingerprint'], values, {:tracker => tracker})
86
- end
87
-
88
- def generate_warnings
89
- render_warnings generic_warnings,
90
- :warning,
91
- 'security_warnings',
92
- ["Confidence", "Class", "Method", "Warning Type", "Message"],
93
- 'Class'
94
- end
95
-
96
- #Generate table of template warnings or return nil if no warnings
97
- def generate_template_warnings
98
- render_warnings template_warnings,
99
- :template,
100
- 'view_warnings',
101
- ['Confidence', 'Template', 'Warning Type', 'Message'],
102
- 'Template'
103
-
104
- end
105
-
106
- #Generate table of model warnings or return nil if no warnings
107
- def generate_model_warnings
108
- render_warnings model_warnings,
109
- :model,
110
- 'model_warnings',
111
- ['Confidence', 'Model', 'Warning Type', 'Message'],
112
- 'Model'
113
- end
114
-
115
- #Generate table of controller warnings or nil if no warnings
116
- def generate_controller_warnings
117
- render_warnings controller_warnings,
118
- :controller,
119
- 'controller_warnings',
120
- ['Confidence', 'Controller', 'Warning Type', 'Message'],
121
- 'Controller'
122
- end
123
-
124
- def generate_ignored_warnings
125
- render_warnings ignored_warnings,
126
- :ignored,
127
- 'ignored_warnings',
128
- ['Confidence', 'Warning Type', 'File', 'Message'],
129
- 'Warning Type'
130
- end
131
-
132
- def render_warnings warnings, type, template, cols, sort_col
133
- unless warnings.empty?
134
- rows = sort(convert_to_rows(warnings, type), sort_col)
135
-
136
- values = rows.collect { |row| row.values_at(*cols) }
137
-
138
- locals = { :warnings => rows }
139
-
140
- render_array(template, cols, values, locals)
141
- else
142
- nil
143
- end
144
- end
145
-
146
- def convert_to_rows warnings, type = :warning
147
- warnings.map do |warning|
148
- w = warning.to_row type
149
-
150
- case type
151
- when :warning
152
- convert_warning w, warning
153
- when :template
154
- convert_template_warning w, warning
155
- when :model
156
- convert_model_warning w, warning
157
- when :controller
158
- convert_controller_warning w, warning
159
- when :ignored
160
- convert_ignored_warning w, warning
161
- end
162
- end
163
- end
164
-
165
- def convert_warning warning, original
166
- warning["Confidence"] = TEXT_CONFIDENCE[warning["Confidence"]]
167
- warning["Message"] = text_message original, warning["Message"]
168
- warning
169
- end
170
-
171
- def convert_template_warning warning, original
172
- convert_warning warning, original
173
- end
174
-
175
- def convert_model_warning warning, original
176
- convert_warning warning, original
177
- end
178
-
179
- def convert_controller_warning warning, original
180
- convert_warning warning, original
181
- end
182
-
183
- def convert_ignored_warning warning, original
184
- convert_warning warning, original
185
- end
186
-
187
- def sort rows, sort_col
188
- stabilizer = 0
189
- rows.sort_by do |row|
190
- stabilizer += 1
191
-
192
- row.values_at("Confidence", "Warning Type", sort_col) << stabilizer
193
- end
194
- end
195
-
196
- #Return summary of warnings in hash and store in @warnings_summary
197
- def warnings_summary
198
- return @warnings_summary if @warnings_summary
199
-
200
- summary = Hash.new(0)
201
- high_confidence_warnings = 0
202
-
203
- [all_warnings].each do |warnings|
204
- warnings.each do |warning|
205
- summary[warning.warning_type.to_s] += 1
206
- high_confidence_warnings += 1 if warning.confidence == 0
207
- end
208
- end
209
-
210
- summary[:high_confidence] = high_confidence_warnings
211
- @warnings_summary = summary
77
+ controller_rows
212
78
  end
213
79
 
214
80
  def all_warnings
@@ -279,14 +145,4 @@ class Brakeman::Report::Base
279
145
  "Unknown"
280
146
  end
281
147
  end
282
-
283
- #Escape warning message and highlight user input in text output
284
- def text_message warning, message
285
- if @highlight_user_input and warning.user_input
286
- user_input = warning.format_user_input
287
- message.gsub(user_input, "+#{user_input}+")
288
- else
289
- message
290
- end
291
- end
292
148
  end
@@ -52,4 +52,21 @@ class Brakeman::Report::CSV < Brakeman::Report::Table
52
52
  header << CSV.generate_line([File.expand_path(tracker.app_path), Time.now.to_s, checks.checks_run.sort.join(", "), rails_version])
53
53
  "BRAKEMAN REPORT\n\n" + header
54
54
  end
55
+
56
+ # rely on Terminal::Table to build the structure, extract the data out in CSV format
57
+ def table_to_csv table
58
+ return "" unless table
59
+
60
+ Brakeman.load_brakeman_dependency 'terminal-table'
61
+ headings = table.headings
62
+ if headings.is_a? Array
63
+ headings = headings.first
64
+ end
65
+
66
+ output = CSV.generate_line(headings.cells.map{|cell| cell.to_s.strip})
67
+ table.rows.each do |row|
68
+ output << CSV.generate_line(row.cells.map{|cell| cell.to_s.strip})
69
+ end
70
+ output
71
+ end
55
72
  end
@@ -1,9 +1,10 @@
1
1
  require 'cgi'
2
+ require 'brakeman/report/report_table.rb'
2
3
 
3
- class Brakeman::Report::HTML < Brakeman::Report::Base
4
+ class Brakeman::Report::HTML < Brakeman::Report::Table
4
5
  HTML_CONFIDENCE = [ "<span class='high-confidence'>High</span>",
5
- "<span class='med-confidence'>Medium</span>",
6
- "<span class='weak-confidence'>Weak</span>" ]
6
+ "<span class='med-confidence'>Medium</span>",
7
+ "<span class='weak-confidence'>Weak</span>" ]
7
8
 
8
9
  def initialize *args
9
10
  super
@@ -66,20 +67,18 @@ class Brakeman::Report::HTML < Brakeman::Report::Base
66
67
  end
67
68
 
68
69
  def convert_warning warning, original
69
- warning["Confidence"] = HTML_CONFIDENCE[warning["Confidence"]]
70
+ warning["Confidence"] = HTML_CONFIDENCE[original.confidence]
70
71
  warning["Message"] = with_context original, warning["Message"]
71
72
  warning["Warning Type"] = with_link original, warning["Warning Type"]
72
73
  warning
73
74
  end
74
75
 
75
76
  def with_link warning, message
76
- "<a rel=\"no-referrer\" href=\"#{warning.link}\">#{message}</a>"
77
+ "<a rel=\"noreferrer\" href=\"#{warning.link}\">#{message}</a>"
77
78
  end
78
79
 
79
80
  def convert_template_warning warning, original
80
- warning["Confidence"] = HTML_CONFIDENCE[warning["Confidence"]]
81
- warning["Message"] = with_context original, warning["Message"]
82
- warning["Warning Type"] = with_link original, warning["Warning Type"]
81
+ warning = convert_warning warning, original
83
82
  warning["Called From"] = original.called_from
84
83
  warning["Template Name"] = original.template.name
85
84
  warning
@@ -113,29 +112,16 @@ class Brakeman::Report::HTML < Brakeman::Report::Base
113
112
 
114
113
  #Generate HTML for warnings, including context show/hidden via Javascript
115
114
  def with_context warning, message
115
+ @element_id += 1
116
116
  context = context_for(@app_tree, warning)
117
- full_message = nil
118
-
119
- if tracker.options[:message_limit] and tracker.options[:message_limit] > 0 and message.length > tracker.options[:message_limit]
120
- full_message = html_message(warning, message)
121
- message = message[0..tracker.options[:message_limit]] << "..."
122
- end
123
-
124
117
  message = html_message(warning, message)
125
- return message if context.empty? and not full_message
126
118
 
127
- @element_id += 1
128
119
  code_id = "context#@element_id"
129
120
  message_id = "message#@element_id"
130
121
  full_message_id = "full_message#@element_id"
131
122
  alt = false
132
123
  output = "<div class='warning_message' onClick=\"toggle('#{code_id}');toggle('#{message_id}');toggle('#{full_message_id}')\" >" <<
133
- if full_message
134
- "<span id='#{message_id}' style='display:block' >#{message}</span>" <<
135
- "<span id='#{full_message_id}' style='display:none'>#{full_message}</span>"
136
- else
137
- message
138
- end <<
124
+ message <<
139
125
  "<table id='#{code_id}' class='context' style='display:none'>" <<
140
126
  "<caption>#{CGI.escapeHTML warning_file(warning) || ''}</caption>"
141
127
 
@@ -199,18 +185,35 @@ class Brakeman::Report::HTML < Brakeman::Report::Base
199
185
 
200
186
  #Escape warning message and highlight user input in HTML output
201
187
  def html_message warning, message
202
- message = CGI.escapeHTML(message)
188
+ message = message.to_html
203
189
 
204
190
  if warning.file
205
- github_url = github_url warning.file, warning.line
206
- message.gsub!(/(near line \d+)/, "<a href=\"#{github_url}\" target='_blank'>\\1</a>") if github_url
191
+ if github_url = github_url(warning.file, warning.line)
192
+ message << " <a href=\"#{github_url}\" target='_blank'>near line #{warning.line}</a>"
193
+ elsif warning.line
194
+ message << " near line #{warning.line}"
195
+ end
207
196
  end
208
197
 
209
- if @highlight_user_input and warning.user_input
210
- user_input = CGI.escapeHTML(warning.format_user_input)
211
- message.gsub!(user_input, "<span class=\"user_input\">#{user_input}</span>")
212
- end
198
+ if warning.code
199
+ code = warning.format_with_user_input do |_, user_input|
200
+ "[BMP_UI]#{user_input}[/BMP_UI]"
201
+ end
202
+
203
+ code = "<span class=\"code\">#{CGI.escapeHTML(code).gsub("[BMP_UI]", "<span class=\"user_input\">").gsub("[/BMP_UI]", "</span>")}</span>"
204
+ full_message = "#{message}: #{code}"
213
205
 
214
- message
206
+ if warning.code.mass > 20
207
+ message_id = "message#@element_id"
208
+ full_message_id = "full_message#@element_id"
209
+
210
+ "<span id='#{message_id}' style='display:block'>#{message}: ...</span>" <<
211
+ "<span id='#{full_message_id}' style='display:none'>#{full_message}</span>"
212
+ else
213
+ full_message
214
+ end
215
+ else
216
+ message
217
+ end
215
218
  end
216
219
  end
@@ -38,8 +38,29 @@ class Brakeman::Report::JSON < Brakeman::Report::Base
38
38
  def convert_to_hashes warnings
39
39
  warnings.map do |w|
40
40
  hash = w.to_hash
41
+ hash[:render_path] = convert_render_path hash[:render_path]
41
42
  hash[:file] = warning_file w
43
+
42
44
  hash
43
45
  end.sort_by { |w| "#{w[:fingerprint]}#{w[:line]}" }
44
46
  end
47
+
48
+ def convert_render_path render_path
49
+ return unless render_path and not @tracker.options[:absolute_paths]
50
+
51
+ render_path.map do |r|
52
+ r = r.dup
53
+
54
+ if r[:file]
55
+ r[:file] = relative_path(r[:file])
56
+ end
57
+
58
+ if r[:rendered] and r[:rendered][:file]
59
+ r[:rendered] = r[:rendered].dup
60
+ r[:rendered][:file] = relative_path(r[:rendered][:file])
61
+ end
62
+
63
+ r
64
+ end
65
+ end
45
66
  end
@@ -92,16 +92,23 @@ class Brakeman::Report::Markdown < Brakeman::Report::Table
92
92
 
93
93
  # Escape and code format warning message
94
94
  def markdown_message warning, message
95
+ message = message.to_s
96
+
95
97
  if warning.file
96
98
  github_url = github_url warning.file, warning.line
97
- message.gsub!(/(near line \d+)/, "[\\1](#{github_url})") if github_url
99
+
100
+ if github_url
101
+ message << " near line [#{warning.line}](#{github_url})"
102
+ elsif warning.line
103
+ message << " near line #{warning.line}"
104
+ end
98
105
  end
106
+
99
107
  if warning.code
100
- code = warning.format_code
101
- message.gsub(code, "`#{code.gsub('`','``').gsub(/\A``|``\z/, '` `')}`")
102
- else
103
- message
108
+ code = warning.format_code.gsub('`','``').gsub(/\A``|``\z/, '` `')
109
+ message << ": `#{code}`"
104
110
  end
105
- end
106
111
 
112
+ message
113
+ end
107
114
  end
@@ -62,6 +62,96 @@ class Brakeman::Report::Table < Brakeman::Report::Base
62
62
  end
63
63
  end
64
64
 
65
+ #Generate table of how many warnings of each warning type were reported
66
+ def generate_warning_overview
67
+ types = warnings_summary.keys
68
+ types.delete :high_confidence
69
+ values = types.sort.collect{|warning_type| [warning_type, warnings_summary[warning_type]] }
70
+ locals = {:types => types, :warnings_summary => warnings_summary}
71
+
72
+ render_array('warning_overview', ['Warning Type', 'Total'], values, locals)
73
+ end
74
+
75
+ #Generate table of controllers and routes found for those controllers
76
+ def generate_controllers
77
+ controller_rows = controller_information
78
+
79
+ cols = ['Name', 'Parent', 'Includes', 'Routes']
80
+
81
+ locals = {:controller_rows => controller_rows}
82
+ values = controller_rows.collect{|row| row.values_at(*cols) }
83
+ render_array('controller_overview', cols, values, locals)
84
+ end
85
+
86
+ #Generate table of errors or return nil if no errors
87
+ def generate_errors
88
+ values = tracker.errors.collect{|error| [error[:error], error[:backtrace][0]]}
89
+ render_array('error_overview', ['Error', 'Location'], values, {:tracker => tracker})
90
+ end
91
+
92
+ def generate_obsolete
93
+ values = tracker.unused_fingerprints.collect{|fingerprint| [fingerprint] }
94
+ render_array('obsolete_ignore_entries', ['fingerprint'], values, {:tracker => tracker})
95
+ end
96
+
97
+ def generate_warnings
98
+ render_warnings generic_warnings,
99
+ :warning,
100
+ 'security_warnings',
101
+ ["Confidence", "Class", "Method", "Warning Type", "Message"],
102
+ 'Class'
103
+ end
104
+
105
+ #Generate table of template warnings or return nil if no warnings
106
+ def generate_template_warnings
107
+ render_warnings template_warnings,
108
+ :template,
109
+ 'view_warnings',
110
+ ['Confidence', 'Template', 'Warning Type', 'Message'],
111
+ 'Template'
112
+
113
+ end
114
+
115
+ #Generate table of model warnings or return nil if no warnings
116
+ def generate_model_warnings
117
+ render_warnings model_warnings,
118
+ :model,
119
+ 'model_warnings',
120
+ ['Confidence', 'Model', 'Warning Type', 'Message'],
121
+ 'Model'
122
+ end
123
+
124
+ #Generate table of controller warnings or nil if no warnings
125
+ def generate_controller_warnings
126
+ render_warnings controller_warnings,
127
+ :controller,
128
+ 'controller_warnings',
129
+ ['Confidence', 'Controller', 'Warning Type', 'Message'],
130
+ 'Controller'
131
+ end
132
+
133
+ def generate_ignored_warnings
134
+ render_warnings ignored_warnings,
135
+ :ignored,
136
+ 'ignored_warnings',
137
+ ['Confidence', 'Warning Type', 'File', 'Message'],
138
+ 'Warning Type'
139
+ end
140
+
141
+ def render_warnings warnings, type, template, cols, sort_col
142
+ unless warnings.empty?
143
+ rows = sort(convert_to_rows(warnings, type), sort_col)
144
+
145
+ values = rows.collect { |row| row.values_at(*cols) }
146
+
147
+ locals = { :warnings => rows }
148
+
149
+ render_array(template, cols, values, locals)
150
+ else
151
+ nil
152
+ end
153
+ end
154
+
65
155
  #Generate listings of templates and their output
66
156
  def generate_templates
67
157
  out_processor = Brakeman::OutputProcessor.new
@@ -92,6 +182,44 @@ class Brakeman::Report::Table < Brakeman::Report::Base
92
182
  output
93
183
  end
94
184
 
185
+ def convert_to_rows warnings, type = :warning
186
+ warnings.map do |warning|
187
+ w = warning.to_row type
188
+
189
+ case type
190
+ when :warning
191
+ convert_warning w, warning
192
+ when :ignored
193
+ convert_ignored_warning w, warning
194
+ when :template
195
+ convert_template_warning w, warning
196
+ else
197
+ convert_warning w, warning
198
+ end
199
+ end
200
+ end
201
+
202
+ def convert_warning warning, original
203
+ warning
204
+ end
205
+
206
+ def convert_ignored_warning warning, original
207
+ convert_warning warning, original
208
+ end
209
+
210
+ def convert_template_warning warning, original
211
+ convert_warning warning, original
212
+ end
213
+
214
+ def sort rows, sort_col
215
+ stabilizer = 0
216
+ rows.sort_by do |row|
217
+ stabilizer += 1
218
+
219
+ row.values_at("Confidence", "Warning Type", sort_col) << stabilizer
220
+ end
221
+ end
222
+
95
223
  def render_array template, headings, value_array, locals
96
224
  return if value_array.empty?
97
225
 
@@ -100,6 +228,35 @@ class Brakeman::Report::Table < Brakeman::Report::Base
100
228
  end
101
229
  end
102
230
 
231
+ def convert_warning warning, original
232
+ warning["Message"] = text_message original, warning["Message"]
233
+
234
+ warning
235
+ end
236
+
237
+ #Escape warning message and highlight user input in text output
238
+ def text_message warning, message
239
+ message = message.to_s
240
+
241
+ if warning.line
242
+ message << " near line #{warning.line}"
243
+ end
244
+
245
+ if warning.code
246
+ if @highlight_user_input and warning.user_input
247
+ code = warning.format_with_user_input do |user_input, user_input_string|
248
+ "+#{user_input_string}+"
249
+ end
250
+ else
251
+ code = warning.format_code
252
+ end
253
+
254
+ message << ": #{code}"
255
+ end
256
+
257
+ message
258
+ end
259
+
103
260
  #Generate header for text output
104
261
  def text_header
105
262
  <<-HEADER