arachni 1.0.5 → 1.0.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (80) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +50 -0
  3. data/README.md +9 -2
  4. data/components/checks/active/code_injection.rb +5 -5
  5. data/components/checks/active/code_injection_timing.rb +3 -3
  6. data/components/checks/active/no_sql_injection_differential.rb +3 -2
  7. data/components/checks/active/os_cmd_injection.rb +11 -5
  8. data/components/checks/active/os_cmd_injection_timing.rb +11 -4
  9. data/components/checks/active/path_traversal.rb +2 -2
  10. data/components/checks/active/sql_injection.rb +1 -1
  11. data/components/checks/active/sql_injection/patterns/mssql +1 -0
  12. data/components/checks/active/sql_injection_differential.rb +3 -2
  13. data/components/checks/active/unvalidated_redirect.rb +3 -3
  14. data/components/checks/passive/common_directories/directories.txt +2 -0
  15. data/components/checks/passive/common_files/filenames.txt +1 -0
  16. data/lib/arachni/browser.rb +17 -1
  17. data/lib/arachni/check/auditor.rb +5 -2
  18. data/lib/arachni/check/base.rb +30 -5
  19. data/lib/arachni/element/capabilities/analyzable/differential.rb +2 -5
  20. data/lib/arachni/element/capabilities/auditable.rb +3 -1
  21. data/lib/arachni/element/capabilities/with_dom.rb +1 -0
  22. data/lib/arachni/element/capabilities/with_node.rb +1 -1
  23. data/lib/arachni/element/cookie.rb +2 -2
  24. data/lib/arachni/element/form.rb +1 -1
  25. data/lib/arachni/element/header.rb +2 -2
  26. data/lib/arachni/element/link_template.rb +1 -1
  27. data/lib/arachni/framework.rb +21 -1144
  28. data/lib/arachni/framework/parts/audit.rb +282 -0
  29. data/lib/arachni/framework/parts/browser.rb +132 -0
  30. data/lib/arachni/framework/parts/check.rb +86 -0
  31. data/lib/arachni/framework/parts/data.rb +158 -0
  32. data/lib/arachni/framework/parts/platform.rb +34 -0
  33. data/lib/arachni/framework/parts/plugin.rb +61 -0
  34. data/lib/arachni/framework/parts/report.rb +128 -0
  35. data/lib/arachni/framework/parts/scope.rb +40 -0
  36. data/lib/arachni/framework/parts/state.rb +457 -0
  37. data/lib/arachni/http/client.rb +33 -30
  38. data/lib/arachni/http/request.rb +6 -2
  39. data/lib/arachni/issue.rb +55 -1
  40. data/lib/arachni/platform/manager.rb +25 -21
  41. data/lib/arachni/state/framework.rb +7 -1
  42. data/lib/arachni/utilities.rb +10 -0
  43. data/lib/version +1 -1
  44. data/spec/arachni/browser_spec.rb +13 -0
  45. data/spec/arachni/check/auditor_spec.rb +1 -0
  46. data/spec/arachni/check/base_spec.rb +80 -0
  47. data/spec/arachni/element/cookie_spec.rb +2 -2
  48. data/spec/arachni/framework/parts/audit_spec.rb +391 -0
  49. data/spec/arachni/framework/parts/browser_spec.rb +26 -0
  50. data/spec/arachni/framework/parts/check_spec.rb +24 -0
  51. data/spec/arachni/framework/parts/data_spec.rb +187 -0
  52. data/spec/arachni/framework/parts/platform_spec.rb +62 -0
  53. data/spec/arachni/framework/parts/plugin_spec.rb +41 -0
  54. data/spec/arachni/framework/parts/report_spec.rb +66 -0
  55. data/spec/arachni/framework/parts/scope_spec.rb +86 -0
  56. data/spec/arachni/framework/parts/state_spec.rb +528 -0
  57. data/spec/arachni/framework_spec.rb +17 -1344
  58. data/spec/arachni/http/client_spec.rb +12 -7
  59. data/spec/arachni/issue_spec.rb +35 -0
  60. data/spec/arachni/platform/manager_spec.rb +2 -3
  61. data/spec/arachni/state/framework_spec.rb +15 -0
  62. data/spec/components/checks/active/code_injection_timing_spec.rb +5 -5
  63. data/spec/components/checks/active/no_sql_injection_differential_spec.rb +4 -0
  64. data/spec/components/checks/active/os_cmd_injection_spec.rb +20 -7
  65. data/spec/components/checks/active/os_cmd_injection_timing_spec.rb +5 -5
  66. data/spec/components/checks/active/sql_injection_differential_spec.rb +4 -0
  67. data/spec/components/checks/active/sql_injection_spec.rb +2 -3
  68. data/spec/support/servers/arachni/browser.rb +31 -0
  69. data/spec/support/servers/checks/active/code_injection.rb +1 -1
  70. data/spec/support/servers/checks/active/no_sql_injection_differential.rb +36 -34
  71. data/spec/support/servers/checks/active/os_cmd_injection.rb +6 -12
  72. data/spec/support/servers/checks/active/os_cmd_injection_timing.rb +9 -4
  73. data/spec/support/servers/checks/active/sql_injection.rb +1 -1
  74. data/spec/support/servers/checks/active/sql_injection_differential.rb +37 -34
  75. data/spec/support/shared/element/capabilities/with_node.rb +25 -0
  76. data/spec/support/shared/framework.rb +26 -0
  77. data/ui/cli/output.rb +2 -0
  78. data/ui/cli/rpc/server/dispatcher/option_parser.rb +1 -1
  79. metadata +32 -4
  80. data/components/checks/active/sql_injection/patterns/coldfusion +0 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 113357f2e377065a79df18200488cc13fe744b6d
4
- data.tar.gz: 41739b4e27d567d15f67f9ed86c571c24143c3a0
3
+ metadata.gz: 9c9fcad54f45425bae6cfe2e13128890fe6bd259
4
+ data.tar.gz: 5909dde7398a67e4da8f94fdbb11f40e3fc6d9b7
5
5
  SHA512:
6
- metadata.gz: 0418e763e4b5577d1d6856cbbf3cdc242ba04525e10de155b4b86484e6208acdf78cea104e0ce9e75a44aab73fb8e7d40c10be0459d58811b8f7a83b6b4971e1
7
- data.tar.gz: 2ab357a8d52233a026374d1f0bd09ba03d8ebffa9d939d8a97f51bf76c638e95362c1f080b6ed78c54e630d1a13a0c4ddd90dbe61555259dddef762d3a3385e3
6
+ metadata.gz: 9adfdde00f808552c7f8387f5bf7bb766672fee202b757dc150eb92eb5f33326ab3fb680ada9b1cf024f26c1a9c503006d47238d5359f9eb9c2f42b27538f0bf
7
+ data.tar.gz: fe7f56f73a56ddc426095e9abd9b54315c0be4ba493fb2a1666521a38cb8a88a4e3992a810ff0b1d936a4d9e4d6a5f23f5c319333241686f8adca5789c891b89
@@ -1,5 +1,55 @@
1
1
  # ChangeLog
2
2
 
3
+ ## 1.0.6 _(December 07, 2014)_
4
+
5
+ - `arachni_rpcd` -- Fixed bug causing the `--nickname` option to not be understood.
6
+ - `UI::Output` -- Flush output stream after each message.
7
+ - `Platform::Manager`
8
+ - Removed 'coldfusion`.
9
+ - Added `sql` and `nosql` parents for DBs.
10
+ - `Check::Auditor#skip?` -- Ignore mutations when checking for redundancies.
11
+ - `Browser` -- Fixed issue causing `select` inputs in forms to not be set.
12
+ - `Element::Cookie.encode` -- Added '&' to the list of reserved characters.
13
+ - `Issue`
14
+ - `#recheck` -- Rechecks the existence of the issue.
15
+ - `Element::Capabilities`
16
+ - `WithNode`
17
+ - `#html=` -- Recode string before storing.
18
+ - `WithDOM`
19
+ - `#dom` -- Return `nil` on `Inputtable::Error`.
20
+ - `Auditable` -- Updated response analysis messages to include vector type,
21
+ name and action URL.
22
+ - `Framework` -- Split into `Parts`:
23
+ - `Audit`
24
+ - If `Options.platforms` are given, checks which don't support them are
25
+ completely skipped.
26
+ - `Browser`
27
+ - `Check`
28
+ - `Data`
29
+ - `#pop_page_from_url_queue` -- Fixed issue causing multiple-choice
30
+ redirections to cause an error.
31
+ - `Platform`
32
+ - `Plugin`
33
+ - `Report`
34
+ - `Scope`
35
+ - `State`
36
+ - `State::Framework`
37
+ - Added `#done?`
38
+ - `#abort` -- Fixed exception message.
39
+ - Checks
40
+ - Active
41
+ - `sql_injection` -- Slight payload update to catch double-quote cases.
42
+ - `code_injection` -- Slight PHP payload update, to ensure it works in more cases.
43
+ - `code_injection_timing` -- Updated payloads to mirror `code_injection`.
44
+ - `os_command_injection` -- Updated payloads to handle chained commands.
45
+ - `os_command_injection_timing` -- Updated payloads to handle chained commands.
46
+ - `path_traversal` -- Fixed MS Windows output pattern.
47
+ - `sql_injection_differential` -- Set platform to generic `sql`.
48
+ - `no_sql_injection_differential` -- Set platform to generic `nosql`.
49
+ - `unvalidated_redirect` -- Disable `follow_location`.
50
+ - Passive
51
+ - `common_files` -- Added `.svn/all-wcprops`.
52
+
3
53
  ## 1.0.5 _(November 14, 2014)_
4
54
 
5
55
  - Executables
data/README.md CHANGED
@@ -1,9 +1,17 @@
1
+ **NOTICE**:
2
+
3
+ * Arachni's license has changed, please see the _LICENSE_ file before working
4
+ with the project.
5
+ * v1.0 is not backwards compatible with v0.4.
6
+
7
+ <hr/>
8
+
1
9
  # Arachni - Web Application Security Scanner Framework
2
10
 
3
11
  <table>
4
12
  <tr>
5
13
  <th>Version</th>
6
- <td>1.0.5</td>
14
+ <td>1.0.6</td>
7
15
  </tr>
8
16
  <tr>
9
17
  <th>Homepage</th>
@@ -348,7 +356,6 @@ Active checks engage the web application via its inputs.
348
356
 
349
357
  - SQL injection (`sql_injection`) -- Error based detection.
350
358
  - Oracle
351
- - ColdFusion
352
359
  - InterBase
353
360
  - PostgreSQL
354
361
  - MySQL
@@ -12,7 +12,7 @@
12
12
  #
13
13
  # @author Tasos "Zapotek" Laskos <tasos.laskos@arachni-scanner.com>
14
14
  #
15
- # @version 0.2
15
+ # @version 0.2.1
16
16
  #
17
17
  # @see http://cwe.mitre.org/data/definitions/94.html
18
18
  # @see http://php.net/manual/en/function.eval.php
@@ -23,11 +23,11 @@
23
23
  class Arachni::Checks::CodeInjection < Arachni::Check::Base
24
24
 
25
25
  def self.rand1
26
- @rand1 ||= '287630581954'
26
+ @rand1 ||= '28763'
27
27
  end
28
28
 
29
29
  def self.rand2
30
- @rand2 ||= '4196403186331128'
30
+ @rand2 ||= '4196403'
31
31
  end
32
32
 
33
33
  def self.options
@@ -41,7 +41,7 @@ class Arachni::Checks::CodeInjection < Arachni::Check::Base
41
41
  def self.code_strings
42
42
  # code strings to be injected to the webapp
43
43
  @code_strings ||= {
44
- php: "echo #{rand1}+#{rand2};",
44
+ php: "print #{rand1}+#{rand2};",
45
45
  perl: "print #{rand1}+#{rand2};",
46
46
  python: "print #{rand1}+#{rand2}",
47
47
  asp: "Response.Write\x28#{rand1}+#{rand2}\x29"
@@ -72,7 +72,7 @@ Injects code snippets and assess whether or not execution was successful.
72
72
  elements: [ Element::Form, Element::Link, Element::Cookie,
73
73
  Element::Header, Element::LinkTemplate ],
74
74
  author: 'Tasos "Zapotek" Laskos <tasos.laskos@arachni-scanner.com>',
75
- version: '0.2',
75
+ version: '0.2.1',
76
76
  platforms: payloads.keys,
77
77
 
78
78
  issue: {
@@ -14,7 +14,7 @@
14
14
  #
15
15
  # @author Tasos "Zapotek" Laskos <tasos.laskos@arachni-scanner.com>
16
16
  #
17
- # @version 0.3
17
+ # @version 0.3.1
18
18
  #
19
19
  # @see http://cwe.mitre.org/data/definitions/94.html
20
20
  # @see http://php.net/manual/en/function.eval.php
@@ -35,7 +35,7 @@ class Arachni::Checks::CodeInjectionTiming < Arachni::Check::Base
35
35
  jsp: 'Thread.sleep(__TIME__);',
36
36
  asp: 'Thread.Sleep(__TIME__);',
37
37
  }.inject({}) do |h, (platform, payload)|
38
- h[platform] = [ ' ', ' && ', ';' ].map { |sep| "#{sep} #{payload}" }
38
+ h[platform] = [ ' %s', ';%s', "\";%s#", "';%s#" ].map { |s| s % payload }
39
39
  h
40
40
  end
41
41
  end
@@ -54,7 +54,7 @@ a time delay.
54
54
  elements: [ Element::Form, Element::Link, Element::Cookie,
55
55
  Element::Header, Element::LinkTemplate ],
56
56
  author: 'Tasos "Zapotek" Laskos <tasos.laskos@arachni-scanner.com>',
57
- version: '0.3',
57
+ version: '0.3.1',
58
58
  platforms: payloads.keys,
59
59
 
60
60
  issue: {
@@ -7,7 +7,7 @@
7
7
  =end
8
8
 
9
9
  # @author Tasos "Zapotek" Laskos <tasos.laskos@arachni-scanner.com>
10
- # @version 0.1
10
+ # @version 0.1.1
11
11
  class Arachni::Checks::NoSqlInjectionDifferential < Arachni::Check::Base
12
12
 
13
13
  def self.options
@@ -40,7 +40,8 @@ that of a vulnerable application.
40
40
  },
41
41
  elements: [ Element::Link, Element::Form, Element::Cookie ],
42
42
  author: 'Tasos "Zapotek" Laskos <tasos.laskos@arachni-scanner.com>',
43
- version: '0.1',
43
+ version: '0.1.1',
44
+ platforms: [ :nosql ],
44
45
 
45
46
  issue: {
46
47
  name: %q{Blind NoSQL Injection (differential analysis)},
@@ -10,7 +10,7 @@
10
10
  #
11
11
  # @author Tasos "Zapotek" Laskos <tasos.laskos@arachni-scanner.com>
12
12
  #
13
- # @version 0.2.1
13
+ # @version 0.2.2
14
14
  #
15
15
  # @see http://cwe.mitre.org/data/definitions/78.html
16
16
  # @see http://www.owasp.org/index.php/OS_Command_Injection
@@ -23,8 +23,8 @@ class Arachni::Checks::OsCmdInjection < Arachni::Check::Base
23
23
  /(root|mail):.+:\d+:\d+:.+:[0-9a-zA-Z\/]+/im
24
24
  ],
25
25
  windows: [
26
- /\[boot loader\](.*)\[operating systems\]/im,
27
- /\[fonts\](.*)\[extensions\]/im
26
+ /\[boot loader\].*\[operating systems\]/im,
27
+ /\[fonts\].*\[extensions\]/im
28
28
  ]
29
29
  },
30
30
  format: [ Format::STRAIGHT, Format::APPEND ]
@@ -49,7 +49,13 @@ class Arachni::Checks::OsCmdInjection < Arachni::Check::Base
49
49
  }.inject({}) do |h, (platform, payloads)|
50
50
  h[platform] ||= []
51
51
  payloads.each do |payload|
52
- h[platform] |= [ '', '&&', '|', ';' ].map { |sep| "#{sep} #{payload}" }
52
+ h[platform] << "#{payload}"
53
+
54
+ ['', '\'', '"'].each do |q|
55
+ h[platform] |= [ '&&', '|', ';' ].
56
+ map { |sep| "#{q} #{sep} #{payload} #{sep} #{q}" }
57
+ end
58
+
53
59
  h[platform] << "` #{payload}`"
54
60
  end
55
61
  h
@@ -69,7 +75,7 @@ Tries to find Operating System command injections.
69
75
  elements: [ Element::Form, Element::Link, Element::Cookie,
70
76
  Element::Header, Element::LinkTemplate ],
71
77
  author: 'Tasos "Zapotek" Laskos <tasos.laskos@arachni-scanner.com> ',
72
- version: '0.2.1',
78
+ version: '0.2.2',
73
79
  platforms: payloads.keys,
74
80
 
75
81
  issue: {
@@ -10,7 +10,7 @@
10
10
  #
11
11
  # @author Tasos "Zapotek" Laskos <tasos.laskos@arachni-scanner.com>
12
12
  #
13
- # @version 0.3
13
+ # @version 0.3.1
14
14
  #
15
15
  # @see http://cwe.mitre.org/data/definitions/78.html
16
16
  # @see http://www.owasp.org/index.php/OS_Command_Injection
@@ -23,8 +23,15 @@ class Arachni::Checks::OsCmdInjectionTiming < Arachni::Check::Base
23
23
  unix: 'sleep __TIME__',
24
24
  windows: 'ping -n __TIME__ localhost'
25
25
  }.inject({}) do |h, (platform, payload)|
26
- h[platform] = [ '', '&', '&&', '|', ';' ].map { |sep| "#{sep} #{payload}" }
27
- h[platform] << "`#{payload}`"
26
+ h[platform] ||= []
27
+ h[platform] << "#{payload}"
28
+
29
+ ['', '\'', '"'].each do |q|
30
+ h[platform] |= [ '&', '&&', '|', ';' ].
31
+ map { |sep| "#{q} #{sep} #{payload} #{sep} #{q}" }
32
+ end
33
+
34
+ h[platform] << "` #{payload}`"
28
35
  h
29
36
  end
30
37
  end
@@ -46,7 +53,7 @@ Tries to find operating system command injections using timing attacks.
46
53
  elements: [ Element::Form, Element::Link, Element::Cookie,
47
54
  Element::Header, Element::LinkTemplate ],
48
55
  author: 'Tasos "Zapotek" Laskos <tasos.laskos@arachni-scanner.com> ',
49
- version: '0.3',
56
+ version: '0.3.1',
50
57
  platforms: payloads.keys,
51
58
 
52
59
  issue: {
@@ -28,8 +28,8 @@ class Arachni::Checks::PathTraversal < Arachni::Check::Base
28
28
  /(root|mail):.+:\d+:\d+:.+:[0-9a-zA-Z\/]+/im
29
29
  ],
30
30
  windows: [
31
- /\[boot loader\](.*)\[operating systems\]/im,
32
- /\[fonts\](.*)\[extensions\]/im
31
+ /\[boot loader\].*\[operating systems\]/im,
32
+ /\[fonts\].*\[extensions\]/im
33
33
  ],
34
34
  tomcat: [
35
35
  /<web\-app/im
@@ -40,7 +40,7 @@ class Arachni::Checks::SqlInjection < Arachni::Check::Base
40
40
  # Prepares the payloads that will hopefully cause the webapp to output SQL
41
41
  # error messages if included as part of an SQL query.
42
42
  def self.payloads
43
- @payloads ||= [ '\'`--', ')' ]
43
+ @payloads ||= [ '"\'`--', ')' ]
44
44
  end
45
45
 
46
46
  def self.options
@@ -1,5 +1,6 @@
1
1
  System\.Data\.OleDb\.OleDbException
2
2
  \[Microsoft\]\[ODBC SQL Server Driver\]
3
+ \[Macromedia\]\[SQLServer JDBC Driver\]
3
4
  \[SqlException
4
5
  System\.Data\.SqlClient\.SqlException
5
6
  Unclosed quotation mark after the character string
@@ -14,7 +14,7 @@
14
14
  #
15
15
  # @author Tasos "Zapotek" Laskos <tasos.laskos@arachni-scanner.com>
16
16
  #
17
- # @version 0.4.2
17
+ # @version 0.4.3
18
18
  #
19
19
  # @see http://cwe.mitre.org/data/definitions/89.html
20
20
  # @see http://capec.mitre.org/data/definitions/7.html
@@ -59,7 +59,8 @@ that of a vulnerable application.
59
59
  },
60
60
  elements: [ Element::Link, Element::Form, Element::Cookie ],
61
61
  author: 'Tasos "Zapotek" Laskos <tasos.laskos@arachni-scanner.com>',
62
- version: '0.4.2',
62
+ version: '0.4.3',
63
+ platforms: [ :sql ],
63
64
 
64
65
  issue: {
65
66
  name: %q{Blind SQL Injection (differential analysis)},
@@ -12,7 +12,7 @@
12
12
  # header field to determine whether the attack was successful.
13
13
  #
14
14
  # @author Tasos "Zapotek" Laskos <tasos.laskos@arachni-scanner.com>
15
- # @version 0.2
15
+ # @version 0.2.1
16
16
  # @see http://www.owasp.org/index.php/Top_10_2010-A10-Unvalidated_Redirects_and_Forwards
17
17
  class Arachni::Checks::UnvalidatedRedirect < Arachni::Check::Base
18
18
 
@@ -32,7 +32,7 @@ class Arachni::Checks::UnvalidatedRedirect < Arachni::Check::Base
32
32
  end
33
33
 
34
34
  def run
35
- audit( self.class.payloads ) do |response, element|
35
+ audit( self.class.payloads, submit: { follow_location: false } ) do |response, element|
36
36
  # If this was a sample/default value submission ignore it, we only
37
37
  # care about our payloads.
38
38
  next if !payload? element.seed
@@ -67,7 +67,7 @@ URL to determine whether the attack was successful.
67
67
  },
68
68
  elements: [Element::Form, Element::Link, Element::Cookie, Element::Header],
69
69
  author: 'Tasos "Zapotek" Laskos <tasos.laskos@arachni-scanner.com>',
70
- version: '0.2',
70
+ version: '0.2.1',
71
71
 
72
72
  issue: {
73
73
  name: %q{Unvalidated redirect},
@@ -6,6 +6,7 @@ CVS/Repository
6
6
  CVS/Root
7
7
  CVS/Entries
8
8
  .svn/wc.db
9
+ .svn/all-wcprops
9
10
  .git/HEAD
10
11
  _mmServerScripts/MMHTTPDB.php
11
12
  _mmServerScripts/MMHTTPDB.asp
@@ -896,7 +896,7 @@ class Browser
896
896
 
897
897
  begin
898
898
  input.set( value.to_s )
899
- # Disabled inputs and such...
899
+ # Disabled inputs and such...
900
900
  rescue Watir::Exception::ObjectDisabledException,
901
901
  Watir::Exception::ObjectReadOnlyException,
902
902
  Selenium::WebDriver::Error::InvalidElementStateError => e
@@ -904,6 +904,22 @@ class Browser
904
904
  " because: #{e} [#{e.class}"
905
905
  end
906
906
  end
907
+
908
+ form.selects.each do |input|
909
+ name_or_id = name_or_id_for( input )
910
+ value = inputs ? inputs[name_or_id] : value_for( input )
911
+
912
+ begin
913
+ input.select_value( value.to_s )
914
+ # Disabled inputs and such...
915
+ rescue Watir::Exception::ObjectDisabledException,
916
+ Watir::Exception::ObjectReadOnlyException,
917
+ Watir::Exception::NoValueFoundException,
918
+ Selenium::WebDriver::Error::InvalidElementStateError => e
919
+ print_debug_level_2 "Could not fill in form select '#{name_or_id}'" <<
920
+ " because: #{e} [#{e.class}"
921
+ end
922
+ end
907
923
  end
908
924
 
909
925
  def skip_state?( state )
@@ -380,8 +380,11 @@ module Auditor
380
380
  #
381
381
  # @see Page#audit?
382
382
  def skip?( element )
383
- return true if audited?( element.coverage_id ) ||
384
- !page.audit_element?( element )
383
+ # This method also gets called from Auditable#audit to check mutations,
384
+ # don't touch these, we're filtering at a higher level here, otherwise
385
+ # we might mess up the audit.
386
+ return true if !element.mutation? && audited?( element.coverage_id )
387
+ return true if !page.audit_element?( element )
385
388
 
386
389
  # Don't audit elements which have been already logged as vulnerable
387
390
  # either by us or preferred checks.
@@ -138,27 +138,47 @@ class Base < Component::Base
138
138
  # @return [Bool]
139
139
  # `true` if the check can benefit from knowing the platform beforehand,
140
140
  # `false` otherwise.
141
+ #
141
142
  # @see .platforms
142
143
  def has_platforms?
143
144
  platforms.any?
144
145
  end
145
146
 
146
- # @return [Array<Symbol>] Targeted platforms.
147
+ # @return [Array<Symbol>]
148
+ # Targeted platforms.
149
+ #
147
150
  # @see .info
148
151
  def platforms
149
- [info[:platforms]].flatten.compact
152
+ @platforms ||= [info[:platforms]].flatten.compact
153
+ end
154
+
155
+ # @param [Array<Symbol, String>] platforms
156
+ # List of platforms to check for support.
157
+ #
158
+ # @return [Boolean]
159
+ # `true` if any of the given platforms are supported, `false` otherwise.
160
+ def supports_platforms?( platforms )
161
+ return true if platforms.empty? || !has_platforms?
162
+
163
+ # Determine if we've got anything for the given platforms, the same
164
+ # way payloads are picked.
165
+ foo_data = self.platforms.inject({}) { |h, platform| h.merge!( platform => true ) }
166
+ Platform::Manager.new( platforms ).pick( foo_data ).any?
150
167
  end
151
168
 
152
- # @return [Array<Symbol>] Targeted element types.
169
+ # @return [Array<Symbol>]
170
+ # Targeted element types.
171
+ #
153
172
  # @see .info
154
173
  def elements
155
- [info[:elements]].flatten.compact
174
+ @elements ||= [info[:elements]].flatten.compact
156
175
  end
157
176
 
158
177
  # Schedules self to be run *after* the specified checks and prevents
159
178
  # auditing elements that have been previously logged by any of these checks.
160
179
  #
161
- # @return [Array] Check names.
180
+ # @return [Array]
181
+ # Check names.
162
182
  def prefer( *args )
163
183
  @preferred = args.flatten.compact
164
184
  end
@@ -170,6 +190,11 @@ class Base < Component::Base
170
190
  def preferred
171
191
  @preferred ||= []
172
192
  end
193
+
194
+ # @private
195
+ def clear_info_cache
196
+ @elements = @platforms = nil
197
+ end
173
198
  end
174
199
 
175
200
  end