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.
- checksums.yaml +4 -4
- data/CHANGES.md +63 -0
- data/README.md +6 -7
- data/lib/brakeman.rb +7 -0
- data/lib/brakeman/app_tree.rb +34 -22
- data/lib/brakeman/call_index.rb +54 -15
- data/lib/brakeman/checks.rb +7 -7
- data/lib/brakeman/checks/base_check.rb +75 -56
- data/lib/brakeman/checks/check_content_tag.rb +12 -0
- data/lib/brakeman/checks/check_cookie_serialization.rb +22 -0
- data/lib/brakeman/checks/check_cross_site_scripting.rb +15 -10
- data/lib/brakeman/checks/check_default_routes.rb +5 -0
- data/lib/brakeman/checks/check_deserialize.rb +49 -0
- data/lib/brakeman/checks/check_dynamic_finders.rb +1 -1
- data/lib/brakeman/checks/check_evaluation.rb +0 -1
- data/lib/brakeman/checks/check_execute.rb +44 -1
- data/lib/brakeman/checks/check_file_access.rb +7 -1
- data/lib/brakeman/checks/check_force_ssl.rb +27 -0
- data/lib/brakeman/checks/check_header_dos.rb +2 -2
- data/lib/brakeman/checks/check_i18n_xss.rb +2 -2
- data/lib/brakeman/checks/check_jruby_xml.rb +2 -2
- data/lib/brakeman/checks/check_json_parsing.rb +7 -2
- data/lib/brakeman/checks/check_link_to_href.rb +6 -1
- data/lib/brakeman/checks/check_mail_to.rb +1 -1
- data/lib/brakeman/checks/check_mime_type_dos.rb +2 -2
- data/lib/brakeman/checks/check_model_attr_accessible.rb +1 -1
- data/lib/brakeman/checks/check_model_attributes.rb +12 -50
- data/lib/brakeman/checks/check_model_serialize.rb +1 -1
- data/lib/brakeman/checks/check_nested_attributes_bypass.rb +4 -4
- data/lib/brakeman/checks/check_reverse_tabnabbing.rb +54 -0
- data/lib/brakeman/checks/check_sanitize_methods.rb +2 -2
- data/lib/brakeman/checks/check_secrets.rb +1 -1
- data/lib/brakeman/checks/check_send.rb +0 -1
- data/lib/brakeman/checks/check_session_manipulation.rb +0 -1
- data/lib/brakeman/checks/check_session_settings.rb +15 -12
- data/lib/brakeman/checks/check_simple_format.rb +5 -0
- data/lib/brakeman/checks/check_skip_before_filter.rb +1 -1
- data/lib/brakeman/checks/check_sql.rb +27 -20
- data/lib/brakeman/checks/check_validation_regex.rb +1 -1
- data/lib/brakeman/checks/check_xml_dos.rb +2 -2
- data/lib/brakeman/checks/check_yaml_parsing.rb +10 -18
- data/lib/brakeman/differ.rb +16 -28
- data/lib/brakeman/file_parser.rb +6 -8
- data/lib/brakeman/file_path.rb +85 -0
- data/lib/brakeman/options.rb +7 -0
- data/lib/brakeman/parsers/haml_embedded.rb +44 -0
- data/lib/brakeman/parsers/slim_embedded.rb +44 -0
- data/lib/brakeman/parsers/template_parser.rb +8 -8
- data/lib/brakeman/processor.rb +4 -5
- data/lib/brakeman/processors/alias_processor.rb +49 -7
- data/lib/brakeman/processors/base_processor.rb +10 -7
- data/lib/brakeman/processors/controller_alias_processor.rb +10 -7
- data/lib/brakeman/processors/controller_processor.rb +9 -13
- data/lib/brakeman/processors/gem_processor.rb +10 -2
- data/lib/brakeman/processors/haml_template_processor.rb +92 -123
- data/lib/brakeman/processors/lib/call_conversion_helper.rb +4 -0
- data/lib/brakeman/processors/lib/find_all_calls.rb +27 -4
- data/lib/brakeman/processors/lib/find_call.rb +3 -64
- data/lib/brakeman/processors/lib/module_helper.rb +8 -8
- data/lib/brakeman/processors/lib/processor_helper.rb +3 -3
- data/lib/brakeman/processors/lib/rails2_config_processor.rb +4 -4
- data/lib/brakeman/processors/lib/rails2_route_processor.rb +2 -2
- data/lib/brakeman/processors/lib/rails3_config_processor.rb +3 -3
- data/lib/brakeman/processors/lib/rails3_route_processor.rb +2 -2
- data/lib/brakeman/processors/lib/render_helper.rb +2 -2
- data/lib/brakeman/processors/lib/render_path.rb +18 -1
- data/lib/brakeman/processors/library_processor.rb +5 -5
- data/lib/brakeman/processors/model_processor.rb +4 -5
- data/lib/brakeman/processors/output_processor.rb +5 -0
- data/lib/brakeman/processors/slim_template_processor.rb +16 -0
- data/lib/brakeman/processors/template_alias_processor.rb +32 -5
- data/lib/brakeman/processors/template_processor.rb +14 -10
- data/lib/brakeman/report.rb +3 -3
- data/lib/brakeman/report/ignore/config.rb +2 -3
- data/lib/brakeman/report/ignore/interactive.rb +2 -2
- data/lib/brakeman/report/pager.rb +1 -0
- data/lib/brakeman/report/report_base.rb +51 -6
- data/lib/brakeman/report/report_codeclimate.rb +3 -3
- data/lib/brakeman/report/report_hash.rb +1 -1
- data/lib/brakeman/report/report_html.rb +2 -2
- data/lib/brakeman/report/report_json.rb +1 -24
- data/lib/brakeman/report/report_table.rb +20 -4
- data/lib/brakeman/report/report_tabs.rb +1 -1
- data/lib/brakeman/report/report_text.rb +2 -2
- data/lib/brakeman/rescanner.rb +13 -12
- data/lib/brakeman/scanner.rb +24 -18
- data/lib/brakeman/tracker.rb +35 -7
- data/lib/brakeman/tracker/collection.rb +4 -3
- data/lib/brakeman/tracker/config.rb +44 -48
- data/lib/brakeman/tracker/constants.rb +2 -1
- data/lib/brakeman/util.rb +18 -147
- data/lib/brakeman/version.rb +1 -1
- data/lib/brakeman/warning.rb +27 -13
- data/lib/brakeman/warning_codes.rb +4 -0
- data/lib/ruby_parser/bm_sexp.rb +1 -1
- data/lib/ruby_parser/bm_sexp_processor.rb +1 -0
- metadata +58 -43
data/lib/brakeman/differ.rb
CHANGED
@@ -24,43 +24,31 @@ class Brakeman::Differ
|
|
24
24
|
# second pass to cleanup any vulns which have changed in line number only.
|
25
25
|
# Given a list of new warnings, delete pairs of new/fixed vulns that differ
|
26
26
|
# only by line number.
|
27
|
-
# Horrible O(n^2) performance. Keep n small :-/
|
28
27
|
def second_pass(warnings)
|
29
|
-
|
30
|
-
|
31
|
-
elements_deleted_offset = 0
|
28
|
+
new_fingerprints = Set.new(warnings[:new].map(&method(:fingerprint)))
|
29
|
+
fixed_fingerprints = Set.new(warnings[:fixed].map(&method(:fingerprint)))
|
32
30
|
|
33
|
-
#
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
31
|
+
# Remove warnings which fingerprints are both in :new and :fixed
|
32
|
+
shared_fingerprints = new_fingerprints.intersection(fixed_fingerprints)
|
33
|
+
|
34
|
+
unless shared_fingerprints.empty?
|
35
|
+
warnings[:new].delete_if do |warning|
|
36
|
+
shared_fingerprints.include?(fingerprint(warning))
|
37
|
+
end
|
38
|
+
|
39
|
+
warnings[:fixed].delete_if do |warning|
|
40
|
+
shared_fingerprints.include?(fingerprint(warning))
|
43
41
|
end
|
44
42
|
end
|
45
43
|
|
46
44
|
warnings
|
47
45
|
end
|
48
46
|
|
49
|
-
def
|
50
|
-
|
51
|
-
|
52
|
-
new_warning = new_warning.to_hash
|
53
|
-
fixed_warning = fixed_warning.to_hash
|
54
|
-
end
|
55
|
-
|
56
|
-
if new_warning[:fingerprint] and fixed_warning[:fingerprint]
|
57
|
-
new_warning[:fingerprint] == fixed_warning[:fingerprint]
|
47
|
+
def fingerprint(warning)
|
48
|
+
if warning.is_a?(Brakeman::Warning)
|
49
|
+
warning.fingerprint
|
58
50
|
else
|
59
|
-
|
60
|
-
return false if new_warning[attr] != fixed_warning[attr]
|
61
|
-
end
|
62
|
-
|
63
|
-
true
|
51
|
+
warning[:fingerprint]
|
64
52
|
end
|
65
53
|
end
|
66
54
|
end
|
data/lib/brakeman/file_parser.rb
CHANGED
@@ -5,16 +5,16 @@ module Brakeman
|
|
5
5
|
class FileParser
|
6
6
|
attr_reader :file_list
|
7
7
|
|
8
|
-
def initialize tracker
|
8
|
+
def initialize tracker
|
9
9
|
@tracker = tracker
|
10
10
|
@timeout = @tracker.options[:parser_timeout]
|
11
|
-
@app_tree = app_tree
|
11
|
+
@app_tree = @tracker.app_tree
|
12
12
|
@file_list = {}
|
13
13
|
end
|
14
14
|
|
15
15
|
def parse_files list, type
|
16
16
|
read_files list, type do |path, contents|
|
17
|
-
if ast = parse_ruby(contents, path)
|
17
|
+
if ast = parse_ruby(contents, path.relative)
|
18
18
|
ASTFile.new(path, ast)
|
19
19
|
end
|
20
20
|
end
|
@@ -24,7 +24,9 @@ module Brakeman
|
|
24
24
|
@file_list[type] ||= []
|
25
25
|
|
26
26
|
list.each do |path|
|
27
|
-
|
27
|
+
file = @app_tree.file_path(path)
|
28
|
+
|
29
|
+
result = yield file, file.read
|
28
30
|
if result
|
29
31
|
@file_list[type] << result
|
30
32
|
end
|
@@ -46,9 +48,5 @@ module Brakeman
|
|
46
48
|
nil
|
47
49
|
end
|
48
50
|
end
|
49
|
-
|
50
|
-
def read_path path
|
51
|
-
@app_tree.read_path path
|
52
|
-
end
|
53
51
|
end
|
54
52
|
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
|
3
|
+
module Brakeman
|
4
|
+
# Class to represent file paths within Brakeman.
|
5
|
+
# FilePath objects track both the relative and absolute paths
|
6
|
+
# to make it easier to manage paths.
|
7
|
+
class FilePath
|
8
|
+
attr_reader :absolute, :relative
|
9
|
+
@cache = {}
|
10
|
+
|
11
|
+
# Create a new FilePath using an AppTree object.
|
12
|
+
#
|
13
|
+
# Note that if the path is already a FilePath, that path will
|
14
|
+
# be returned unaltered.
|
15
|
+
#
|
16
|
+
# Additionally, paths are cached. If the absolute path already has
|
17
|
+
# a FilePath in the cache, that existing FilePath will be returned.
|
18
|
+
def self.from_app_tree app_tree, path
|
19
|
+
return path if path.is_a? Brakeman::FilePath
|
20
|
+
|
21
|
+
absolute = app_tree.expand_path(path).freeze
|
22
|
+
|
23
|
+
if fp = @cache[absolute]
|
24
|
+
return fp
|
25
|
+
end
|
26
|
+
|
27
|
+
relative = app_tree.relative_path(path).freeze
|
28
|
+
|
29
|
+
self.new(absolute, relative).tap { |fp| @cache[absolute] = fp }
|
30
|
+
end
|
31
|
+
|
32
|
+
# Create a new FilePath with the given absolute and relative paths.
|
33
|
+
def initialize absolute_path, relative_path
|
34
|
+
@absolute = absolute_path
|
35
|
+
@relative = relative_path
|
36
|
+
end
|
37
|
+
|
38
|
+
# Just the file name, no path
|
39
|
+
def basename
|
40
|
+
@basename ||= File.basename(self.relative)
|
41
|
+
end
|
42
|
+
|
43
|
+
# Read file from absolute path.
|
44
|
+
def read
|
45
|
+
File.read self.absolute
|
46
|
+
end
|
47
|
+
|
48
|
+
# Check if absolute path exists.
|
49
|
+
def exists?
|
50
|
+
File.exist? self.absolute
|
51
|
+
end
|
52
|
+
|
53
|
+
# Compare FilePaths. Raises an ArgumentError unless both objects are FilePaths.
|
54
|
+
def <=> rhs
|
55
|
+
raise ArgumentError unless rhs.is_a? Brakeman::FilePath
|
56
|
+
self.relative <=> rhs.relative
|
57
|
+
end
|
58
|
+
|
59
|
+
# Compare FilePaths. Raises an ArgumentError unless both objects are FilePaths.
|
60
|
+
def == rhs
|
61
|
+
return false unless rhs.is_a? Brakeman::FilePath
|
62
|
+
|
63
|
+
self.absolute == rhs.absolute
|
64
|
+
end
|
65
|
+
|
66
|
+
# Returns a string with the absolute path.
|
67
|
+
def to_str
|
68
|
+
self.absolute
|
69
|
+
end
|
70
|
+
|
71
|
+
# Returns a string with the absolute path.
|
72
|
+
def to_s
|
73
|
+
self.to_str
|
74
|
+
end
|
75
|
+
|
76
|
+
def hash
|
77
|
+
@hash ||= [@absolute, @relative].hash
|
78
|
+
end
|
79
|
+
|
80
|
+
def eql? rhs
|
81
|
+
@absolute == rhs.absolute and
|
82
|
+
@relative == rhs.relative
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
data/lib/brakeman/options.rb
CHANGED
@@ -82,6 +82,13 @@ module Brakeman::Options
|
|
82
82
|
options[:rails5] = true
|
83
83
|
end
|
84
84
|
|
85
|
+
opts.on "-6", "--rails6", "Force Rails 6 mode" do
|
86
|
+
options[:rails3] = true
|
87
|
+
options[:rails4] = true
|
88
|
+
options[:rails5] = true
|
89
|
+
options[:rails6] = true
|
90
|
+
end
|
91
|
+
|
85
92
|
opts.separator ""
|
86
93
|
opts.separator "Scanning options:"
|
87
94
|
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Brakeman
|
2
|
+
module FakeHamlFilter
|
3
|
+
# Copied from Haml 4 - force delayed compilation
|
4
|
+
def compile(compiler, text)
|
5
|
+
filter = self
|
6
|
+
compiler.instance_eval do
|
7
|
+
text = unescape_interpolation(text).gsub(/(\\+)n/) do |s|
|
8
|
+
escapes = $1.size
|
9
|
+
next s if escapes % 2 == 0
|
10
|
+
("\\" * (escapes - 1)) + "\n"
|
11
|
+
end
|
12
|
+
# We need to add a newline at the beginning to get the
|
13
|
+
# filter lines to line up (since the Haml filter contains
|
14
|
+
# a line that doesn't show up in the source, namely the
|
15
|
+
# filter name). Then we need to escape the trailing
|
16
|
+
# newline so that the whole filter block doesn't take up
|
17
|
+
# too many.
|
18
|
+
text = "\n" + text.sub(/\n"\Z/, "\\n\"")
|
19
|
+
push_script <<RUBY.rstrip, :escape_html => false
|
20
|
+
find_and_preserve(#{filter.inspect}.render_with_options(#{text}, _hamlout.options))
|
21
|
+
RUBY
|
22
|
+
return
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# Fake CoffeeScript filter for Haml
|
29
|
+
module Haml::Filters::Coffee
|
30
|
+
include Haml::Filters::Base
|
31
|
+
extend Brakeman::FakeHamlFilter
|
32
|
+
end
|
33
|
+
|
34
|
+
# Fake Markdown filter for Haml
|
35
|
+
module Haml::Filters::Markdown
|
36
|
+
include Haml::Filters::Base
|
37
|
+
extend Brakeman::FakeHamlFilter
|
38
|
+
end
|
39
|
+
|
40
|
+
# Fake Sass filter for Haml
|
41
|
+
module Haml::Filters::Sass
|
42
|
+
include Haml::Filters::Base
|
43
|
+
extend Brakeman::FakeHamlFilter
|
44
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# Fake filters for Slim
|
2
|
+
module Slim
|
3
|
+
class Embedded
|
4
|
+
class TiltEngine
|
5
|
+
def on_slim_embedded(engine, body, attrs)
|
6
|
+
# Override this method to avoid Slim trying to load sass/scss and failing
|
7
|
+
case engine
|
8
|
+
when :sass, :scss, :coffee
|
9
|
+
tilt_engine = nil # Doesn't really matter, ignored below
|
10
|
+
else
|
11
|
+
# Original Slim code
|
12
|
+
tilt_engine = Tilt[engine] || raise(Temple::FilterError, "Tilt engine #{engine} is not available.")
|
13
|
+
end
|
14
|
+
|
15
|
+
tilt_options = options[engine.to_sym] || {}
|
16
|
+
tilt_options[:default_encoding] ||= 'utf-8'
|
17
|
+
|
18
|
+
[:multi, tilt_render(tilt_engine, tilt_options, collect_text(body)), collect_newlines(body)]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class SassEngine
|
23
|
+
protected
|
24
|
+
|
25
|
+
def tilt_render(tilt_engine, tilt_options, text)
|
26
|
+
[:dynamic,
|
27
|
+
"BrakemanFilter.render(#{text.inspect}, #{self.class})"]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class CoffeeEngine < TiltEngine
|
32
|
+
protected
|
33
|
+
|
34
|
+
def tilt_render(tilt_engine, tilt_options, text)
|
35
|
+
[:dynamic,
|
36
|
+
"BrakemanFilter.render(#{text.inspect}, #{self.class})"]
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Override the engine for CoffeeScript, because Slim doesn't have
|
41
|
+
# one, it just uses Tilt's
|
42
|
+
register :coffee, JavaScriptEngine, engine: CoffeeEngine
|
43
|
+
end
|
44
|
+
end
|
@@ -13,7 +13,7 @@ module Brakeman
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def parse_template path, text
|
16
|
-
type = path.match(KNOWN_TEMPLATE_EXTENSIONS)[1].to_sym
|
16
|
+
type = path.relative.match(KNOWN_TEMPLATE_EXTENSIONS)[1].to_sym
|
17
17
|
type = :erb if type == :rhtml
|
18
18
|
name = template_path_to_name path
|
19
19
|
Brakeman.debug "Parsing #{path}"
|
@@ -63,7 +63,7 @@ module Brakeman
|
|
63
63
|
else
|
64
64
|
ERB.new(text, nil, '-').src
|
65
65
|
end
|
66
|
-
src.sub!(/^#.*\n/, '')
|
66
|
+
src.sub!(/^#.*\n/, '')
|
67
67
|
src
|
68
68
|
end
|
69
69
|
end
|
@@ -75,21 +75,21 @@ module Brakeman
|
|
75
75
|
|
76
76
|
def parse_haml path, text
|
77
77
|
Brakeman.load_brakeman_dependency 'haml'
|
78
|
-
|
78
|
+
require_relative 'haml_embedded'
|
79
79
|
|
80
80
|
Haml::Engine.new(text,
|
81
81
|
:filename => path,
|
82
|
-
:escape_html => tracker.config.escape_html
|
82
|
+
:escape_html => tracker.config.escape_html?,
|
83
|
+
:escape_filter_interpolations => tracker.config.escape_filter_interpolations?
|
84
|
+
).precompiled.gsub(/([^\\])\\n/, '\1')
|
83
85
|
rescue Haml::Error => e
|
84
86
|
tracker.error e, ["While compiling HAML in #{path}"] << e.backtrace
|
85
87
|
nil
|
86
|
-
rescue Sass::SyntaxError => e
|
87
|
-
tracker.error e, "While processing #{path}"
|
88
|
-
nil
|
89
88
|
end
|
90
89
|
|
91
90
|
def parse_slim path, text
|
92
91
|
Brakeman.load_brakeman_dependency 'slim'
|
92
|
+
require_relative 'slim_embedded'
|
93
93
|
|
94
94
|
Slim::Template.new(path,
|
95
95
|
:disable_capture => true,
|
@@ -97,7 +97,7 @@ module Brakeman
|
|
97
97
|
end
|
98
98
|
|
99
99
|
def self.parse_inline_erb tracker, text
|
100
|
-
fp = Brakeman::FileParser.new(tracker
|
100
|
+
fp = Brakeman::FileParser.new(tracker)
|
101
101
|
tp = self.new(tracker, fp)
|
102
102
|
src = tp.parse_erb '_inline_', text
|
103
103
|
type = tp.erubis? ? :erubis : :erb
|
data/lib/brakeman/processor.rb
CHANGED
@@ -13,8 +13,7 @@ module Brakeman
|
|
13
13
|
include Util
|
14
14
|
|
15
15
|
def initialize(app_tree, options)
|
16
|
-
@
|
17
|
-
@tracker = Tracker.new(@app_tree, self, options)
|
16
|
+
@tracker = Tracker.new(app_tree, self, options)
|
18
17
|
end
|
19
18
|
|
20
19
|
def tracked_events
|
@@ -39,7 +38,7 @@ module Brakeman
|
|
39
38
|
#Process controller source. +file_name+ is used for reporting
|
40
39
|
def process_controller src, file_name
|
41
40
|
if contains_class? src
|
42
|
-
ControllerProcessor.new(@
|
41
|
+
ControllerProcessor.new(@tracker).process_controller src, file_name
|
43
42
|
else
|
44
43
|
LibraryProcessor.new(@tracker).process_library src, file_name
|
45
44
|
end
|
@@ -48,7 +47,7 @@ module Brakeman
|
|
48
47
|
#Process variable aliasing in controller source and save it in the
|
49
48
|
#tracker.
|
50
49
|
def process_controller_alias name, src, only_method = nil, file = nil
|
51
|
-
ControllerAliasProcessor.new(@
|
50
|
+
ControllerAliasProcessor.new(@tracker, only_method).process_controller name, src, file
|
52
51
|
end
|
53
52
|
|
54
53
|
#Process a model source
|
@@ -91,7 +90,7 @@ module Brakeman
|
|
91
90
|
def process_initializer file_name, src
|
92
91
|
res = BaseProcessor.new(@tracker).process_file src, file_name
|
93
92
|
res = AliasProcessor.new(@tracker).process_safely res, nil, file_name
|
94
|
-
@tracker.initializers[
|
93
|
+
@tracker.initializers[file_name] = res
|
95
94
|
end
|
96
95
|
|
97
96
|
#Process source for a library file
|
@@ -20,19 +20,18 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
|
|
20
20
|
#The recommended usage is:
|
21
21
|
#
|
22
22
|
# AliasProcessor.new.process_safely src
|
23
|
-
def initialize tracker = nil,
|
23
|
+
def initialize tracker = nil, current_file = nil
|
24
24
|
super()
|
25
25
|
@env = SexpProcessor::Environment.new
|
26
26
|
@inside_if = false
|
27
27
|
@ignore_ifs = nil
|
28
28
|
@exp_context = []
|
29
|
-
@current_module = nil
|
30
29
|
@tracker = tracker #set in subclass as necessary
|
31
30
|
@helper_method_cache = {}
|
32
31
|
@helper_method_info = Hash.new({})
|
33
32
|
@or_depth_limit = (tracker && tracker.options[:branch_limit]) || 5 #arbitrary default
|
34
33
|
@meth_env = nil
|
35
|
-
@
|
34
|
+
@current_file = current_file
|
36
35
|
set_env_defaults
|
37
36
|
end
|
38
37
|
|
@@ -44,8 +43,8 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
|
|
44
43
|
#
|
45
44
|
#This method returns a new Sexp with variables replaced with their values,
|
46
45
|
#where possible.
|
47
|
-
def process_safely src, set_env = nil,
|
48
|
-
@
|
46
|
+
def process_safely src, set_env = nil, current_file = @current_file
|
47
|
+
@current_file = current_file
|
49
48
|
@env = set_env || SexpProcessor::Environment.new
|
50
49
|
@result = src.deep_clone
|
51
50
|
process @result
|
@@ -66,7 +65,11 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
|
|
66
65
|
end
|
67
66
|
end
|
68
67
|
rescue => err
|
69
|
-
|
68
|
+
if @tracker
|
69
|
+
@tracker.error err
|
70
|
+
else
|
71
|
+
raise err
|
72
|
+
end
|
70
73
|
end
|
71
74
|
|
72
75
|
result = replace(exp)
|
@@ -246,6 +249,9 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
|
|
246
249
|
end
|
247
250
|
env[target_var] = target
|
248
251
|
return first_arg
|
252
|
+
elsif new_string? target
|
253
|
+
env[target_var] = first_arg
|
254
|
+
return first_arg
|
249
255
|
elsif array? target
|
250
256
|
target << first_arg
|
251
257
|
env[target_var] = target
|
@@ -262,10 +268,19 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
|
|
262
268
|
unless target.nil?
|
263
269
|
exp = target
|
264
270
|
end
|
271
|
+
when :dup
|
272
|
+
unless target.nil?
|
273
|
+
exp = target
|
274
|
+
end
|
265
275
|
when :join
|
266
276
|
if array? target and target.length > 2 and (string? first_arg or first_arg.nil?)
|
267
277
|
exp = process_array_join(target, first_arg)
|
268
278
|
end
|
279
|
+
when :!
|
280
|
+
# Convert `!!a` to boolean
|
281
|
+
if call? target and target.method == :!
|
282
|
+
exp = s(:or, s(:true).line(exp.line), s(:false).line(exp.line)).line(exp.line)
|
283
|
+
end
|
269
284
|
end
|
270
285
|
|
271
286
|
exp
|
@@ -364,6 +379,8 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
|
|
364
379
|
elsif e.is_a? Symbol
|
365
380
|
local = Sexp.new(:lvar, e)
|
366
381
|
env.current[local] = local
|
382
|
+
elsif e.nil? # trailing comma, argument destructuring
|
383
|
+
next # Punt for now
|
367
384
|
else
|
368
385
|
raise "Unexpected value in block args: #{e.inspect}"
|
369
386
|
end
|
@@ -585,6 +602,24 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
|
|
585
602
|
exp
|
586
603
|
end
|
587
604
|
|
605
|
+
def process_hash exp
|
606
|
+
exp = process_default(exp)
|
607
|
+
|
608
|
+
# Handle { **kw }
|
609
|
+
if node_type? exp, :hash
|
610
|
+
if exp.any? { |e| node_type? e, :kwsplat and node_type? e.value, :hash }
|
611
|
+
kwsplats, rest = exp.partition { |e| node_type? e, :kwsplat and node_type? e.value, :hash }
|
612
|
+
exp = Sexp.new.concat(rest).line(exp.line)
|
613
|
+
|
614
|
+
kwsplats.each do |e|
|
615
|
+
exp = process_hash_merge! exp, e.value
|
616
|
+
end
|
617
|
+
end
|
618
|
+
end
|
619
|
+
|
620
|
+
exp
|
621
|
+
end
|
622
|
+
|
588
623
|
#Merge values into hash when processing
|
589
624
|
#
|
590
625
|
# h.merge! :something => "value"
|
@@ -671,7 +706,7 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
|
|
671
706
|
if @tracker
|
672
707
|
@tracker.add_constant exp.lhs,
|
673
708
|
exp.rhs,
|
674
|
-
:file =>
|
709
|
+
:file => @current_file,
|
675
710
|
:module => @current_module,
|
676
711
|
:class => @current_class,
|
677
712
|
:method => @current_method
|
@@ -1166,6 +1201,13 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
|
|
1166
1201
|
call? exp and exp.method == :raise
|
1167
1202
|
end
|
1168
1203
|
|
1204
|
+
STRING_NEW = s(:call, s(:const, :String), :new)
|
1205
|
+
|
1206
|
+
# String.new ?
|
1207
|
+
def new_string? exp
|
1208
|
+
exp == STRING_NEW
|
1209
|
+
end
|
1210
|
+
|
1169
1211
|
#Set variable to given value.
|
1170
1212
|
#Creates "branched" versions of values when appropriate.
|
1171
1213
|
#Avoids creating multiple branched versions inside same
|