brakeman-lib 3.3.1

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 (159) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGES +872 -0
  3. data/FEATURES +16 -0
  4. data/README.md +169 -0
  5. data/WARNING_TYPES +95 -0
  6. data/bin/brakeman +89 -0
  7. data/lib/brakeman.rb +495 -0
  8. data/lib/brakeman/app_tree.rb +161 -0
  9. data/lib/brakeman/brakeman.rake +17 -0
  10. data/lib/brakeman/call_index.rb +219 -0
  11. data/lib/brakeman/checks.rb +191 -0
  12. data/lib/brakeman/checks/base_check.rb +518 -0
  13. data/lib/brakeman/checks/check_basic_auth.rb +88 -0
  14. data/lib/brakeman/checks/check_basic_auth_timing_attack.rb +33 -0
  15. data/lib/brakeman/checks/check_content_tag.rb +160 -0
  16. data/lib/brakeman/checks/check_create_with.rb +75 -0
  17. data/lib/brakeman/checks/check_cross_site_scripting.rb +385 -0
  18. data/lib/brakeman/checks/check_default_routes.rb +86 -0
  19. data/lib/brakeman/checks/check_deserialize.rb +57 -0
  20. data/lib/brakeman/checks/check_detailed_exceptions.rb +55 -0
  21. data/lib/brakeman/checks/check_digest_dos.rb +38 -0
  22. data/lib/brakeman/checks/check_dynamic_finders.rb +49 -0
  23. data/lib/brakeman/checks/check_escape_function.rb +21 -0
  24. data/lib/brakeman/checks/check_evaluation.rb +36 -0
  25. data/lib/brakeman/checks/check_execute.rb +167 -0
  26. data/lib/brakeman/checks/check_file_access.rb +63 -0
  27. data/lib/brakeman/checks/check_file_disclosure.rb +35 -0
  28. data/lib/brakeman/checks/check_filter_skipping.rb +31 -0
  29. data/lib/brakeman/checks/check_forgery_setting.rb +74 -0
  30. data/lib/brakeman/checks/check_header_dos.rb +31 -0
  31. data/lib/brakeman/checks/check_i18n_xss.rb +48 -0
  32. data/lib/brakeman/checks/check_jruby_xml.rb +38 -0
  33. data/lib/brakeman/checks/check_json_encoding.rb +47 -0
  34. data/lib/brakeman/checks/check_json_parsing.rb +107 -0
  35. data/lib/brakeman/checks/check_link_to.rb +132 -0
  36. data/lib/brakeman/checks/check_link_to_href.rb +115 -0
  37. data/lib/brakeman/checks/check_mail_to.rb +49 -0
  38. data/lib/brakeman/checks/check_mass_assignment.rb +198 -0
  39. data/lib/brakeman/checks/check_mime_type_dos.rb +39 -0
  40. data/lib/brakeman/checks/check_model_attr_accessible.rb +55 -0
  41. data/lib/brakeman/checks/check_model_attributes.rb +119 -0
  42. data/lib/brakeman/checks/check_model_serialize.rb +67 -0
  43. data/lib/brakeman/checks/check_nested_attributes.rb +38 -0
  44. data/lib/brakeman/checks/check_nested_attributes_bypass.rb +58 -0
  45. data/lib/brakeman/checks/check_number_to_currency.rb +74 -0
  46. data/lib/brakeman/checks/check_quote_table_name.rb +40 -0
  47. data/lib/brakeman/checks/check_redirect.rb +215 -0
  48. data/lib/brakeman/checks/check_regex_dos.rb +69 -0
  49. data/lib/brakeman/checks/check_render.rb +92 -0
  50. data/lib/brakeman/checks/check_render_dos.rb +37 -0
  51. data/lib/brakeman/checks/check_render_inline.rb +54 -0
  52. data/lib/brakeman/checks/check_response_splitting.rb +21 -0
  53. data/lib/brakeman/checks/check_route_dos.rb +42 -0
  54. data/lib/brakeman/checks/check_safe_buffer_manipulation.rb +31 -0
  55. data/lib/brakeman/checks/check_sanitize_methods.rb +79 -0
  56. data/lib/brakeman/checks/check_secrets.rb +40 -0
  57. data/lib/brakeman/checks/check_select_tag.rb +60 -0
  58. data/lib/brakeman/checks/check_select_vulnerability.rb +60 -0
  59. data/lib/brakeman/checks/check_send.rb +48 -0
  60. data/lib/brakeman/checks/check_send_file.rb +19 -0
  61. data/lib/brakeman/checks/check_session_manipulation.rb +36 -0
  62. data/lib/brakeman/checks/check_session_settings.rb +170 -0
  63. data/lib/brakeman/checks/check_simple_format.rb +59 -0
  64. data/lib/brakeman/checks/check_single_quotes.rb +101 -0
  65. data/lib/brakeman/checks/check_skip_before_filter.rb +60 -0
  66. data/lib/brakeman/checks/check_sql.rb +660 -0
  67. data/lib/brakeman/checks/check_sql_cves.rb +101 -0
  68. data/lib/brakeman/checks/check_ssl_verify.rb +49 -0
  69. data/lib/brakeman/checks/check_strip_tags.rb +89 -0
  70. data/lib/brakeman/checks/check_symbol_dos.rb +64 -0
  71. data/lib/brakeman/checks/check_symbol_dos_cve.rb +30 -0
  72. data/lib/brakeman/checks/check_translate_bug.rb +45 -0
  73. data/lib/brakeman/checks/check_unsafe_reflection.rb +51 -0
  74. data/lib/brakeman/checks/check_unscoped_find.rb +41 -0
  75. data/lib/brakeman/checks/check_validation_regex.rb +116 -0
  76. data/lib/brakeman/checks/check_weak_hash.rb +151 -0
  77. data/lib/brakeman/checks/check_without_protection.rb +80 -0
  78. data/lib/brakeman/checks/check_xml_dos.rb +51 -0
  79. data/lib/brakeman/checks/check_yaml_parsing.rb +121 -0
  80. data/lib/brakeman/differ.rb +66 -0
  81. data/lib/brakeman/file_parser.rb +50 -0
  82. data/lib/brakeman/format/style.css +133 -0
  83. data/lib/brakeman/options.rb +301 -0
  84. data/lib/brakeman/parsers/rails2_erubis.rb +6 -0
  85. data/lib/brakeman/parsers/rails2_xss_plugin_erubis.rb +48 -0
  86. data/lib/brakeman/parsers/rails3_erubis.rb +74 -0
  87. data/lib/brakeman/parsers/template_parser.rb +89 -0
  88. data/lib/brakeman/processor.rb +102 -0
  89. data/lib/brakeman/processors/alias_processor.rb +1013 -0
  90. data/lib/brakeman/processors/base_processor.rb +277 -0
  91. data/lib/brakeman/processors/config_processor.rb +14 -0
  92. data/lib/brakeman/processors/controller_alias_processor.rb +273 -0
  93. data/lib/brakeman/processors/controller_processor.rb +326 -0
  94. data/lib/brakeman/processors/erb_template_processor.rb +80 -0
  95. data/lib/brakeman/processors/erubis_template_processor.rb +104 -0
  96. data/lib/brakeman/processors/gem_processor.rb +57 -0
  97. data/lib/brakeman/processors/haml_template_processor.rb +190 -0
  98. data/lib/brakeman/processors/lib/basic_processor.rb +37 -0
  99. data/lib/brakeman/processors/lib/find_all_calls.rb +223 -0
  100. data/lib/brakeman/processors/lib/find_call.rb +183 -0
  101. data/lib/brakeman/processors/lib/find_return_value.rb +134 -0
  102. data/lib/brakeman/processors/lib/processor_helper.rb +75 -0
  103. data/lib/brakeman/processors/lib/rails2_config_processor.rb +145 -0
  104. data/lib/brakeman/processors/lib/rails2_route_processor.rb +313 -0
  105. data/lib/brakeman/processors/lib/rails3_config_processor.rb +132 -0
  106. data/lib/brakeman/processors/lib/rails3_route_processor.rb +308 -0
  107. data/lib/brakeman/processors/lib/render_helper.rb +181 -0
  108. data/lib/brakeman/processors/lib/render_path.rb +107 -0
  109. data/lib/brakeman/processors/lib/route_helper.rb +68 -0
  110. data/lib/brakeman/processors/lib/safe_call_helper.rb +16 -0
  111. data/lib/brakeman/processors/library_processor.rb +119 -0
  112. data/lib/brakeman/processors/model_processor.rb +191 -0
  113. data/lib/brakeman/processors/output_processor.rb +171 -0
  114. data/lib/brakeman/processors/route_processor.rb +17 -0
  115. data/lib/brakeman/processors/slim_template_processor.rb +107 -0
  116. data/lib/brakeman/processors/template_alias_processor.rb +116 -0
  117. data/lib/brakeman/processors/template_processor.rb +74 -0
  118. data/lib/brakeman/report.rb +78 -0
  119. data/lib/brakeman/report/config/remediation.yml +71 -0
  120. data/lib/brakeman/report/ignore/config.rb +135 -0
  121. data/lib/brakeman/report/ignore/interactive.rb +311 -0
  122. data/lib/brakeman/report/renderer.rb +24 -0
  123. data/lib/brakeman/report/report_base.rb +286 -0
  124. data/lib/brakeman/report/report_codeclimate.rb +70 -0
  125. data/lib/brakeman/report/report_csv.rb +55 -0
  126. data/lib/brakeman/report/report_hash.rb +23 -0
  127. data/lib/brakeman/report/report_html.rb +216 -0
  128. data/lib/brakeman/report/report_json.rb +42 -0
  129. data/lib/brakeman/report/report_markdown.rb +156 -0
  130. data/lib/brakeman/report/report_table.rb +107 -0
  131. data/lib/brakeman/report/report_tabs.rb +17 -0
  132. data/lib/brakeman/report/templates/controller_overview.html.erb +22 -0
  133. data/lib/brakeman/report/templates/controller_warnings.html.erb +21 -0
  134. data/lib/brakeman/report/templates/error_overview.html.erb +29 -0
  135. data/lib/brakeman/report/templates/header.html.erb +58 -0
  136. data/lib/brakeman/report/templates/ignored_warnings.html.erb +25 -0
  137. data/lib/brakeman/report/templates/model_warnings.html.erb +21 -0
  138. data/lib/brakeman/report/templates/overview.html.erb +38 -0
  139. data/lib/brakeman/report/templates/security_warnings.html.erb +23 -0
  140. data/lib/brakeman/report/templates/template_overview.html.erb +21 -0
  141. data/lib/brakeman/report/templates/view_warnings.html.erb +34 -0
  142. data/lib/brakeman/report/templates/warning_overview.html.erb +17 -0
  143. data/lib/brakeman/rescanner.rb +483 -0
  144. data/lib/brakeman/scanner.rb +317 -0
  145. data/lib/brakeman/tracker.rb +347 -0
  146. data/lib/brakeman/tracker/collection.rb +93 -0
  147. data/lib/brakeman/tracker/config.rb +101 -0
  148. data/lib/brakeman/tracker/constants.rb +101 -0
  149. data/lib/brakeman/tracker/controller.rb +161 -0
  150. data/lib/brakeman/tracker/library.rb +17 -0
  151. data/lib/brakeman/tracker/model.rb +90 -0
  152. data/lib/brakeman/tracker/template.rb +33 -0
  153. data/lib/brakeman/util.rb +481 -0
  154. data/lib/brakeman/version.rb +3 -0
  155. data/lib/brakeman/warning.rb +255 -0
  156. data/lib/brakeman/warning_codes.rb +111 -0
  157. data/lib/ruby_parser/bm_sexp.rb +610 -0
  158. data/lib/ruby_parser/bm_sexp_processor.rb +116 -0
  159. metadata +362 -0
@@ -0,0 +1,116 @@
1
+ require 'set'
2
+ require 'brakeman/processors/alias_processor'
3
+ require 'brakeman/processors/lib/render_helper'
4
+ require 'brakeman/processors/lib/render_path'
5
+ require 'brakeman/tracker'
6
+
7
+ #Processes aliasing in templates.
8
+ #Handles calls to +render+.
9
+ class Brakeman::TemplateAliasProcessor < Brakeman::AliasProcessor
10
+ include Brakeman::RenderHelper
11
+
12
+ FORM_METHODS = Set[:form_for, :remote_form_for, :form_remote_for]
13
+
14
+ def initialize tracker, template, called_from = nil
15
+ super tracker
16
+ @template = template
17
+ @called_from = called_from
18
+ end
19
+
20
+ #Process template
21
+ def process_template name, args, _, line = nil, file_name = nil
22
+ @file_name = file_name || relative_path(@template.file || @tracker.templates[@template.name])
23
+
24
+ if @called_from
25
+ if @called_from.include_template? name
26
+ Brakeman.debug "Skipping circular render from #{@template.name} to #{name}"
27
+ return
28
+ end
29
+
30
+ super name, args, @called_from.dup.add_template_render(@template.name, line, @file_name)
31
+ else
32
+ super name, args, Brakeman::RenderPath.new.add_template_render(@template.name, line, @file_name)
33
+ end
34
+ end
35
+
36
+ #Determine template name
37
+ def template_name name
38
+ if !name.to_s.include?('/') && @template.name.to_s.include?('/')
39
+ name = "#{@template.name.to_s.match(/^(.*\/).*$/)[1]}#{name}"
40
+ end
41
+ name
42
+ end
43
+
44
+ UNKNOWN_MODEL_CALL = Sexp.new(:call, Sexp.new(:const, Brakeman::Tracker::UNKNOWN_MODEL), :new)
45
+ FORM_BUILDER_CALL = Sexp.new(:call, Sexp.new(:const, :FormBuilder), :new)
46
+
47
+ #Looks for form methods and iterating over collections of Models
48
+ def process_iter exp
49
+ process_default exp
50
+
51
+ call = exp.block_call
52
+
53
+ if call? call
54
+ target = call.target
55
+ method = call.method
56
+ arg = exp.block_args.first_param
57
+ block = exp.block
58
+
59
+ #Check for e.g. Model.find.each do ... end
60
+ if method == :each and arg and block and model = get_model_target(target)
61
+ if arg.is_a? Symbol
62
+ if model == target.target
63
+ env[Sexp.new(:lvar, arg)] = Sexp.new(:call, model, :new)
64
+ else
65
+ env[Sexp.new(:lvar, arg)] = UNKNOWN_MODEL_CALL
66
+ end
67
+
68
+ process block if sexp? block
69
+ end
70
+ elsif FORM_METHODS.include? method
71
+ if arg.is_a? Symbol
72
+ env[Sexp.new(:lvar, arg)] = FORM_BUILDER_CALL
73
+
74
+ process block if sexp? block
75
+ end
76
+ end
77
+ end
78
+
79
+ exp
80
+ end
81
+
82
+ #Checks if +exp+ is a call to Model.all or Model.find*
83
+ def get_model_target exp
84
+ if call? exp
85
+ target = exp.target
86
+
87
+ if exp.method == :all or exp.method.to_s[0,4] == "find"
88
+ models = Set.new @tracker.models.keys
89
+ name = class_name target
90
+ return target if models.include?(name)
91
+ end
92
+
93
+ return get_model_target(target)
94
+ end
95
+
96
+ false
97
+ end
98
+
99
+ #Ignore `<<` calls on template variables which are used by the templating
100
+ #library (HAML, ERB, etc.)
101
+ def find_push_target exp
102
+ if sexp? exp
103
+ if exp.node_type == :lvar and (exp.value == :_buf or exp.value == :_erbout)
104
+ return nil
105
+ elsif exp.node_type == :ivar and exp.value == :@output_buffer
106
+ return nil
107
+ elsif exp.node_type == :call and call? exp.target and
108
+ exp.target.method == :_hamlout and exp.method == :buffer
109
+
110
+ return nil
111
+ end
112
+ end
113
+
114
+ super
115
+ end
116
+ end
@@ -0,0 +1,74 @@
1
+ require 'brakeman/processors/base_processor'
2
+ require 'brakeman/tracker/template'
3
+
4
+ #Base Processor for templates/views
5
+ class Brakeman::TemplateProcessor < Brakeman::BaseProcessor
6
+
7
+ #Initializes template information.
8
+ def initialize tracker, template_name, called_from = nil, file_name = nil
9
+ super(tracker)
10
+ @current_template = Brakeman::Template.new template_name, called_from, file_name, tracker
11
+ @file_name = file_name
12
+
13
+ if called_from
14
+ template_name = (template_name.to_s + "." + called_from.to_s).to_sym
15
+ end
16
+
17
+ tracker.templates[template_name] = @current_template
18
+
19
+ @inside_concat = false
20
+ end
21
+
22
+ #Process the template Sexp.
23
+ def process exp
24
+ begin
25
+ super
26
+ rescue => e
27
+ except = e.exception("Error when processing #{@current_template.name}: #{e.message}")
28
+ except.set_backtrace(e.backtrace)
29
+ raise except
30
+ end
31
+ end
32
+
33
+ #Ignore initial variable assignment
34
+ def process_lasgn exp
35
+ if exp.lhs == :_erbout and exp.rhs.node_type == :str #ignore
36
+ ignore
37
+ elsif exp.lhs == :_buf and exp.rhs.node_type == :str
38
+ ignore
39
+ else
40
+ exp.rhs = process exp.rhs
41
+ exp
42
+ end
43
+ end
44
+
45
+ #Adds output to the list of outputs.
46
+ def process_output exp
47
+ exp.value = process exp.value
48
+ @current_template.add_output exp unless exp.original_line
49
+ exp
50
+ end
51
+
52
+ def process_escaped_output exp
53
+ process_output exp
54
+ end
55
+
56
+ # Pull out actual output value from template
57
+ def normalize_output arg
58
+ if call? arg and [:to_s, :html_safe!, :freeze].include? arg.method
59
+ arg.target
60
+ elsif node_type? arg, :if
61
+ branches = [arg.then_clause, arg.else_clause].compact
62
+
63
+ if branches.empty?
64
+ s(:nil)
65
+ elsif branches.length == 2
66
+ Sexp.new(:or, *branches)
67
+ else
68
+ branches.first
69
+ end
70
+ else
71
+ arg
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,78 @@
1
+ require 'brakeman/report/report_base'
2
+
3
+ #Generates a report based on the Tracker and the results of
4
+ #Tracker#run_checks. Be sure to +run_checks+ before generating
5
+ #a report.
6
+ class Brakeman::Report
7
+ attr_reader :tracker
8
+
9
+ VALID_FORMATS = [:to_html, :to_pdf, :to_csv, :to_json, :to_tabs, :to_hash, :to_s, :to_markdown, :to_codeclimate]
10
+
11
+ def initialize app_tree, tracker
12
+ @app_tree = app_tree
13
+ @tracker = tracker
14
+ end
15
+
16
+ def format format
17
+ reporter = case format
18
+ when :to_codeclimate
19
+ require_report 'codeclimate'
20
+ Brakeman::Report::CodeClimate
21
+ when :to_csv
22
+ require_report 'csv'
23
+ Brakeman::Report::CSV
24
+ when :to_html
25
+ require_report 'html'
26
+ Brakeman::Report::HTML
27
+ when :to_json
28
+ return self.to_json
29
+ when :to_tabs
30
+ require_report 'tabs'
31
+ Brakeman::Report::Tabs
32
+ when :to_hash
33
+ require_report 'hash'
34
+ Brakeman::Report::Hash
35
+ when :to_markdown
36
+ return self.to_markdown
37
+ when :to_s
38
+ return self.to_s
39
+ when :to_pdf
40
+ raise "PDF output is not yet supported."
41
+ else
42
+ raise "Invalid format: #{format}. Should be one of #{VALID_FORMATS.inspect}"
43
+ end
44
+
45
+ generate(reporter)
46
+ end
47
+
48
+ def method_missing method, *args
49
+ if VALID_FORMATS.include? method
50
+ format method
51
+ else
52
+ super
53
+ end
54
+ end
55
+
56
+ def require_report type
57
+ require "brakeman/report/report_#{type}"
58
+ end
59
+
60
+ def to_json
61
+ require_report 'json'
62
+ generate Brakeman::Report::JSON
63
+ end
64
+
65
+ def to_s
66
+ require_report 'table'
67
+ generate Brakeman::Report::Table
68
+ end
69
+
70
+ def to_markdown
71
+ require_report 'markdown'
72
+ generate Brakeman::Report::Markdown
73
+ end
74
+
75
+ def generate reporter
76
+ reporter.new(@app_tree, @tracker).generate_report
77
+ end
78
+ end
@@ -0,0 +1,71 @@
1
+ ---
2
+ basic_auth_password: 300000
3
+ cross_site_scripting: 300000
4
+ xss_content_tag: 300000
5
+ CVE_2014_3514_call: 600000
6
+ all_default_routes: 2000000
7
+ unsafe_deserialize: 2000000
8
+ local_request_config: 100000
9
+ CVE_2012_3424: 4000000
10
+ CVE_2011_2932: 8000000
11
+ code_eval: 2000000
12
+ command_injection: 2000000
13
+ file_access: 2000000
14
+ CVE_2014_7829: 4000000
15
+ CVE_2011_2929: 4000000
16
+ csrf_protection_disabled: 4000000
17
+ CVE_2013_6414: 4000000
18
+ CVE_2013_4491: 4000000
19
+ CVE_2013_1856: 4000000
20
+ CVE_2015_3226: 4000000
21
+ CVE_2013_0333: 4000000
22
+ xss_link_to: 300000
23
+ xss_link_to_href: 300000
24
+ CVE_2011_0446: 300000
25
+ mass_assign_call: 2000000
26
+ dangerous_attr_accessible: 2000000
27
+ no_attr_accessible: 2000000
28
+ CVE_2013_0277: 2000000
29
+ CVE_2010_3933: 4000000
30
+ CVE_2014_0081: 300000
31
+ CVE_2011_2930: 600000
32
+ open_redirect: 300000
33
+ regex_dos: 600000
34
+ dynamic_render_path: 4000000
35
+ CVE_2014_0082: 4000000
36
+ cross_site_scripting_inline: 600000
37
+ CVE_2011_3186: 2000000
38
+ safe_buffer_vuln: 4000000
39
+ CVE_2013_1855: 4000000
40
+ CVE_2013_1857: 4000000
41
+ CVE_2012_3463: 600000
42
+ select_options_vuln: 4000000
43
+ dangerous_send: 600000
44
+ session_key_manipulation: 600000
45
+ http_cookies: 600000
46
+ session_secret: 600000
47
+ secure_cookies: 600000
48
+ CVE_2013_6416: 600000
49
+ CVE_2012_3464: 4000000
50
+ csrf_blacklist: 300000
51
+ auth_blacklist: 300000
52
+ sql_injection: 1200000
53
+ CVE-2012-2660: 4000000
54
+ CVE-2012-2661: 4000000
55
+ CVE-2012-2695: 4000000
56
+ CVE-2012-5664: 4000000
57
+ CVE-2013-0155: 4000000
58
+ CVE-2013-6417: 4000000
59
+ CVE-2014-3482: 4000000
60
+ CVE-2014-3483: 4000000
61
+ ssl_verification_bypass: 2500000
62
+ CVE_2011_2931: 4000000
63
+ unsafe_symbol_creation: 300000
64
+ translate_vuln: 300000
65
+ unsafe_constantize: 600000
66
+ unscoped_find: 300000
67
+ validation_regex: 300000
68
+ mass_assign_without_protection: 600000
69
+ CVE_2015_3227: 4000000
70
+ CVE_2013_0156: 4000000
71
+ weak_hash_digest: 800000
@@ -0,0 +1,135 @@
1
+ require 'set'
2
+ require 'json'
3
+
4
+ module Brakeman
5
+ class IgnoreConfig
6
+ attr_reader :shown_warnings, :ignored_warnings
7
+ attr_accessor :file
8
+
9
+ def initialize file, new_warnings
10
+ @file = file
11
+ @new_warnings = new_warnings
12
+ @already_ignored = []
13
+ @ignored_fingerprints = Set.new
14
+ @notes = {}
15
+ @shown_warnings = @ignored_warnings = nil
16
+ @changed = false
17
+ end
18
+
19
+ # Populate ignored_warnings and shown_warnings based on ignore
20
+ # configuration
21
+ def filter_ignored
22
+ @shown_warnings = []
23
+ @ignored_warnings = []
24
+
25
+ @new_warnings.each do |w|
26
+ if ignored? w
27
+ @ignored_warnings << w
28
+ else
29
+ @shown_warnings << w
30
+ end
31
+ end
32
+
33
+ @shown_warnings
34
+ end
35
+
36
+ # Remove warning from ignored list
37
+ def unignore warning
38
+ @ignored_fingerprints.delete warning.fingerprint
39
+ if @already_ignored.reject! { |w|w[:fingerprint] == warning.fingerprint }
40
+ @changed = true
41
+ end
42
+ end
43
+
44
+ # Determine if warning should be ignored
45
+ def ignored? warning
46
+ @ignored_fingerprints.include? warning.fingerprint
47
+ end
48
+
49
+ def ignore warning
50
+ @changed = true unless ignored? warning
51
+ @ignored_fingerprints << warning.fingerprint
52
+ end
53
+
54
+ # Add note for warning
55
+ def add_note warning, note
56
+ @changed = true
57
+ @notes[warning.fingerprint] = note
58
+ end
59
+
60
+ # Retrieve note for warning if it exists. Returns nil if no
61
+ # note is found
62
+ def note_for warning
63
+ if warning.is_a? Warning
64
+ fingerprint = warning.fingerprint
65
+ else
66
+ fingerprint = warning[:fingerprint]
67
+ end
68
+
69
+ @already_ignored.each do |w|
70
+ if fingerprint == w[:fingerprint]
71
+ return w[:note]
72
+ end
73
+ end
74
+
75
+ nil
76
+ end
77
+
78
+ # Read configuration to file
79
+ def read_from_file file = @file
80
+ if File.exist? file
81
+ @already_ignored = JSON.parse(File.read(file), :symbolize_names => true)[:ignored_warnings]
82
+ else
83
+ Brakeman.notify "[Notice] Could not find ignore configuration in #{file}"
84
+ @already_ignored = []
85
+ end
86
+
87
+ @already_ignored.each do |w|
88
+ @ignored_fingerprints << w[:fingerprint]
89
+ @notes[w[:fingerprint]] = w[:note]
90
+ end
91
+ end
92
+
93
+ # Save configuration to file
94
+ def save_to_file warnings, file = @file
95
+ warnings = warnings.map do |w|
96
+ if w.is_a? Warning
97
+ w_hash = w.to_hash
98
+ w_hash[:file] = w.relative_path
99
+ w = w_hash
100
+ end
101
+
102
+ w[:note] = @notes[w[:fingerprint]] || ""
103
+ w
104
+ end.sort_by { |w| w[:fingerprint] }
105
+
106
+ output = {
107
+ :ignored_warnings => warnings,
108
+ :updated => Time.now.to_s,
109
+ :brakeman_version => Brakeman::Version
110
+ }
111
+
112
+ File.open file, "w" do |f|
113
+ f.puts JSON.pretty_generate(output)
114
+ end
115
+ end
116
+
117
+ # Save old ignored warnings and newly ignored ones
118
+ def save_with_old
119
+ warnings = @ignored_warnings.dup
120
+
121
+ # Only add ignored warnings not already ignored
122
+ @already_ignored.each do |w|
123
+ fingerprint = w[:fingerprint]
124
+
125
+ unless @ignored_warnings.find { |ignored_warning| ignored_warning.fingerprint == fingerprint }
126
+ warnings << w
127
+ end
128
+ end
129
+
130
+ if @changed
131
+ save_to_file warnings
132
+ end
133
+ end
134
+ end
135
+ end