brakeman 5.0.4 → 5.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGES.md +53 -1
- data/README.md +1 -1
- data/bundle/load.rb +5 -4
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.2}/CHANGELOG.md +8 -0
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.2}/FAQ.md +0 -0
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.2}/Gemfile +0 -0
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.2}/MIT-LICENSE +0 -0
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.2}/README.md +19 -13
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.2}/REFERENCE.md +10 -3
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.2}/TODO +0 -0
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.2}/haml.gemspec +0 -0
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.2}/lib/haml/attribute_builder.rb +55 -0
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.2}/lib/haml/attribute_compiler.rb +4 -2
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.2}/lib/haml/attribute_parser.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.2}/lib/haml/buffer.rb +0 -56
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.2}/lib/haml/compiler.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.2}/lib/haml/engine.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.2}/lib/haml/error.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.2}/lib/haml/escapable.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.2}/lib/haml/exec.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.2}/lib/haml/filters.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.2}/lib/haml/generator.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.2}/lib/haml/helpers/action_view_extensions.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.2}/lib/haml/helpers/action_view_mods.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.2}/lib/haml/helpers/action_view_xss_mods.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.2}/lib/haml/helpers/safe_erubi_template.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.2}/lib/haml/helpers/safe_erubis_template.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.2}/lib/haml/helpers/xss_mods.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.2}/lib/haml/helpers.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.2}/lib/haml/options.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.2}/lib/haml/parser.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.2}/lib/haml/plugin.rb +18 -1
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.2}/lib/haml/railtie.rb +5 -0
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.2}/lib/haml/sass_rails_filter.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.2}/lib/haml/template/options.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.2}/lib/haml/template.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.2}/lib/haml/temple_engine.rb +2 -1
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.2}/lib/haml/temple_line_counter.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.2}/lib/haml/util.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.2}/lib/haml/version.rb +1 -1
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.2}/lib/haml.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.2}/yard/default/fulldoc/html/css/common.sass +0 -0
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.2}/yard/default/layout/html/footer.erb +0 -0
- data/bundle/ruby/2.7.0/gems/parallel-1.21.0/MIT-LICENSE.txt +20 -0
- data/bundle/ruby/2.7.0/gems/parallel-1.21.0/lib/parallel/processor_count.rb +45 -0
- data/bundle/ruby/2.7.0/gems/parallel-1.21.0/lib/parallel/version.rb +4 -0
- data/bundle/ruby/2.7.0/gems/parallel-1.21.0/lib/parallel.rb +532 -0
- data/bundle/ruby/2.7.0/gems/{ruby_parser-3.16.0 → ruby_parser-3.18.1}/History.rdoc +88 -0
- data/bundle/ruby/2.7.0/gems/{ruby_parser-3.16.0 → ruby_parser-3.18.1}/Manifest.txt +3 -0
- data/bundle/ruby/2.7.0/gems/{ruby_parser-3.16.0 → ruby_parser-3.18.1}/README.rdoc +1 -0
- data/bundle/ruby/2.7.0/gems/{ruby_parser-3.16.0 → ruby_parser-3.18.1}/compare/normalize.rb +6 -1
- data/bundle/ruby/2.7.0/gems/{ruby_parser-3.16.0 → ruby_parser-3.18.1}/debugging.md +0 -0
- data/bundle/ruby/2.7.0/gems/ruby_parser-3.18.1/gauntlet.md +106 -0
- data/bundle/ruby/2.7.0/gems/{ruby_parser-3.16.0 → ruby_parser-3.18.1}/lib/rp_extensions.rb +15 -36
- data/bundle/ruby/2.7.0/gems/ruby_parser-3.18.1/lib/rp_stringscanner.rb +33 -0
- data/bundle/ruby/2.7.0/gems/ruby_parser-3.18.1/lib/ruby20_parser.rb +7128 -0
- data/bundle/ruby/2.7.0/gems/{ruby_parser-3.16.0 → ruby_parser-3.18.1}/lib/ruby20_parser.y +335 -252
- data/bundle/ruby/2.7.0/gems/ruby_parser-3.18.1/lib/ruby21_parser.rb +7182 -0
- data/bundle/ruby/2.7.0/gems/{ruby_parser-3.16.0 → ruby_parser-3.18.1}/lib/ruby21_parser.y +330 -249
- data/bundle/ruby/2.7.0/gems/ruby_parser-3.18.1/lib/ruby22_parser.rb +7228 -0
- data/bundle/ruby/2.7.0/gems/{ruby_parser-3.16.0 → ruby_parser-3.18.1}/lib/ruby22_parser.y +334 -251
- data/bundle/ruby/2.7.0/gems/ruby_parser-3.18.1/lib/ruby23_parser.rb +7237 -0
- data/bundle/ruby/2.7.0/gems/{ruby_parser-3.16.0/lib/ruby26_parser.y → ruby_parser-3.18.1/lib/ruby23_parser.y} +336 -276
- data/bundle/ruby/2.7.0/gems/ruby_parser-3.18.1/lib/ruby24_parser.rb +7268 -0
- data/bundle/ruby/2.7.0/gems/{ruby_parser-3.16.0 → ruby_parser-3.18.1}/lib/ruby24_parser.y +334 -251
- data/bundle/ruby/2.7.0/gems/ruby_parser-3.18.1/lib/ruby25_parser.rb +7268 -0
- data/bundle/ruby/2.7.0/gems/{ruby_parser-3.16.0/lib/ruby30_parser.y → ruby_parser-3.18.1/lib/ruby25_parser.y} +335 -304
- data/bundle/ruby/2.7.0/gems/ruby_parser-3.18.1/lib/ruby26_parser.rb +7287 -0
- data/bundle/ruby/2.7.0/gems/{ruby_parser-3.16.0/lib/ruby27_parser.y → ruby_parser-3.18.1/lib/ruby26_parser.y} +334 -288
- data/bundle/ruby/2.7.0/gems/ruby_parser-3.18.1/lib/ruby27_parser.rb +8517 -0
- data/bundle/ruby/2.7.0/gems/{ruby_parser-3.16.0/lib/ruby_parser.yy → ruby_parser-3.18.1/lib/ruby27_parser.y} +906 -380
- data/bundle/ruby/2.7.0/gems/ruby_parser-3.18.1/lib/ruby30_parser.rb +8751 -0
- data/bundle/ruby/2.7.0/gems/ruby_parser-3.18.1/lib/ruby30_parser.y +3472 -0
- data/bundle/ruby/2.7.0/gems/ruby_parser-3.18.1/lib/ruby3_parser.yy +3476 -0
- data/bundle/ruby/2.7.0/gems/{ruby_parser-3.16.0 → ruby_parser-3.18.1}/lib/ruby_lexer.rb +261 -609
- data/bundle/ruby/2.7.0/gems/{ruby_parser-3.16.0 → ruby_parser-3.18.1}/lib/ruby_lexer.rex +27 -20
- data/bundle/ruby/2.7.0/gems/{ruby_parser-3.16.0 → ruby_parser-3.18.1}/lib/ruby_lexer.rex.rb +59 -23
- data/bundle/ruby/2.7.0/gems/ruby_parser-3.18.1/lib/ruby_lexer_strings.rb +638 -0
- data/bundle/ruby/2.7.0/gems/{ruby_parser-3.16.0 → ruby_parser-3.18.1}/lib/ruby_parser.rb +0 -0
- data/bundle/ruby/2.7.0/gems/ruby_parser-3.18.1/lib/ruby_parser.yy +3487 -0
- data/bundle/ruby/2.7.0/gems/{ruby_parser-3.16.0 → ruby_parser-3.18.1}/lib/ruby_parser_extras.rb +296 -115
- data/bundle/ruby/2.7.0/gems/{ruby_parser-3.16.0 → ruby_parser-3.18.1}/tools/munge.rb +34 -6
- data/bundle/ruby/2.7.0/gems/ruby_parser-3.18.1/tools/ripper.rb +44 -0
- data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.3 → sexp_processor-4.16.0}/History.rdoc +15 -0
- data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.3 → sexp_processor-4.16.0}/Manifest.txt +0 -0
- data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.3 → sexp_processor-4.16.0}/README.rdoc +0 -0
- data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.3 → sexp_processor-4.16.0}/lib/composite_sexp_processor.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.3 → sexp_processor-4.16.0}/lib/pt_testcase.rb +7 -2
- data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.3 → sexp_processor-4.16.0}/lib/sexp.rb +19 -9
- data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.3 → sexp_processor-4.16.0}/lib/sexp_matcher.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.3 → sexp_processor-4.16.0}/lib/sexp_processor.rb +1 -1
- data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.3 → sexp_processor-4.16.0}/lib/strict_sexp.rb +25 -3
- data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.3 → sexp_processor-4.16.0}/lib/unique.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{unicode-display_width-1.7.0 → unicode-display_width-1.8.0}/CHANGELOG.md +4 -0
- data/bundle/ruby/2.7.0/gems/{unicode-display_width-1.7.0 → unicode-display_width-1.8.0}/MIT-LICENSE.txt +0 -0
- data/bundle/ruby/2.7.0/gems/{unicode-display_width-1.7.0 → unicode-display_width-1.8.0}/README.md +1 -1
- data/bundle/ruby/2.7.0/gems/unicode-display_width-1.8.0/data/display_width.marshal.gz +0 -0
- data/bundle/ruby/2.7.0/gems/{unicode-display_width-1.7.0 → unicode-display_width-1.8.0}/lib/unicode/display_width/constants.rb +2 -2
- data/bundle/ruby/2.7.0/gems/{unicode-display_width-1.7.0 → unicode-display_width-1.8.0}/lib/unicode/display_width/index.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{unicode-display_width-1.7.0 → unicode-display_width-1.8.0}/lib/unicode/display_width/no_string_ext.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{unicode-display_width-1.7.0 → unicode-display_width-1.8.0}/lib/unicode/display_width/string_ext.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{unicode-display_width-1.7.0 → unicode-display_width-1.8.0}/lib/unicode/display_width.rb +0 -0
- data/lib/brakeman/app_tree.rb +1 -1
- data/lib/brakeman/checks/base_check.rb +10 -0
- data/lib/brakeman/checks/check_detailed_exceptions.rb +1 -1
- data/lib/brakeman/checks/check_eol_rails.rb +23 -0
- data/lib/brakeman/checks/check_eol_ruby.rb +26 -0
- data/lib/brakeman/checks/check_evaluation.rb +1 -1
- data/lib/brakeman/checks/check_execute.rb +10 -0
- data/lib/brakeman/checks/check_json_parsing.rb +1 -1
- data/lib/brakeman/checks/check_render.rb +15 -1
- data/lib/brakeman/checks/check_sql.rb +58 -7
- data/lib/brakeman/checks/check_symbol_dos.rb +1 -1
- data/lib/brakeman/checks/check_verb_confusion.rb +1 -1
- data/lib/brakeman/checks/eol_check.rb +47 -0
- data/lib/brakeman/file_parser.rb +45 -15
- data/lib/brakeman/options.rb +15 -2
- data/lib/brakeman/processors/alias_processor.rb +91 -9
- data/lib/brakeman/processors/controller_alias_processor.rb +6 -43
- data/lib/brakeman/processors/gem_processor.rb +3 -0
- data/lib/brakeman/processors/haml_template_processor.rb +9 -0
- data/lib/brakeman/processors/lib/call_conversion_helper.rb +12 -6
- data/lib/brakeman/processors/lib/rails3_route_processor.rb +2 -0
- data/lib/brakeman/processors/library_processor.rb +9 -0
- data/lib/brakeman/processors/model_processor.rb +32 -0
- data/lib/brakeman/report/ignore/config.rb +1 -1
- data/lib/brakeman/report/ignore/interactive.rb +1 -1
- data/lib/brakeman/report/report_csv.rb +1 -1
- data/lib/brakeman/report/report_github.rb +31 -0
- data/lib/brakeman/report/report_sarif.rb +22 -3
- data/lib/brakeman/report/report_text.rb +1 -1
- data/lib/brakeman/report.rb +4 -1
- data/lib/brakeman/rescanner.rb +1 -1
- data/lib/brakeman/scanner.rb +19 -14
- data/lib/brakeman/tracker/collection.rb +57 -7
- data/lib/brakeman/tracker/config.rb +8 -1
- data/lib/brakeman/tracker/method_info.rb +70 -0
- data/lib/brakeman/tracker.rb +33 -4
- data/lib/brakeman/util.rb +34 -18
- data/lib/brakeman/version.rb +1 -1
- data/lib/brakeman/warning_codes.rb +4 -0
- data/lib/brakeman.rb +8 -2
- data/lib/ruby_parser/bm_sexp.rb +24 -0
- metadata +107 -95
- data/bundle/ruby/2.7.0/gems/ruby_parser-3.16.0/lib/rp_stringscanner.rb +0 -64
- data/bundle/ruby/2.7.0/gems/ruby_parser-3.16.0/lib/ruby20_parser.rb +0 -7075
- data/bundle/ruby/2.7.0/gems/ruby_parser-3.16.0/lib/ruby21_parser.rb +0 -7148
- data/bundle/ruby/2.7.0/gems/ruby_parser-3.16.0/lib/ruby22_parser.rb +0 -7185
- data/bundle/ruby/2.7.0/gems/ruby_parser-3.16.0/lib/ruby23_parser.rb +0 -7199
- data/bundle/ruby/2.7.0/gems/ruby_parser-3.16.0/lib/ruby23_parser.y +0 -2643
- data/bundle/ruby/2.7.0/gems/ruby_parser-3.16.0/lib/ruby24_parser.rb +0 -7219
- data/bundle/ruby/2.7.0/gems/ruby_parser-3.16.0/lib/ruby25_parser.rb +0 -7218
- data/bundle/ruby/2.7.0/gems/ruby_parser-3.16.0/lib/ruby25_parser.y +0 -2651
- data/bundle/ruby/2.7.0/gems/ruby_parser-3.16.0/lib/ruby26_parser.rb +0 -7240
- data/bundle/ruby/2.7.0/gems/ruby_parser-3.16.0/lib/ruby27_parser.rb +0 -7358
- data/bundle/ruby/2.7.0/gems/ruby_parser-3.16.0/lib/ruby30_parser.rb +0 -7358
- data/bundle/ruby/2.7.0/gems/ruby_parser-3.16.0/tools/ripper.rb +0 -39
- data/bundle/ruby/2.7.0/gems/unicode-display_width-1.7.0/data/display_width.marshal.gz +0 -0
@@ -22,7 +22,19 @@ class Brakeman::CheckSQL < Brakeman::BaseCheck
|
|
22
22
|
:find_by_sql, :maximum, :minimum, :pluck, :sum, :update_all]
|
23
23
|
@sql_targets.concat [:from, :group, :having, :joins, :lock, :order, :reorder, :where] if tracker.options[:rails3]
|
24
24
|
@sql_targets.concat [:find_by, :find_by!, :find_or_create_by, :find_or_create_by!, :find_or_initialize_by, :not] if tracker.options[:rails4]
|
25
|
-
|
25
|
+
|
26
|
+
if tracker.options[:rails6]
|
27
|
+
@sql_targets.concat [:delete_by, :destroy_by, :rewhere, :reselect]
|
28
|
+
|
29
|
+
@sql_targets.delete :delete_all
|
30
|
+
@sql_targets.delete :destroy_all
|
31
|
+
end
|
32
|
+
|
33
|
+
if version_between?("6.1.0", "9.9.9")
|
34
|
+
@sql_targets.delete :order
|
35
|
+
@sql_targets.delete :reorder
|
36
|
+
@sql_targets.delete :pluck
|
37
|
+
end
|
26
38
|
|
27
39
|
if version_between?("2.0.0", "3.9.9") or tracker.config.rails_version.nil?
|
28
40
|
@sql_targets << :first << :last << :all
|
@@ -185,7 +197,7 @@ class Brakeman::CheckSQL < Brakeman::BaseCheck
|
|
185
197
|
else
|
186
198
|
check_find_arguments call.last_arg
|
187
199
|
end
|
188
|
-
when :where, :having, :find_by, :find_by!, :find_or_create_by, :find_or_create_by!, :find_or_initialize_by,:not, :delete_by, :destroy_by
|
200
|
+
when :where, :rewhere, :having, :find_by, :find_by!, :find_or_create_by, :find_or_create_by!, :find_or_initialize_by,:not, :delete_by, :destroy_by
|
189
201
|
check_query_arguments call.arglist
|
190
202
|
when :order, :group, :reorder
|
191
203
|
check_order_arguments call.arglist
|
@@ -199,7 +211,7 @@ class Brakeman::CheckSQL < Brakeman::BaseCheck
|
|
199
211
|
unsafe_sql? call.first_arg
|
200
212
|
when :sql
|
201
213
|
unsafe_sql? call.first_arg
|
202
|
-
when :update_all, :select
|
214
|
+
when :update_all, :select, :reselect
|
203
215
|
check_update_all_arguments call.args
|
204
216
|
when *@connection_calls
|
205
217
|
check_by_sql_arguments call.first_arg
|
@@ -579,6 +591,10 @@ class Brakeman::CheckSQL < Brakeman::BaseCheck
|
|
579
591
|
:where_values_hash, :foreign_key, :uuid
|
580
592
|
]
|
581
593
|
|
594
|
+
def ignore_methods_in_sql
|
595
|
+
@ignore_methods_in_sql ||= IGNORE_METHODS_IN_SQL + (tracker.options[:sql_safe_methods] || [])
|
596
|
+
end
|
597
|
+
|
582
598
|
def safe_value? exp
|
583
599
|
return true unless sexp? exp
|
584
600
|
|
@@ -589,10 +605,7 @@ class Brakeman::CheckSQL < Brakeman::BaseCheck
|
|
589
605
|
if exp.method == :to_s or exp.method == :to_sym
|
590
606
|
safe_value? exp.target
|
591
607
|
else
|
592
|
-
|
593
|
-
quote_call? exp or
|
594
|
-
arel? exp or
|
595
|
-
exp.method.to_s.end_with? "_id"
|
608
|
+
ignore_call? exp
|
596
609
|
end
|
597
610
|
when :if
|
598
611
|
safe_value? exp.then_clause and safe_value? exp.else_clause
|
@@ -607,6 +620,18 @@ class Brakeman::CheckSQL < Brakeman::BaseCheck
|
|
607
620
|
end
|
608
621
|
end
|
609
622
|
|
623
|
+
def ignore_call? exp
|
624
|
+
return unless call? exp
|
625
|
+
|
626
|
+
ignore_methods_in_sql.include? exp.method or
|
627
|
+
quote_call? exp or
|
628
|
+
arel? exp or
|
629
|
+
exp.method.to_s.end_with? "_id" or
|
630
|
+
number_target? exp or
|
631
|
+
date_target? exp or
|
632
|
+
locale_call? exp
|
633
|
+
end
|
634
|
+
|
610
635
|
QUOTE_METHODS = [:quote, :quote_column_name, :quoted_date, :quote_string, :quote_table_name]
|
611
636
|
|
612
637
|
def quote_call? exp
|
@@ -695,4 +720,30 @@ class Brakeman::CheckSQL < Brakeman::BaseCheck
|
|
695
720
|
active_record_models.include? klass
|
696
721
|
end
|
697
722
|
end
|
723
|
+
|
724
|
+
def number_target? exp
|
725
|
+
return unless call? exp
|
726
|
+
|
727
|
+
if number? exp.target
|
728
|
+
true
|
729
|
+
elsif call? exp.target
|
730
|
+
number_target? exp.target
|
731
|
+
else
|
732
|
+
false
|
733
|
+
end
|
734
|
+
end
|
735
|
+
|
736
|
+
DATE_CLASS = s(:const, :Date)
|
737
|
+
|
738
|
+
def date_target? exp
|
739
|
+
return unless call? exp
|
740
|
+
|
741
|
+
if exp.target == DATE_CLASS
|
742
|
+
true
|
743
|
+
elsif call? exp.target
|
744
|
+
date_target? exp.target
|
745
|
+
else
|
746
|
+
false
|
747
|
+
end
|
748
|
+
end
|
698
749
|
end
|
@@ -9,7 +9,7 @@ class Brakeman::CheckSymbolDoS < Brakeman::BaseCheck
|
|
9
9
|
|
10
10
|
def run_check
|
11
11
|
return if rails_version and rails_version >= "5.0.0"
|
12
|
-
return if tracker.config.ruby_version >= "2.2"
|
12
|
+
return if tracker.config.ruby_version and tracker.config.ruby_version >= "2.2"
|
13
13
|
|
14
14
|
tracker.find_call(:methods => UNSAFE_METHODS, :nested => true).each do |result|
|
15
15
|
check_unsafe_symbol_creation(result)
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'date'
|
2
|
+
require 'brakeman/checks/base_check'
|
3
|
+
|
4
|
+
# Not used directly - base check for EOLRails and EOLRuby
|
5
|
+
class Brakeman::EOLCheck < Brakeman::BaseCheck
|
6
|
+
def check_eol_version library, eol_dates
|
7
|
+
version = case library
|
8
|
+
when :rails
|
9
|
+
tracker.config.rails_version
|
10
|
+
when :ruby
|
11
|
+
tracker.config.ruby_version
|
12
|
+
else
|
13
|
+
raise 'Implement using tracker.config.gem_version'
|
14
|
+
end
|
15
|
+
|
16
|
+
eol_dates.each do |(start_version, end_version), eol_date|
|
17
|
+
if version_between? start_version, end_version, version
|
18
|
+
case
|
19
|
+
when Date.today >= eol_date
|
20
|
+
warn_about_unsupported_version library, eol_date, version
|
21
|
+
when (Date.today + 30) >= eol_date
|
22
|
+
warn_about_soon_unsupported_version library, eol_date, version, :medium
|
23
|
+
when (Date.today + 60) >= eol_date
|
24
|
+
warn_about_soon_unsupported_version library, eol_date, version, :low
|
25
|
+
end
|
26
|
+
|
27
|
+
break
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def warn_about_soon_unsupported_version library, eol_date, version, confidence
|
33
|
+
warn warning_type: 'Unmaintained Dependency',
|
34
|
+
warning_code: :"pending_eol_#{library}",
|
35
|
+
message: msg("Support for ", msg_version(version, library.capitalize), " ends on #{eol_date}"),
|
36
|
+
confidence: confidence,
|
37
|
+
gem_info: gemfile_or_environment
|
38
|
+
end
|
39
|
+
|
40
|
+
def warn_about_unsupported_version library, eol_date, version
|
41
|
+
warn warning_type: 'Unmaintained Dependency',
|
42
|
+
warning_code: :"eol_#{library}",
|
43
|
+
message: msg("Support for ", msg_version(version, library.capitalize), " ended on #{eol_date}"),
|
44
|
+
confidence: :high,
|
45
|
+
gem_info: gemfile_or_environment
|
46
|
+
end
|
47
|
+
end
|
data/lib/brakeman/file_parser.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'parallel'
|
2
|
+
|
1
3
|
module Brakeman
|
2
4
|
ASTFile = Struct.new(:path, :ast)
|
3
5
|
|
@@ -5,29 +7,62 @@ module Brakeman
|
|
5
7
|
class FileParser
|
6
8
|
attr_reader :file_list, :errors
|
7
9
|
|
8
|
-
def initialize app_tree, timeout
|
10
|
+
def initialize app_tree, timeout, parallel = true
|
9
11
|
@app_tree = app_tree
|
10
12
|
@timeout = timeout
|
11
13
|
@file_list = []
|
12
14
|
@errors = []
|
15
|
+
@parallel = parallel
|
13
16
|
end
|
14
17
|
|
15
18
|
def parse_files list
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
+
if @parallel
|
20
|
+
parallel_options = {}
|
21
|
+
else
|
22
|
+
# Disable parallelism
|
23
|
+
parallel_options = { in_threads: 0 }
|
24
|
+
end
|
25
|
+
|
26
|
+
# Parse the files in parallel.
|
27
|
+
# By default, the parsing will be in separate processes.
|
28
|
+
# So we map the result to ASTFiles and/or Exceptions
|
29
|
+
# then partition them into ASTFiles and Exceptions
|
30
|
+
# and add the Exceptions to @errors
|
31
|
+
#
|
32
|
+
# Basically just a funky way to deal with two possible
|
33
|
+
# return types that are returned from isolated processes.
|
34
|
+
#
|
35
|
+
# Note this method no longer uses read_files
|
36
|
+
@file_list, new_errors = Parallel.map(list, parallel_options) do |file_name|
|
37
|
+
file_path = @app_tree.file_path(file_name)
|
38
|
+
contents = file_path.read
|
39
|
+
|
40
|
+
begin
|
41
|
+
if ast = parse_ruby(contents, file_path.relative)
|
42
|
+
ASTFile.new(file_name, ast)
|
43
|
+
end
|
44
|
+
rescue Exception => e
|
45
|
+
e
|
19
46
|
end
|
47
|
+
end.compact.partition do |result|
|
48
|
+
result.is_a? ASTFile
|
20
49
|
end
|
50
|
+
|
51
|
+
errors.concat new_errors
|
21
52
|
end
|
22
53
|
|
23
54
|
def read_files list
|
24
55
|
list.each do |path|
|
25
56
|
file = @app_tree.file_path(path)
|
26
57
|
|
27
|
-
|
58
|
+
begin
|
59
|
+
result = yield file, file.read
|
28
60
|
|
29
|
-
|
30
|
-
|
61
|
+
if result
|
62
|
+
@file_list << result
|
63
|
+
end
|
64
|
+
rescue Exception => e
|
65
|
+
@errors << e
|
31
66
|
end
|
32
67
|
end
|
33
68
|
end
|
@@ -42,17 +77,12 @@ module Brakeman
|
|
42
77
|
Brakeman.debug "Parsing #{path}"
|
43
78
|
RubyParser.new.parse input, path, @timeout
|
44
79
|
rescue Racc::ParseError => e
|
45
|
-
|
80
|
+
raise e.exception(e.message + "\nCould not parse #{path}")
|
46
81
|
rescue Timeout::Error => e
|
47
|
-
|
82
|
+
raise Exception.new("Parsing #{path} took too long (> #{@timeout} seconds). Try increasing the limit with --parser-timeout")
|
48
83
|
rescue => e
|
49
|
-
|
84
|
+
raise e.exception(e.message + "\nWhile processing #{path}")
|
50
85
|
end
|
51
86
|
end
|
52
|
-
|
53
|
-
def error exception
|
54
|
-
@errors << exception
|
55
|
-
nil
|
56
|
-
end
|
57
87
|
end
|
58
88
|
end
|
data/lib/brakeman/options.rb
CHANGED
@@ -39,7 +39,7 @@ module Brakeman::Options
|
|
39
39
|
OptionParser.new do |opts|
|
40
40
|
opts.banner = "Usage: brakeman [options] rails/root/path"
|
41
41
|
|
42
|
-
opts.on "-n", "--no-threads", "Run checks sequentially" do
|
42
|
+
opts.on "-n", "--no-threads", "Run checks and file parsing sequentially" do
|
43
43
|
options[:parallel_checks] = false
|
44
44
|
end
|
45
45
|
|
@@ -93,6 +93,14 @@ module Brakeman::Options
|
|
93
93
|
options[:rails6] = true
|
94
94
|
end
|
95
95
|
|
96
|
+
opts.on "-7", "--rails7", "Force Rails 7 mode" do
|
97
|
+
options[:rails3] = true
|
98
|
+
options[:rails4] = true
|
99
|
+
options[:rails5] = true
|
100
|
+
options[:rails6] = true
|
101
|
+
options[:rails7] = true
|
102
|
+
end
|
103
|
+
|
96
104
|
opts.separator ""
|
97
105
|
opts.separator "Scanning options:"
|
98
106
|
|
@@ -151,6 +159,11 @@ module Brakeman::Options
|
|
151
159
|
options[:safe_methods].merge methods.map {|e| e.to_sym }
|
152
160
|
end
|
153
161
|
|
162
|
+
opts.on "--sql-safe-methods meth1,meth2,etc", Array, "Do not warn of SQL if the input is wrapped in a safe method" do |methods|
|
163
|
+
options[:sql_safe_methods] ||= Set.new
|
164
|
+
options[:sql_safe_methods].merge methods.map {|e| e.to_sym }
|
165
|
+
end
|
166
|
+
|
154
167
|
opts.on "--url-safe-methods method1,method2,etc", Array, "Do not warn of XSS if the link_to href parameter is wrapped in a safe method" do |methods|
|
155
168
|
options[:url_safe_methods] ||= Set.new
|
156
169
|
options[:url_safe_methods].merge methods.map {|e| e.to_sym }
|
@@ -233,7 +246,7 @@ module Brakeman::Options
|
|
233
246
|
|
234
247
|
opts.on "-f",
|
235
248
|
"--format TYPE",
|
236
|
-
[:pdf, :text, :html, :csv, :tabs, :json, :markdown, :codeclimate, :cc, :plain, :table, :junit, :sarif, :sonar],
|
249
|
+
[:pdf, :text, :html, :csv, :tabs, :json, :markdown, :codeclimate, :cc, :plain, :table, :junit, :sarif, :sonar, :github],
|
237
250
|
"Specify output formats. Default is text" do |type|
|
238
251
|
|
239
252
|
type = "s" if type == :text
|
@@ -208,6 +208,15 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
|
|
208
208
|
return Sexp.new(:false).line(exp.line)
|
209
209
|
end
|
210
210
|
|
211
|
+
# For the simplest case of `Foo.thing`
|
212
|
+
if node_type? target, :const and first_arg.nil?
|
213
|
+
if tracker and (klass = tracker.find_class(class_name(target.value)))
|
214
|
+
if return_value = klass.get_simple_method_return_value(:class, method)
|
215
|
+
return return_value.deep_clone(exp.line)
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
211
220
|
#See if it is possible to simplify some basic cases
|
212
221
|
#of addition/concatenation.
|
213
222
|
case method
|
@@ -220,13 +229,28 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
|
|
220
229
|
exp = math_op(:+, target, first_arg, exp)
|
221
230
|
end
|
222
231
|
when :-, :*, :/
|
223
|
-
|
232
|
+
if method == :* and array? target
|
233
|
+
if string? first_arg
|
234
|
+
exp = process_array_join(target, first_arg)
|
235
|
+
end
|
236
|
+
else
|
237
|
+
exp = math_op(method, target, first_arg, exp)
|
238
|
+
end
|
224
239
|
when :[]
|
225
240
|
if array? target
|
226
241
|
exp = process_array_access(target, exp.args, exp)
|
227
242
|
elsif hash? target
|
228
243
|
exp = process_hash_access(target, first_arg, exp)
|
229
244
|
end
|
245
|
+
when :fetch
|
246
|
+
if array? target
|
247
|
+
# Not dealing with default value
|
248
|
+
# so just pass in first argument, but process_array_access expects
|
249
|
+
# an array of arguments.
|
250
|
+
exp = process_array_access(target, [first_arg], exp)
|
251
|
+
elsif hash? target
|
252
|
+
exp = process_hash_access(target, first_arg, exp)
|
253
|
+
end
|
230
254
|
when :merge!, :update
|
231
255
|
if hash? target and hash? first_arg
|
232
256
|
target = process_hash_merge! target, first_arg
|
@@ -266,6 +290,12 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
|
|
266
290
|
target = find_push_target(target_var)
|
267
291
|
env[target] = exp unless target.nil? # Happens in TemplateAliasProcessor
|
268
292
|
end
|
293
|
+
when :push
|
294
|
+
if array? target
|
295
|
+
target << first_arg
|
296
|
+
env[target_var] = target
|
297
|
+
return target
|
298
|
+
end
|
269
299
|
when :first
|
270
300
|
if array? target and first_arg.nil? and sexp? target[1]
|
271
301
|
exp = target[1]
|
@@ -279,7 +309,7 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
|
|
279
309
|
exp = target
|
280
310
|
end
|
281
311
|
when :join
|
282
|
-
if array? target and
|
312
|
+
if array? target and (string? first_arg or first_arg.nil?)
|
283
313
|
exp = process_array_join(target, first_arg)
|
284
314
|
end
|
285
315
|
when :!
|
@@ -287,6 +317,21 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
|
|
287
317
|
if call? target and target.method == :!
|
288
318
|
exp = s(:or, s(:true).line(exp.line), s(:false).line(exp.line)).line(exp.line)
|
289
319
|
end
|
320
|
+
when :values
|
321
|
+
# Hash literal
|
322
|
+
if node_type? target, :hash
|
323
|
+
exp = hash_values(target)
|
324
|
+
end
|
325
|
+
when :values_at
|
326
|
+
if node_type? target, :hash
|
327
|
+
res = hash_values_at target, exp.args
|
328
|
+
|
329
|
+
# Only convert to array of values if _all_ keys
|
330
|
+
# are present in the hash.
|
331
|
+
unless res.any?(&:nil?)
|
332
|
+
exp = res
|
333
|
+
end
|
334
|
+
end
|
290
335
|
end
|
291
336
|
|
292
337
|
exp
|
@@ -294,6 +339,11 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
|
|
294
339
|
|
295
340
|
# Painful conversion of Array#join into string interpolation
|
296
341
|
def process_array_join array, join_str
|
342
|
+
# Empty array
|
343
|
+
if array.length == 1
|
344
|
+
return s(:str, '').line(array.line)
|
345
|
+
end
|
346
|
+
|
297
347
|
result = s().line(array.line)
|
298
348
|
|
299
349
|
join_value = if string? join_str
|
@@ -302,8 +352,10 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
|
|
302
352
|
nil
|
303
353
|
end
|
304
354
|
|
305
|
-
array
|
306
|
-
|
355
|
+
if array.length > 2
|
356
|
+
array[1..-2].each do |e|
|
357
|
+
result << join_item(e, join_value)
|
358
|
+
end
|
307
359
|
end
|
308
360
|
|
309
361
|
result << join_item(array.last, nil)
|
@@ -332,7 +384,7 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
|
|
332
384
|
result.unshift combined_first
|
333
385
|
|
334
386
|
# Have to fix up strings that follow interpolation
|
335
|
-
result.reduce(s(:dstr).line(array.line)) do |memo, e|
|
387
|
+
string = result.reduce(s(:dstr).line(array.line)) do |memo, e|
|
336
388
|
if string? e and node_type? memo.last, :evstr
|
337
389
|
e.value = "#{join_value}#{e.value}"
|
338
390
|
elsif join_value and node_type? memo.last, :evstr and node_type? e, :evstr
|
@@ -341,6 +393,14 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
|
|
341
393
|
|
342
394
|
memo << e
|
343
395
|
end
|
396
|
+
|
397
|
+
# Convert (:dstr, "hello world")
|
398
|
+
# to (:str, "hello world")
|
399
|
+
if string.length == 2 and string.last.is_a? String
|
400
|
+
string[0] = :str
|
401
|
+
end
|
402
|
+
|
403
|
+
string
|
344
404
|
end
|
345
405
|
|
346
406
|
def join_item item, join_value
|
@@ -749,6 +809,18 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
|
|
749
809
|
exp
|
750
810
|
end
|
751
811
|
|
812
|
+
def hash_or_array_include_all_literals? exp
|
813
|
+
return unless call? exp and sexp? exp.target
|
814
|
+
target = exp.target
|
815
|
+
|
816
|
+
case target.node_type
|
817
|
+
when :hash
|
818
|
+
hash_include_all_literals? exp
|
819
|
+
else
|
820
|
+
array_include_all_literals? exp
|
821
|
+
end
|
822
|
+
end
|
823
|
+
|
752
824
|
# Check if exp is a call to Array#include? on an array literal
|
753
825
|
# that contains all literal values. For example:
|
754
826
|
#
|
@@ -767,6 +839,16 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
|
|
767
839
|
(all_literals? exp.target or dir_glob? exp.target)
|
768
840
|
end
|
769
841
|
|
842
|
+
# Check if exp is a call to Hash#include? on a hash literal
|
843
|
+
# that contains all literal values. For example:
|
844
|
+
#
|
845
|
+
# {x: 1}.include? x
|
846
|
+
def hash_include_all_literals? exp
|
847
|
+
call? exp and
|
848
|
+
exp.method == :include? and
|
849
|
+
all_literals? exp.target, :hash
|
850
|
+
end
|
851
|
+
|
770
852
|
#Sets @inside_if = true
|
771
853
|
def process_if exp
|
772
854
|
if @ignore_ifs.nil?
|
@@ -807,7 +889,7 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
|
|
807
889
|
scope do
|
808
890
|
@branch_env = env.current
|
809
891
|
branch_index = 2 + i # s(:if, condition, then_branch, else_branch)
|
810
|
-
if i == 0 and
|
892
|
+
if i == 0 and hash_or_array_include_all_literals? condition
|
811
893
|
# If the condition is ["a", "b"].include? x
|
812
894
|
# set x to "a" inside the true branch
|
813
895
|
var = condition.first_arg
|
@@ -815,7 +897,7 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
|
|
815
897
|
env.current[var] = safe_literal(var.line)
|
816
898
|
exp[branch_index] = process_if_branch branch
|
817
899
|
env.current[var] = previous_value
|
818
|
-
elsif i == 1 and
|
900
|
+
elsif i == 1 and hash_or_array_include_all_literals? condition and early_return? branch
|
819
901
|
var = condition.first_arg
|
820
902
|
env.current[var] = safe_literal(var.line)
|
821
903
|
exp[branch_index] = process_if_branch branch
|
@@ -1013,8 +1095,8 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
|
|
1013
1095
|
method_name = call.method
|
1014
1096
|
|
1015
1097
|
#Look for helper methods and see if we can get a return value
|
1016
|
-
if found_method = find_method(method_name, @current_class)
|
1017
|
-
helper = found_method
|
1098
|
+
if found_method = tracker.find_method(method_name, @current_class)
|
1099
|
+
helper = found_method.src
|
1018
1100
|
|
1019
1101
|
if sexp? helper
|
1020
1102
|
value = process_helper_method helper, call.args
|
@@ -51,7 +51,7 @@ class Brakeman::ControllerAliasProcessor < Brakeman::AliasProcessor
|
|
51
51
|
#Need to process the method like it was in a controller in order
|
52
52
|
#to get the renders set
|
53
53
|
processor = Brakeman::ControllerProcessor.new(@tracker, mixin.file)
|
54
|
-
method = mixin.get_method(name)
|
54
|
+
method = mixin.get_method(name).src.deep_clone
|
55
55
|
|
56
56
|
if node_type? method, :defn
|
57
57
|
method = processor.process_defn method
|
@@ -143,16 +143,16 @@ class Brakeman::ControllerAliasProcessor < Brakeman::AliasProcessor
|
|
143
143
|
#Basically, adds any instance variable assignments to the environment.
|
144
144
|
#TODO: method arguments?
|
145
145
|
def process_before_filter name
|
146
|
-
filter = find_method name, @current_class
|
146
|
+
filter = tracker.find_method name, @current_class
|
147
147
|
|
148
148
|
if filter.nil?
|
149
149
|
Brakeman.debug "[Notice] Could not find filter #{name}"
|
150
150
|
return
|
151
151
|
end
|
152
152
|
|
153
|
-
method = filter
|
153
|
+
method = filter.src
|
154
154
|
|
155
|
-
if ivars = @tracker.filter_cache[[filter
|
155
|
+
if ivars = @tracker.filter_cache[[filter.owner, name]]
|
156
156
|
ivars.each do |variable, value|
|
157
157
|
env[variable] = value
|
158
158
|
end
|
@@ -162,7 +162,7 @@ class Brakeman::ControllerAliasProcessor < Brakeman::AliasProcessor
|
|
162
162
|
|
163
163
|
ivars = processor.only_ivars(:include_request_vars).all
|
164
164
|
|
165
|
-
@tracker.filter_cache[[filter
|
165
|
+
@tracker.filter_cache[[filter.owner, name]] = ivars
|
166
166
|
|
167
167
|
ivars.each do |variable, value|
|
168
168
|
env[variable] = value
|
@@ -182,7 +182,7 @@ class Brakeman::ControllerAliasProcessor < Brakeman::AliasProcessor
|
|
182
182
|
# method as the line number
|
183
183
|
if line.nil? and controller = @tracker.controllers[@current_class]
|
184
184
|
if meth = controller.get_method(@current_method)
|
185
|
-
if line = meth
|
185
|
+
if line = meth.src && meth.src.last && meth.src.last.line
|
186
186
|
line += 1
|
187
187
|
else
|
188
188
|
line = 1
|
@@ -241,41 +241,4 @@ class Brakeman::ControllerAliasProcessor < Brakeman::AliasProcessor
|
|
241
241
|
[]
|
242
242
|
end
|
243
243
|
end
|
244
|
-
|
245
|
-
#Finds a method in the given class or a parent class
|
246
|
-
#
|
247
|
-
#Returns nil if the method could not be found.
|
248
|
-
#
|
249
|
-
#If found, returns hash table with controller name and method sexp.
|
250
|
-
def find_method method_name, klass
|
251
|
-
return nil if sexp? method_name
|
252
|
-
method_name = method_name.to_sym
|
253
|
-
|
254
|
-
if method = @method_cache[method_name]
|
255
|
-
return method
|
256
|
-
end
|
257
|
-
|
258
|
-
controller = @tracker.controllers[klass]
|
259
|
-
controller ||= @tracker.libs[klass]
|
260
|
-
|
261
|
-
if klass and controller
|
262
|
-
method = controller.get_method method_name
|
263
|
-
|
264
|
-
if method.nil?
|
265
|
-
controller.includes.each do |included|
|
266
|
-
method = find_method method_name, included
|
267
|
-
if method
|
268
|
-
@method_cache[method_name] = method
|
269
|
-
return method
|
270
|
-
end
|
271
|
-
end
|
272
|
-
|
273
|
-
@method_cache[method_name] = find_method method_name, controller.parent
|
274
|
-
else
|
275
|
-
@method_cache[method_name] = { :controller => controller.name, :method => method[:src] }
|
276
|
-
end
|
277
|
-
else
|
278
|
-
nil
|
279
|
-
end
|
280
|
-
end
|
281
244
|
end
|
@@ -6,6 +6,7 @@ class Brakeman::GemProcessor < Brakeman::BasicProcessor
|
|
6
6
|
def initialize *args
|
7
7
|
super
|
8
8
|
@gem_name_version = /^\s*([-_+.A-Za-z0-9]+) \((\w(\.\w+)*)\)/
|
9
|
+
@ruby_version = /^\s+ruby (\d\.\d.\d+)/
|
9
10
|
end
|
10
11
|
|
11
12
|
def process_gems gem_files
|
@@ -95,6 +96,8 @@ class Brakeman::GemProcessor < Brakeman::BasicProcessor
|
|
95
96
|
def set_gem_version_and_file line, file, line_num
|
96
97
|
if line =~ @gem_name_version
|
97
98
|
@tracker.config.add_gem $1, $2, file, line_num
|
99
|
+
elsif line =~ @ruby_version
|
100
|
+
@tracker.config.set_ruby_version $1
|
98
101
|
end
|
99
102
|
end
|
100
103
|
end
|
@@ -8,6 +8,7 @@ class Brakeman::HamlTemplateProcessor < Brakeman::TemplateProcessor
|
|
8
8
|
HAML_HELPERS2 = s(:colon2, s(:colon3, :Haml), :Helpers)
|
9
9
|
JAVASCRIPT_FILTER = s(:colon2, s(:colon2, s(:const, :Haml), :Filters), :Javascript)
|
10
10
|
COFFEE_FILTER = s(:colon2, s(:colon2, s(:const, :Haml), :Filters), :Coffee)
|
11
|
+
ATTRIBUTE_BUILDER = s(:colon2, s(:colon3, :Haml), :AttributeBuilder)
|
11
12
|
|
12
13
|
def initialize *args
|
13
14
|
super
|
@@ -133,6 +134,8 @@ class Brakeman::HamlTemplateProcessor < Brakeman::TemplateProcessor
|
|
133
134
|
|
134
135
|
get_pushed_value(exp.first_arg, default)
|
135
136
|
@javascript = false
|
137
|
+
elsif haml_attribute_builder? exp
|
138
|
+
ignore # probably safe... seems escaped by default?
|
136
139
|
else
|
137
140
|
add_output exp, default
|
138
141
|
end
|
@@ -154,6 +157,12 @@ class Brakeman::HamlTemplateProcessor < Brakeman::TemplateProcessor
|
|
154
157
|
exp.method == :attributes
|
155
158
|
end
|
156
159
|
|
160
|
+
def haml_attribute_builder? exp
|
161
|
+
call? exp and
|
162
|
+
exp.target == ATTRIBUTE_BUILDER and
|
163
|
+
exp.method == :build
|
164
|
+
end
|
165
|
+
|
157
166
|
def fix_textareas? exp
|
158
167
|
call? exp and
|
159
168
|
exp.target == HAMLOUT and
|
@@ -1,11 +1,5 @@
|
|
1
1
|
module Brakeman
|
2
2
|
module CallConversionHelper
|
3
|
-
def all_literals? exp, expected_type = :array
|
4
|
-
node_type? exp, expected_type and
|
5
|
-
exp.length > 1 and
|
6
|
-
exp.all? { |e| e.is_a? Symbol or node_type? e, :lit, :str }
|
7
|
-
end
|
8
|
-
|
9
3
|
# Join two array literals into one.
|
10
4
|
def join_arrays lhs, rhs, original_exp = nil
|
11
5
|
if array? lhs and array? rhs
|
@@ -76,6 +70,8 @@ module Brakeman
|
|
76
70
|
|
77
71
|
#Have to do this because first element is :array and we have to skip it
|
78
72
|
array[1..-1][index] or original_exp
|
73
|
+
elsif all_literals? array
|
74
|
+
safe_literal(array.line)
|
79
75
|
else
|
80
76
|
original_exp
|
81
77
|
end
|
@@ -92,5 +88,15 @@ module Brakeman
|
|
92
88
|
original_exp
|
93
89
|
end
|
94
90
|
end
|
91
|
+
|
92
|
+
# You must check the return value for `nil`s -
|
93
|
+
# which indicate a key could not be found.
|
94
|
+
def hash_values_at hash, keys
|
95
|
+
values = keys.map do |key|
|
96
|
+
process_hash_access hash, key
|
97
|
+
end
|
98
|
+
|
99
|
+
Sexp.new(:array).concat(values).line(hash.line)
|
100
|
+
end
|
95
101
|
end
|
96
102
|
end
|