brakeman-lib 4.4.0 → 4.7.0

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 (97) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES.md +63 -0
  3. data/README.md +6 -7
  4. data/lib/brakeman.rb +7 -0
  5. data/lib/brakeman/app_tree.rb +34 -22
  6. data/lib/brakeman/call_index.rb +54 -15
  7. data/lib/brakeman/checks.rb +7 -7
  8. data/lib/brakeman/checks/base_check.rb +75 -56
  9. data/lib/brakeman/checks/check_content_tag.rb +12 -0
  10. data/lib/brakeman/checks/check_cookie_serialization.rb +22 -0
  11. data/lib/brakeman/checks/check_cross_site_scripting.rb +15 -10
  12. data/lib/brakeman/checks/check_default_routes.rb +5 -0
  13. data/lib/brakeman/checks/check_deserialize.rb +49 -0
  14. data/lib/brakeman/checks/check_dynamic_finders.rb +1 -1
  15. data/lib/brakeman/checks/check_evaluation.rb +0 -1
  16. data/lib/brakeman/checks/check_execute.rb +44 -1
  17. data/lib/brakeman/checks/check_file_access.rb +7 -1
  18. data/lib/brakeman/checks/check_force_ssl.rb +27 -0
  19. data/lib/brakeman/checks/check_header_dos.rb +2 -2
  20. data/lib/brakeman/checks/check_i18n_xss.rb +2 -2
  21. data/lib/brakeman/checks/check_jruby_xml.rb +2 -2
  22. data/lib/brakeman/checks/check_json_parsing.rb +7 -2
  23. data/lib/brakeman/checks/check_link_to_href.rb +6 -1
  24. data/lib/brakeman/checks/check_mail_to.rb +1 -1
  25. data/lib/brakeman/checks/check_mime_type_dos.rb +2 -2
  26. data/lib/brakeman/checks/check_model_attr_accessible.rb +1 -1
  27. data/lib/brakeman/checks/check_model_attributes.rb +12 -50
  28. data/lib/brakeman/checks/check_model_serialize.rb +1 -1
  29. data/lib/brakeman/checks/check_nested_attributes_bypass.rb +4 -4
  30. data/lib/brakeman/checks/check_reverse_tabnabbing.rb +54 -0
  31. data/lib/brakeman/checks/check_sanitize_methods.rb +2 -2
  32. data/lib/brakeman/checks/check_secrets.rb +1 -1
  33. data/lib/brakeman/checks/check_send.rb +0 -1
  34. data/lib/brakeman/checks/check_session_manipulation.rb +0 -1
  35. data/lib/brakeman/checks/check_session_settings.rb +15 -12
  36. data/lib/brakeman/checks/check_simple_format.rb +5 -0
  37. data/lib/brakeman/checks/check_skip_before_filter.rb +1 -1
  38. data/lib/brakeman/checks/check_sql.rb +27 -20
  39. data/lib/brakeman/checks/check_validation_regex.rb +1 -1
  40. data/lib/brakeman/checks/check_xml_dos.rb +2 -2
  41. data/lib/brakeman/checks/check_yaml_parsing.rb +10 -18
  42. data/lib/brakeman/differ.rb +16 -28
  43. data/lib/brakeman/file_parser.rb +6 -8
  44. data/lib/brakeman/file_path.rb +85 -0
  45. data/lib/brakeman/options.rb +7 -0
  46. data/lib/brakeman/parsers/haml_embedded.rb +44 -0
  47. data/lib/brakeman/parsers/slim_embedded.rb +44 -0
  48. data/lib/brakeman/parsers/template_parser.rb +8 -8
  49. data/lib/brakeman/processor.rb +4 -5
  50. data/lib/brakeman/processors/alias_processor.rb +49 -7
  51. data/lib/brakeman/processors/base_processor.rb +10 -7
  52. data/lib/brakeman/processors/controller_alias_processor.rb +10 -7
  53. data/lib/brakeman/processors/controller_processor.rb +9 -13
  54. data/lib/brakeman/processors/gem_processor.rb +10 -2
  55. data/lib/brakeman/processors/haml_template_processor.rb +92 -123
  56. data/lib/brakeman/processors/lib/call_conversion_helper.rb +4 -0
  57. data/lib/brakeman/processors/lib/find_all_calls.rb +27 -4
  58. data/lib/brakeman/processors/lib/find_call.rb +3 -64
  59. data/lib/brakeman/processors/lib/module_helper.rb +8 -8
  60. data/lib/brakeman/processors/lib/processor_helper.rb +3 -3
  61. data/lib/brakeman/processors/lib/rails2_config_processor.rb +4 -4
  62. data/lib/brakeman/processors/lib/rails2_route_processor.rb +2 -2
  63. data/lib/brakeman/processors/lib/rails3_config_processor.rb +3 -3
  64. data/lib/brakeman/processors/lib/rails3_route_processor.rb +2 -2
  65. data/lib/brakeman/processors/lib/render_helper.rb +2 -2
  66. data/lib/brakeman/processors/lib/render_path.rb +18 -1
  67. data/lib/brakeman/processors/library_processor.rb +5 -5
  68. data/lib/brakeman/processors/model_processor.rb +4 -5
  69. data/lib/brakeman/processors/output_processor.rb +5 -0
  70. data/lib/brakeman/processors/slim_template_processor.rb +16 -0
  71. data/lib/brakeman/processors/template_alias_processor.rb +32 -5
  72. data/lib/brakeman/processors/template_processor.rb +14 -10
  73. data/lib/brakeman/report.rb +3 -3
  74. data/lib/brakeman/report/ignore/config.rb +2 -3
  75. data/lib/brakeman/report/ignore/interactive.rb +2 -2
  76. data/lib/brakeman/report/pager.rb +1 -0
  77. data/lib/brakeman/report/report_base.rb +51 -6
  78. data/lib/brakeman/report/report_codeclimate.rb +3 -3
  79. data/lib/brakeman/report/report_hash.rb +1 -1
  80. data/lib/brakeman/report/report_html.rb +2 -2
  81. data/lib/brakeman/report/report_json.rb +1 -24
  82. data/lib/brakeman/report/report_table.rb +20 -4
  83. data/lib/brakeman/report/report_tabs.rb +1 -1
  84. data/lib/brakeman/report/report_text.rb +2 -2
  85. data/lib/brakeman/rescanner.rb +13 -12
  86. data/lib/brakeman/scanner.rb +24 -18
  87. data/lib/brakeman/tracker.rb +35 -7
  88. data/lib/brakeman/tracker/collection.rb +4 -3
  89. data/lib/brakeman/tracker/config.rb +44 -48
  90. data/lib/brakeman/tracker/constants.rb +2 -1
  91. data/lib/brakeman/util.rb +18 -147
  92. data/lib/brakeman/version.rb +1 -1
  93. data/lib/brakeman/warning.rb +27 -13
  94. data/lib/brakeman/warning_codes.rb +4 -0
  95. data/lib/ruby_parser/bm_sexp.rb +1 -1
  96. data/lib/ruby_parser/bm_sexp_processor.rb +1 -0
  97. metadata +58 -43
@@ -1,5 +1,6 @@
1
1
  begin
2
2
  Brakeman.load_brakeman_dependency 'ruby_parser'
3
+ Brakeman.load_brakeman_dependency 'ruby_parser/legacy'
3
4
  require 'ruby_parser/bm_sexp.rb'
4
5
  require 'ruby_parser/bm_sexp_processor.rb'
5
6
  require 'brakeman/processor'
@@ -15,7 +16,6 @@ end
15
16
  #Scans the Rails application.
16
17
  class Brakeman::Scanner
17
18
  attr_reader :options
18
- RUBY_1_9 = RUBY_VERSION >= "1.9.0"
19
19
 
20
20
  #Pass in path to the root of the Rails application
21
21
  def initialize options, processor = nil
@@ -65,7 +65,7 @@ class Brakeman::Scanner
65
65
  end
66
66
 
67
67
  def parse_files
68
- fp = Brakeman::FileParser.new tracker, @app_tree
68
+ fp = Brakeman::FileParser.new tracker
69
69
 
70
70
  files = {
71
71
  :initializers => @app_tree.initializer_paths,
@@ -94,7 +94,7 @@ class Brakeman::Scanner
94
94
  #
95
95
  #Stores parsed information in tracker.config
96
96
  def process_config
97
- if options[:rails3] or options[:rails4] or options[:rails5]
97
+ if options[:rails3] or options[:rails4] or options[:rails5] or options[:rails6]
98
98
  process_config_file "application.rb"
99
99
  process_config_file "environments/production.rb"
100
100
  else
@@ -110,15 +110,15 @@ class Brakeman::Scanner
110
110
  end
111
111
 
112
112
  if @app_tree.exists? ".ruby-version"
113
- tracker.config.set_ruby_version @app_tree.read ".ruby-version"
113
+ tracker.config.set_ruby_version @app_tree.file_path(".ruby-version").read
114
114
  end
115
115
  end
116
116
 
117
117
  def process_config_file file
118
- path = "config/#{file}"
118
+ path = @app_tree.file_path("config/#{file}")
119
119
 
120
- if @app_tree.exists?(path)
121
- @processor.process_config(parse_ruby(@app_tree.read(path)), path)
120
+ if path.exists?
121
+ @processor.process_config(parse_ruby_file(path), path)
122
122
  end
123
123
 
124
124
  rescue => e
@@ -131,20 +131,25 @@ class Brakeman::Scanner
131
131
  #Process Gemfile
132
132
  def process_gems
133
133
  gem_files = {}
134
+
134
135
  if @app_tree.exists? "Gemfile"
135
- gem_files[:gemfile] = { :src => parse_ruby(@app_tree.read("Gemfile")), :file => "Gemfile" }
136
+ file = @app_tree.file_path("Gemfile")
137
+ gem_files[:gemfile] = { :src => parse_ruby_file(file), :file => file }
136
138
  elsif @app_tree.exists? "gems.rb"
137
- gem_files[:gemfile] = { :src => parse_ruby(@app_tree.read("gems.rb")), :file => "gems.rb" }
139
+ file = @app_tree.file_path("gems.rb")
140
+ gem_files[:gemfile] = { :src => parse_ruby_file(file), :file => file }
138
141
  end
139
142
 
140
143
  if @app_tree.exists? "Gemfile.lock"
141
- gem_files[:gemlock] = { :src => @app_tree.read("Gemfile.lock"), :file => "Gemfile.lock" }
144
+ file = @app_tree.file_path("Gemfile.lock")
145
+ gem_files[:gemlock] = { :src => file.read, :file => file }
142
146
  elsif @app_tree.exists? "gems.locked"
143
- gem_files[:gemlock] = { :src => @app_tree.read("gems.locked"), :file => "gems.locked" }
147
+ file = @app_tree.file_path("gems.locked")
148
+ gem_files[:gemlock] = { :src => file.read, :file => file }
144
149
  end
145
150
 
146
151
  if @app_tree.gemspec
147
- gem_files[:gemspec] = { :src => parse_ruby(@app_tree.read(@app_tree.gemspec)), :file => @app_tree.gemspec }
152
+ gem_files[:gemspec] = { :src => parse_ruby_file(@app_tree.gemspec), :file => @app_tree.gemspec }
148
153
  end
149
154
 
150
155
  if not gem_files.empty?
@@ -214,10 +219,10 @@ class Brakeman::Scanner
214
219
  #Adds parsed information to tracker.routes
215
220
  def process_routes
216
221
  if @app_tree.exists?("config/routes.rb")
217
- begin
218
- @processor.process_routes parse_ruby(@app_tree.read("config/routes.rb"))
219
- rescue => e
220
- tracker.error e.exception(e.message + "\nWhile processing routes.rb"), e.backtrace
222
+ file = @app_tree.file_path("config/routes.rb")
223
+ if routes_sexp = parse_ruby_file(file)
224
+ @processor.process_routes routes_sexp
225
+ else
221
226
  Brakeman.notify "[Notice] Error while processing routes - assuming all public controller methods are actions."
222
227
  options[:assume_all_routes] = true
223
228
  end
@@ -316,8 +321,9 @@ class Brakeman::Scanner
316
321
  tracker.index_call_sites
317
322
  end
318
323
 
319
- def parse_ruby input
320
- RubyParser.new.parse input
324
+ def parse_ruby_file file
325
+ fp = Brakeman::FileParser.new(self.tracker)
326
+ fp.parse_ruby(file.read, file)
321
327
  end
322
328
  end
323
329
 
@@ -12,7 +12,7 @@ class Brakeman::Tracker
12
12
  attr_accessor :controllers, :constants, :templates, :models, :errors,
13
13
  :checks, :initializers, :config, :routes, :processor, :libs,
14
14
  :template_cache, :options, :filter_cache, :start_time, :end_time,
15
- :duration, :ignored_filter
15
+ :duration, :ignored_filter, :app_tree
16
16
 
17
17
  #Place holder when there should be a model, but it is not
18
18
  #clear what model it will be.
@@ -34,7 +34,7 @@ class Brakeman::Tracker
34
34
  #we can match models later without knowing precisely what
35
35
  #class they are.
36
36
  @models = {}
37
- @models[UNKNOWN_MODEL] = Brakeman::Model.new(UNKNOWN_MODEL, nil, nil, nil, self)
37
+ @models[UNKNOWN_MODEL] = Brakeman::Model.new(UNKNOWN_MODEL, nil, @app_tree.file_path("NOT_REAL.rb"), nil, self)
38
38
  @routes = {}
39
39
  @initializers = {}
40
40
  @errors = []
@@ -61,13 +61,17 @@ class Brakeman::Tracker
61
61
  Brakeman.debug exception
62
62
  Brakeman.debug backtrace
63
63
 
64
- @errors << { :error => exception.to_s.gsub("\n", " "), :backtrace => backtrace }
64
+ @errors << {
65
+ :exception => exception,
66
+ :error => exception.to_s.gsub("\n", " "),
67
+ :backtrace => backtrace
68
+ }
65
69
  end
66
70
 
67
71
  #Run a set of checks on the current information. Results will be stored
68
72
  #in Tracker#checks.
69
73
  def run_checks
70
- @checks = Brakeman::Checks.run_checks(@app_tree, self)
74
+ @checks = Brakeman::Checks.run_checks(self)
71
75
 
72
76
  @end_time = Time.now
73
77
  @duration = @end_time - @start_time
@@ -168,7 +172,7 @@ class Brakeman::Tracker
168
172
 
169
173
  #Returns a Report with this Tracker's information
170
174
  def report
171
- Brakeman::Report.new(@app_tree, self)
175
+ Brakeman::Report.new(self)
172
176
  end
173
177
 
174
178
  def warnings
@@ -223,6 +227,10 @@ class Brakeman::Tracker
223
227
  finder.process_source template.src, :template => template, :file => template.file
224
228
  end
225
229
 
230
+ self.initializers.each do |file_name, src|
231
+ finder.process_all_source src, :file => file_name
232
+ end
233
+
226
234
  @call_index = Brakeman::CallIndex.new finder.calls
227
235
  end
228
236
 
@@ -233,8 +241,8 @@ class Brakeman::Tracker
233
241
  #
234
242
  #This will limit reindexing to the given sets
235
243
  def reindex_call_sites locations
236
- #If reindexing templates, models, and controllers, just redo
237
- #everything
244
+ #If reindexing templates, models, controllers,
245
+ #just redo everything.
238
246
  if locations.length == 3
239
247
  return index_call_sites
240
248
  end
@@ -256,6 +264,12 @@ class Brakeman::Tracker
256
264
  method_sets << self.controllers
257
265
  end
258
266
 
267
+ if locations.include? :initializers
268
+ self.initializers.each do |file_name, src|
269
+ @call_index.remove_indexes_by_file file_name
270
+ end
271
+ end
272
+
259
273
  @call_index.remove_indexes_by_class classes_to_reindex
260
274
 
261
275
  finder = Brakeman::FindAllCalls.new self
@@ -275,6 +289,12 @@ class Brakeman::Tracker
275
289
  end
276
290
  end
277
291
 
292
+ if locations.include? :initializers
293
+ self.initializers.each do |file_name, src|
294
+ finder.process_all_source src, :file => file_name
295
+ end
296
+ end
297
+
278
298
  @call_index.index_calls finder.calls
279
299
  end
280
300
 
@@ -359,4 +379,12 @@ class Brakeman::Tracker
359
379
  def reset_routes
360
380
  @routes = {}
361
381
  end
382
+
383
+ def reset_initializer path
384
+ @initializers.delete_if do |file, src|
385
+ path.relative.include? file
386
+ end
387
+
388
+ @call_index.remove_indexes_by_file path
389
+ end
362
390
  end
@@ -9,13 +9,14 @@ module Brakeman
9
9
  def initialize name, parent, file_name, src, tracker
10
10
  @name = name
11
11
  @parent = parent
12
- @file_name = file_name
13
- @files = [ file_name ]
14
- @src = { file_name => src }
12
+ @files = []
13
+ @src = {}
15
14
  @includes = []
16
15
  @methods = { :public => {}, :private => {}, :protected => {} }
17
16
  @options = {}
18
17
  @tracker = tracker
18
+
19
+ add_file file_name, src
19
20
  end
20
21
 
21
22
  def ancestor? parent, seen={}
@@ -4,10 +4,8 @@ module Brakeman
4
4
  class Config
5
5
  include Util
6
6
 
7
- attr_reader :rails, :tracker
8
- attr_accessor :rails_version, :ruby_version
7
+ attr_reader :gems, :rails, :ruby_version, :tracker
9
8
  attr_writer :erubis, :escape_html
10
- attr_reader :gems
11
9
 
12
10
  def initialize tracker
13
11
  @tracker = tracker
@@ -19,16 +17,9 @@ module Brakeman
19
17
  @ruby_version = ""
20
18
  end
21
19
 
22
- def allow_forgery_protection?
23
- @rails[:action_controller] and
24
- @rails[:action_controller][:allow_forgery_protection] == Sexp.new(:false)
25
- end
26
-
27
20
  def default_protect_from_forgery?
28
- if version_between? "5.2.0", "9.9.9"
29
- if @rails[:action_controller] and
30
- @rails[:action_controller][:default_protect_from_forgery] == Sexp.new(:false)
31
-
21
+ if version_between? "5.2.0.beta1", "9.9.9"
22
+ if @rails.dig(:action_controller, :default_protect_from_forgery) == Sexp.new(:false)
32
23
  return false
33
24
  else
34
25
  return true
@@ -48,17 +39,21 @@ module Brakeman
48
39
 
49
40
  def escape_html_entities_in_json?
50
41
  #TODO add version-specific information here
51
- @rails[:active_support] and
52
- true? @rails[:active_support][:escape_html_entities_in_json]
42
+ true? @rails.dig(:active_support, :escape_html_entities_in_json)
43
+ end
44
+
45
+ def escape_filter_interpolations?
46
+ # TODO see if app is actually turning this off itself
47
+ has_gem?(:haml) and
48
+ version_between? "5.0.0", "5.99", gem_version(:haml)
53
49
  end
54
50
 
55
51
  def whitelist_attributes?
56
- @rails[:active_record] and
57
- @rails[:active_record][:whitelist_attributes] == Sexp.new(:true)
52
+ @rails.dig(:active_record, :whitelist_attributes) == Sexp.new(:true)
58
53
  end
59
54
 
60
55
  def gem_version name
61
- @gems[name] and @gems[name][:version]
56
+ extract_version @gems.dig(name, :version)
62
57
  end
63
58
 
64
59
  def add_gem name, version, file, line
@@ -78,11 +73,16 @@ module Brakeman
78
73
  @gems[name]
79
74
  end
80
75
 
81
- def set_rails_version
82
- # Ignore ~>, etc. when using values from Gemfile
83
- version = gem_version(:rails) || gem_version(:railties)
84
- if version and version.match(/(\d+\.\d+(\.\d+.*)?)/)
85
- @rails_version = $1
76
+ def set_rails_version version = nil
77
+ version = if version
78
+ # Only used by Rails2ConfigProcessor right now
79
+ extract_version(version)
80
+ else
81
+ gem_version(:rails) || gem_version(:railties)
82
+ end
83
+
84
+ if version
85
+ @rails_version = version
86
86
 
87
87
  if tracker.options[:rails3].nil? and tracker.options[:rails4].nil?
88
88
  if @rails_version.start_with? "3"
@@ -97,6 +97,12 @@ module Brakeman
97
97
  tracker.options[:rails4] = true
98
98
  tracker.options[:rails5] = true
99
99
  Brakeman.notify "[Notice] Detected Rails 5 application"
100
+ elsif @rails_version.start_with? "6"
101
+ tracker.options[:rails3] = true
102
+ tracker.options[:rails4] = true
103
+ tracker.options[:rails5] = true
104
+ tracker.options[:rails6] = true
105
+ Brakeman.notify "[Notice] Detected Rails 6 application"
100
106
  end
101
107
  end
102
108
  end
@@ -107,12 +113,20 @@ module Brakeman
107
113
  end
108
114
  end
109
115
 
116
+ def rails_version
117
+ # This needs to be here because Util#rails_version calls Tracker::Config#rails_version
118
+ # but Tracker::Config includes Util...
119
+ @rails_version
120
+ end
121
+
110
122
  def set_ruby_version version
123
+ @ruby_version = extract_version(version)
124
+ end
125
+
126
+ def extract_version version
111
127
  return unless version.is_a? String
112
128
 
113
- if version =~ /(\d+\.\d+\.\d+)/
114
- self.ruby_version = $1
115
- end
129
+ version[/\d+\.\d+(\.\d+.*)?/]
116
130
  end
117
131
 
118
132
  #Returns true if low_version <= RAILS_VERSION <= high_version
@@ -122,33 +136,15 @@ module Brakeman
122
136
  current_version ||= rails_version
123
137
  return false unless current_version
124
138
 
125
- version = current_version.split(".").map!(&:to_i)
126
- low_version = low_version.split(".").map!(&:to_i)
127
- high_version = high_version.split(".").map!(&:to_i)
128
-
129
- version.each_with_index do |v, i|
130
- if v < low_version.fetch(i, 0)
131
- return false
132
- elsif v > low_version.fetch(i, 0)
133
- break
134
- end
135
- end
139
+ low = Gem::Version.new(low_version)
140
+ high = Gem::Version.new(high_version)
141
+ current = Gem::Version.new(current_version)
136
142
 
137
- version.each_with_index do |v, i|
138
- if v > high_version.fetch(i, 0)
139
- return false
140
- elsif v < high_version.fetch(i, 0)
141
- break
142
- end
143
- end
144
-
145
- true
143
+ current.between?(low, high)
146
144
  end
147
145
 
148
146
  def session_settings
149
- @rails[:action_controller] &&
150
- @rails[:action_controller][:session]
147
+ @rails.dig(:action_controller, :session)
151
148
  end
152
-
153
149
  end
154
150
  end
@@ -49,7 +49,7 @@ module Brakeman
49
49
  include Brakeman::Util
50
50
 
51
51
  def initialize
52
- @constants = Hash.new { |h, k| h[k] = [] }
52
+ @constants = {}
53
53
  end
54
54
 
55
55
  def size
@@ -103,6 +103,7 @@ module Brakeman
103
103
  end
104
104
 
105
105
  base_name = Constants.get_constant_base_name(name)
106
+ @constants[base_name] ||= []
106
107
  @constants[base_name] << Constant.new(name, value, context)
107
108
  end
108
109
 
data/lib/brakeman/util.rb CHANGED
@@ -94,11 +94,21 @@ module Brakeman::Util
94
94
  # end
95
95
  # names #["bob"]
96
96
  def hash_iterate hash
97
+ hash = remove_kwsplat(hash)
98
+
97
99
  1.step(hash.length - 1, 2) do |i|
98
100
  yield hash[i], hash[i + 1]
99
101
  end
100
102
  end
101
103
 
104
+ def remove_kwsplat exp
105
+ if exp.any? { |e| node_type? e, :kwsplat }
106
+ exp.reject { |e| node_type? e, :kwsplat }
107
+ else
108
+ exp
109
+ end
110
+ end
111
+
102
112
  #Insert value into Hash Sexp
103
113
  def hash_insert hash, key, value
104
114
  index = 1
@@ -264,6 +274,13 @@ module Brakeman::Util
264
274
  node_type? exp, :const, :colon2, :colon3
265
275
  end
266
276
 
277
+ def kwsplat? exp
278
+ exp.is_a? Sexp and
279
+ exp.node_type == :hash and
280
+ exp[1].is_a? Sexp and
281
+ exp[1].node_type == :kwsplat
282
+ end
283
+
267
284
  #Check if _exp_ is a Sexp.
268
285
  def sexp? exp
269
286
  exp.is_a? Sexp
@@ -329,158 +346,12 @@ module Brakeman::Util
329
346
  @tracker.config.rails_version
330
347
  end
331
348
 
332
- #Return file name related to given warning. Uses +warning.file+ if it exists
333
- def file_for warning, tracker = nil
334
- if tracker.nil?
335
- tracker = @tracker || self.tracker
336
- end
337
-
338
- if warning.file
339
- File.expand_path warning.file, tracker.app_path
340
- elsif warning.template and warning.template.file
341
- warning.template.file
342
- else
343
- case warning.warning_set
344
- when :controller
345
- file_by_name warning.controller, :controller, tracker
346
- when :template
347
- file_by_name warning.template.name, :template, tracker
348
- when :model
349
- file_by_name warning.model, :model, tracker
350
- when :warning
351
- file_by_name warning.class, nil, tracker
352
- else
353
- nil
354
- end
355
- end
356
- end
357
-
358
- #Attempt to determine path to context file based on the reported name
359
- #in the warning.
360
- #
361
- #For example,
362
- #
363
- # file_by_name FileController #=> "/rails/root/app/controllers/file_controller.rb
364
- def file_by_name name, type, tracker = nil
365
- return nil unless name
366
- string_name = name.to_s
367
- name = name.to_sym
368
-
369
- unless type
370
- if string_name =~ /Controller$/
371
- type = :controller
372
- elsif camelize(string_name) == string_name # This is not always true
373
- type = :model
374
- else
375
- type = :template
376
- end
377
- end
378
-
379
- path = tracker.app_path
380
-
381
- case type
382
- when :controller
383
- if tracker.controllers[name]
384
- path = tracker.controllers[name].file
385
- else
386
- path += "/app/controllers/#{underscore(string_name)}.rb"
387
- end
388
- when :model
389
- if tracker.models[name]
390
- path = tracker.models[name].file
391
- else
392
- path += "/app/models/#{underscore(string_name)}.rb"
393
- end
394
- when :template
395
- if tracker.templates[name] and tracker.templates[name].file
396
- path = tracker.templates[name].file
397
- elsif string_name.include? " "
398
- name = string_name.split[0].to_sym
399
- path = file_for tracker, name, :template
400
- else
401
- path = nil
402
- end
403
- end
404
-
405
- path
406
- end
407
-
408
- #Return array of lines surrounding the warning location from the original
409
- #file.
410
- def context_for app_tree, warning, tracker = nil
411
- file = file_for warning, tracker
412
- context = []
413
- return context unless warning.line and file and @app_tree.path_exists? file
414
-
415
- current_line = 0
416
- start_line = warning.line - 5
417
- end_line = warning.line + 5
418
-
419
- start_line = 1 if start_line < 0
420
-
421
- File.open file do |f|
422
- f.each_line do |line|
423
- current_line += 1
424
-
425
- next if line.strip == ""
426
-
427
- if current_line > end_line
428
- break
429
- end
430
-
431
- if current_line >= start_line
432
- context << [current_line, line]
433
- end
434
- end
435
- end
436
-
437
- context
438
- end
439
-
440
- def relative_path file
441
- pname = Pathname.new file
442
- if file and not file.empty? and pname.absolute?
443
- pname.relative_path_from(Pathname.new(@tracker.app_path)).to_s
444
- else
445
- file
446
- end
447
- end
448
-
449
349
  #Convert path/filename to view name
450
350
  #
451
351
  # views/test/something.html.erb -> test/something
452
352
  def template_path_to_name path
453
- names = path.split("/")
353
+ names = path.relative.split("/")
454
354
  names.last.gsub!(/(\.(html|js)\..*|\.(rhtml|haml|erb|slim))$/, '')
455
355
  names[(names.index("views") + 1)..-1].join("/").to_sym
456
356
  end
457
-
458
- def github_url file, line=nil
459
- if repo_url = @tracker.options[:github_url] and file and not file.empty? and file.start_with? '/'
460
- url = "#{repo_url}/#{relative_path(file)}"
461
- url << "#L#{line}" if line
462
- else
463
- nil
464
- end
465
- end
466
-
467
- def truncate_table str
468
- @terminal_width ||= if @tracker.options[:table_width]
469
- @tracker.options[:table_width]
470
- elsif $stdin && $stdin.tty?
471
- Brakeman.load_brakeman_dependency 'highline'
472
- ::HighLine.new.terminal_size[0]
473
- else
474
- 80
475
- end
476
- lines = str.lines
477
-
478
- lines.map do |line|
479
- if line.chomp.length > @terminal_width
480
- line[0..(@terminal_width - 3)] + ">>\n"
481
- else
482
- line
483
- end
484
- end.join
485
- end
486
357
  end