arachni 1.0.1 → 1.0.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a4f1fba6f25f0dd437f9d31c82b3f036d4b87ec9
4
- data.tar.gz: eaa9814da188578b10283e23101525828d42b17a
3
+ metadata.gz: f1ab8801aa396dbd2a6aa10c911a91777b046542
4
+ data.tar.gz: 2251a40388dec9fc771bc8aa51ddc7680bb4f825
5
5
  SHA512:
6
- metadata.gz: a98cde207400471e0ba80cffc9fce6ce46348d43e76c509cbd06f5c7e6b4867f62f9e5382bedaa7b500d731a82428cde04d23db0ea72a4cfceb9087c8fe8062a
7
- data.tar.gz: a66344c76f782b7042f003c0e7b525b5ea173d2f72257d77f9a4673be35280624d4c73a5f874c157b4b66fd5b3eb46a0196480d9b91379639da6cf26e288c045
6
+ metadata.gz: ccf69071cb3b2ddb1d880041979ac24d8d2f0d61662eadae5ad77544cbd226d47aa746e8505022d03b466290bece49410efc61957d0fc3fbd9359e5361d0b198
7
+ data.tar.gz: 8d3f66447ef08172a43b29605b1f611131a0565a06ba70c706ee199d191043ee78c93b1eb8bef80d95e7215950e54a1ad3d650e3d6d440cc9fb5ab2babbb21f1
@@ -1,5 +1,26 @@
1
1
  # ChangeLog
2
2
 
3
+ ## 1.0.2 _(September 13, 2014)_
4
+
5
+ - `UI::Output` -- Updated null output interface with placeholder debugging methods.
6
+ - `Browser`
7
+ - Updated to catch exception when trying to manipulate read-only inputs.
8
+ - `BrowserCluster`
9
+ - Added debugging messages for job processing.
10
+ - `Worker`
11
+ - `#run_job` -- Clear the `@window_responses` cache after each job in
12
+ addition to after each browser re-spawn.
13
+ - `Form`
14
+ - `#audit` -- `:each_mutation` callback now ignores `#mutation_with_original_values`
15
+ and `#mutation_with_sample_values`.
16
+ - Checks
17
+ - Active
18
+ - `xss_dom_inputs` -- Ignore out-of-scope browser pages.
19
+ - `code_injection_php_input_wrapper` -- Cleaned up `:each_mutation` callback.
20
+ - `file_inclusion` -- Cleaned up `:each_mutation` callback.
21
+ - `path_traversal` -- Cleaned up `:each_mutation` callback.
22
+ - `source_code_disclosure` -- Cleaned up `:each_mutation` callback.
23
+
3
24
  ## 1.0.1 _(September 7, 2014)_
4
25
 
5
26
  - `RPC::Server::Dispatcher`
data/Gemfile CHANGED
@@ -21,6 +21,8 @@ end
21
21
 
22
22
  group :prof do
23
23
  gem 'stackprof'
24
+ gem 'sys-proctable'
25
+ gem 'ruby-mass'
24
26
  end
25
27
 
26
28
  gemspec
data/README.md CHANGED
@@ -11,7 +11,7 @@
11
11
  <table>
12
12
  <tr>
13
13
  <th>Version</th>
14
- <td>1.0.1</td>
14
+ <td>1.0.2</td>
15
15
  </tr>
16
16
  <tr>
17
17
  <th>Homepage</th>
@@ -7,7 +7,7 @@
7
7
  =end
8
8
 
9
9
  # @author Tasos "Zapotek" Laskos <tasos.laskos@arachni-scanner.com>
10
- # @version 0.1.1
10
+ # @version 0.1.2
11
11
  # @see OWASP https://www.owasp.org/index.php/Top_10_2007-Malicious_File_Execution
12
12
  class Arachni::Checks::CodeInjectionPhpInputWrapper < Arachni::Check::Base
13
13
 
@@ -20,10 +20,7 @@ class Arachni::Checks::CodeInjectionPhpInputWrapper < Arachni::Check::Base
20
20
  # Add one more mutation (on the fly) which will include the extension
21
21
  # of the original value (if that value was a filename) after a null byte.
22
22
  each_mutation: proc do |mutation|
23
- next if !mutation.affected_input_value ||
24
- (mutation.is_a?( Arachni::Form ) &&
25
- (mutation.mutation_with_original_values? ||
26
- mutation.mutation_with_sample_values?))
23
+ next if !mutation.affected_input_value
27
24
 
28
25
  # Don't bother if the current element type can't carry nulls.
29
26
  next if !mutation.valid_input_value_data?( "\0" )
@@ -56,7 +53,7 @@ to try and load it.
56
53
  },
57
54
  elements: [ Element::Form, Element::Link, Element::Cookie, Element::Header ],
58
55
  author: 'Tasos "Zapotek" Laskos <tasos.laskos@arachni-scanner.com> ',
59
- version: '0.1.1',
56
+ version: '0.1.2',
60
57
  platforms: [:php],
61
58
 
62
59
  issue: {
@@ -9,7 +9,7 @@
9
9
  # File inclusion check.
10
10
  #
11
11
  # @author Tasos "Zapotek" Laskos <tasos.laskos@arachni-scanner.com>
12
- # @version 0.1.2
12
+ # @version 0.1.3
13
13
  #
14
14
  # @see http://cwe.mitre.org/data/definitions/98.html
15
15
  # @see https://www.owasp.org/index.php/PHP_File_Inclusion
@@ -50,10 +50,7 @@ class Arachni::Checks::FileInclusion < Arachni::Check::Base
50
50
  # Add one more mutation (on the fly) which will include the extension
51
51
  # of the original value (if that value was a filename) after a null byte.
52
52
  each_mutation: proc do |mutation|
53
- next if !mutation.affected_input_value ||
54
- (mutation.is_a?( Arachni::Form ) &&
55
- (mutation.mutation_with_original_values? ||
56
- mutation.mutation_with_sample_values?))
53
+ next if !mutation.affected_input_value
57
54
 
58
55
  # Don't bother if the current element type can't carry nulls.
59
56
  next if !mutation.valid_input_value_data?( "\0" )
@@ -105,7 +102,7 @@ content or errors in the HTTP response body.
105
102
  elements: [ Element::Form, Element::Link, Element::Cookie,
106
103
  Element::Header, Element::LinkTemplate ],
107
104
  author: 'Tasos "Zapotek" Laskos <tasos.laskos@arachni-scanner.com> ',
108
- version: '0.1.2',
105
+ version: '0.1.3',
109
106
  platforms: options[:regexp].keys,
110
107
 
111
108
  issue: {
@@ -9,7 +9,7 @@
9
9
  # Path Traversal check.
10
10
  #
11
11
  # @author Tasos "Zapotek" Laskos <tasos.laskos@arachni-scanner.com>
12
- # @version 0.4.2
12
+ # @version 0.4.3
13
13
  #
14
14
  # @see http://cwe.mitre.org/data/definitions/22.html
15
15
  # @see http://www.owasp.org/index.php/Path_Traversal
@@ -39,10 +39,7 @@ class Arachni::Checks::PathTraversal < Arachni::Check::Base
39
39
  # Add one more mutation (on the fly) which will include the extension
40
40
  # of the original value (if that value was a filename) after a null byte.
41
41
  each_mutation: proc do |mutation|
42
- next if !mutation.affected_input_value ||
43
- (mutation.is_a?( Arachni::Form ) &&
44
- (mutation.mutation_with_original_values? ||
45
- mutation.mutation_with_sample_values?))
42
+ next if !mutation.affected_input_value
46
43
 
47
44
  # Don't bother if the current element type can't carry nulls.
48
45
  next if !mutation.valid_input_value_data?( "\0" )
@@ -115,7 +112,7 @@ of relevant content in the HTML responses.
115
112
  elements: [ Element::Form, Element::Link, Element::Cookie,
116
113
  Element::Header, Element::LinkTemplate ],
117
114
  author: 'Tasos "Zapotek" Laskos <tasos.laskos@arachni-scanner.com> ',
118
- version: '0.4.2',
115
+ version: '0.4.3',
119
116
  platforms: payloads.keys,
120
117
 
121
118
  issue: {
@@ -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/540.html
18
18
  class Arachni::Checks::SourceCodeDisclosure < Arachni::Check::Base
@@ -39,10 +39,7 @@ class Arachni::Checks::SourceCodeDisclosure < Arachni::Check::Base
39
39
  # Add one more mutation (on the fly) which will include the extension
40
40
  # of the original value (if that value was a filename) after a null byte.
41
41
  each_mutation: proc do |mutation|
42
- next if !mutation.affected_input_value ||
43
- (mutation.is_a?( Arachni::Form ) &&
44
- (mutation.mutation_with_original_values? ||
45
- mutation.mutation_with_sample_values?))
42
+ next if !mutation.affected_input_value
46
43
 
47
44
  # Don't bother if the current element type can't carry nulls.
48
45
  next if !mutation.valid_input_value_data?( "\0" )
@@ -122,7 +119,7 @@ source code.
122
119
  elements: [ Element::Form, Element::Link, Element::Cookie,
123
120
  Element::Header, Element::LinkTemplate ],
124
121
  author: 'Tasos "Zapotek" Laskos <tasos.laskos@arachni-scanner.com>',
125
- version: '0.2',
122
+ version: '0.2.1',
126
123
  platforms: options[:regexp].keys,
127
124
 
128
125
  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::XssDomInputs < Arachni::Check::Base
12
12
 
13
13
  INPUTS = Set.new([:input, :textarea])
@@ -41,7 +41,9 @@ class Arachni::Checks::XssDomInputs < Arachni::Check::Base
41
41
  transition = b.fire_event( locator, event, value: self.tag )
42
42
  next if !transition
43
43
 
44
- p = b.to_page
44
+ # Page may be out of scope, some sort of JS redirection.
45
+ next if !(p = b.to_page)
46
+
45
47
  p.dom.transitions << transition
46
48
 
47
49
  check_and_log p
@@ -77,7 +79,7 @@ Injects an HTML element into page text fields, triggers their associated events
77
79
  and inspects the DOM for proof of vulnerability.
78
80
  },
79
81
  author: 'Tasos "Zapotek" Laskos <tasos.laskos@arachni-scanner.com>',
80
- version: '0.1',
82
+ version: '0.1.1',
81
83
  elements: [Element::GenericDOM],
82
84
 
83
85
  issue: {
@@ -883,6 +883,7 @@ class Browser
883
883
  input.set( value.to_s )
884
884
  # Disabled inputs and such...
885
885
  rescue Watir::Exception::ObjectDisabledException,
886
+ Watir::Exception::ObjectReadOnlyException,
886
887
  Selenium::WebDriver::Error::InvalidElementStateError => e
887
888
  print_debug_level_2 "Could not fill in form input '#{name_or_id}'" <<
888
889
  " because: #{e} [#{e.class}"
@@ -150,6 +150,8 @@ class BrowserCluster
150
150
  @done_signal.clear
151
151
 
152
152
  synchronize do
153
+ print_debug "Queueing: #{job}"
154
+
153
155
  @pending_job_counter += 1
154
156
  @pending_jobs[job.id] += 1
155
157
  @job_callbacks[job.id] = block if block
@@ -200,6 +202,8 @@ class BrowserCluster
200
202
  # {Worker} states.
201
203
  def job_done( job )
202
204
  synchronize do
205
+ print_debug "Job done: #{job}"
206
+
203
207
  if !job.never_ending?
204
208
  @skip_states_per_job.delete job.id
205
209
  @job_callbacks.delete job.id
@@ -241,6 +245,8 @@ class BrowserCluster
241
245
  return if job_done? result.job
242
246
 
243
247
  synchronize do
248
+ print_debug "Got job result: #{result}"
249
+
244
250
  exception_jail( false ) do
245
251
  @job_callbacks[result.job.id].call result
246
252
  end
@@ -20,6 +20,10 @@ class BrowserProvider < Job
20
20
  browser.master.callback_for( self ).call browser
21
21
  end
22
22
 
23
+ def to_s
24
+ "#<#{self.class}:#{object_id} callback=#{browser.master.callback_for( self ) if browser && browser.master}>"
25
+ end
26
+
23
27
  end
24
28
 
25
29
  end
@@ -53,6 +53,10 @@ class ResourceExploration < Job
53
53
  super.tap { |j| j.resource = nil }
54
54
  end
55
55
 
56
+ def to_s
57
+ "#<#{self.class}:#{object_id} @resource=#{@resource}>"
58
+ end
59
+
56
60
  end
57
61
 
58
62
  end
@@ -35,6 +35,11 @@ class EventTrigger < ResourceExploration
35
35
  browser.trigger_event( resource, element, event )
36
36
  end
37
37
 
38
+ def to_s
39
+ "#<#{self.class}:#{object_id} @resource=#{@resource} " +
40
+ "@event=#{@event.inspect} @element=#{@element.inspect}>"
41
+ end
42
+
38
43
  end
39
44
 
40
45
  end
@@ -13,8 +13,14 @@ class ResourceExploration
13
13
 
14
14
  # @author Tasos "Zapotek" Laskos <tasos.laskos@arachni-scanner.com>
15
15
  class Result < Job::Result
16
+
16
17
  # @return [Page]
17
18
  attr_accessor :page
19
+
20
+ def to_s
21
+ "#<#{self.class}:#{object_id} @job=#{@job} @page=#{@page}>"
22
+ end
23
+
18
24
  end
19
25
 
20
26
  end
@@ -41,6 +41,11 @@ class TaintTrace < ResourceExploration
41
41
  super
42
42
  end
43
43
 
44
+ def to_s
45
+ "#<#{self.class}:#{object_id} @resource=#{@resource} " +
46
+ "@taint=#{@taint.inspect} @injector=#{@injector.inspect}>"
47
+ end
48
+
44
49
  end
45
50
 
46
51
  end
@@ -25,6 +25,12 @@ class EventTrigger < ResourceExploration::EventTrigger
25
25
  super
26
26
  end
27
27
 
28
+ def to_s
29
+ "#<#{self.class}:#{object_id} @resource=#{@resource} " +
30
+ "@event=#{@event.inspect} @element=#{@element.inspect} " +
31
+ "@forwarder=#{@forwarder}>"
32
+ end
33
+
28
34
  end
29
35
 
30
36
  end
@@ -78,6 +78,7 @@ class Worker < Arachni::Browser
78
78
  # @see Arachni::Browser#trigger_events
79
79
  def run_job( job )
80
80
  @job = job
81
+ print_debug "Started: #{@job}"
81
82
 
82
83
  # PhantomJS may have crashed (it happens sometimes) so make sure that
83
84
  # we've got a live one before running the job.
@@ -94,7 +95,7 @@ class Worker < Arachni::Browser
94
95
  end
95
96
  end
96
97
  rescue TimeoutError => e
97
- print_debug "Job timed-out after #{@job_timeout} seconds: #{job}"
98
+ print_debug "Job timed-out after #{@job_timeout} seconds: #{@job}"
98
99
 
99
100
  # Could have left us with a broken browser.
100
101
  browser_respawn
@@ -110,6 +111,8 @@ class Worker < Arachni::Browser
110
111
  decrease_time_to_live
111
112
  browser_respawn_if_necessary
112
113
 
114
+ print_debug "Finished: #{@job}"
115
+
113
116
  true
114
117
  rescue Selenium::WebDriver::Error::WebDriverError
115
118
  browser_respawn
@@ -122,6 +125,7 @@ class Worker < Arachni::Browser
122
125
  @captured_pages.clear
123
126
  @page_snapshots.clear
124
127
  @page_snapshots_with_sinks.clear
128
+ @window_responses.clear
125
129
 
126
130
  # The jobs may have configured callbacks to capture pages etc.,
127
131
  # remove them.
@@ -18,7 +18,7 @@ module Auditable
18
18
  module DOM
19
19
  include WithNode
20
20
  include Auditable
21
- extend Forwardable
21
+ extend ::Forwardable
22
22
 
23
23
  INVALID_INPUT_DATA = [ "\0" ]
24
24
 
@@ -12,7 +12,7 @@ module WithAuditor
12
12
 
13
13
  # Delegate output related methods to the {WithAuditor#auditor}.
14
14
  module Output
15
- extend Forwardable
15
+ extend ::Forwardable
16
16
 
17
17
  [ :debug?, :print_error, :print_status, :print_verbose, :print_info,
18
18
  :print_line, :print_ok, :print_bad, :print_debug, :print_debug_backtrace,
@@ -490,6 +490,21 @@ class Form < Base
490
490
 
491
491
  private
492
492
 
493
+ def audit_single( payload, opts = {}, &block )
494
+ opts = opts.dup
495
+
496
+ if (each_m = opts.delete(:each_mutation))
497
+ opts[:each_mutation] = proc do |mutation|
498
+ next if mutation.mutation_with_original_values? ||
499
+ mutation.mutation_with_sample_values?
500
+
501
+ each_m.call( mutation )
502
+ end
503
+ end
504
+
505
+ super( payload, opts, &block )
506
+ end
507
+
493
508
  def skip?( elem )
494
509
  if elem.mutation_with_original_values? || elem.mutation_with_sample_values?
495
510
  id = elem.audit_id
@@ -425,6 +425,10 @@ class Page
425
425
  end
426
426
  alias :to_hash :to_h
427
427
 
428
+ def to_s
429
+ "#<#{self.class}:#{object_id} @url=#{@url.inspect} @dom=#{@dom}>"
430
+ end
431
+
428
432
  def persistent_hash
429
433
  digest.persistent_hash
430
434
  end
@@ -69,9 +69,16 @@ class DOM
69
69
  @url = url.freeze
70
70
  end
71
71
 
72
- def digest=( digest )
73
- return @digest = nil if !digest
74
- @digest = digest.freeze
72
+ def digest=( d )
73
+ return @digest = nil if !d
74
+
75
+ if d.include?( url ) || d.include?( page.url )
76
+ d = d.dup
77
+ d.gsub!( url, '' )
78
+ d.gsub!( page.url, '' )
79
+ end
80
+
81
+ @digest = d.freeze
75
82
  end
76
83
 
77
84
  # @param [Transition] transition
@@ -198,6 +205,10 @@ class DOM
198
205
  to_h
199
206
  end
200
207
 
208
+ def to_s
209
+ "#<#{self.class}:#{object_id} @url=#{@url.inspect}>"
210
+ end
211
+
201
212
  # @return [Hash]
202
213
  # Data representing this instance that are suitable the RPC transmission.
203
214
  def to_rpc_data
@@ -270,8 +281,14 @@ class DOM
270
281
  protected
271
282
 
272
283
  def digest_without_urls( other )
273
- digest.gsub( url, '' ).gsub( other.url, '' ).
274
- gsub( page.url, '' ).gsub( other.page.url, '' )
284
+ if !digest.include?( other.url ) && !digest.include?( other.page.url )
285
+ return digest
286
+ end
287
+
288
+ d = digest.dup
289
+ d.gsub!( other.url, '' )
290
+ d.gsub!( other.page.url, '' )
291
+ d
275
292
  end
276
293
 
277
294
  end
@@ -131,7 +131,7 @@ class Report
131
131
  end
132
132
 
133
133
  # @param [String] location
134
- # Location for the dumped report file.
134
+ # Location for the {#to_afr dumped} report file.
135
135
  #
136
136
  # @return [String]
137
137
  # Absolute location of the report.
@@ -144,15 +144,21 @@ class Report
144
144
  location += "/#{default_filename}"
145
145
  end
146
146
 
147
- IO.binwrite( location, RPC::Serializer.dump( self ) )
147
+ IO.binwrite( location, to_afr )
148
148
 
149
- # Append metadata to the end of the file.
149
+ File.expand_path( location )
150
+ end
151
+
152
+ # @return [String]
153
+ # Report serialized in the Arachni Framework Report format..
154
+ def to_afr
155
+ afr = RPC::Serializer.dump( self )
156
+
157
+ # Append metadata to the end of the dump.
150
158
  metadata = RPC::Serializer.dump( summary )
151
- File.open( location, 'a' ) do |f|
152
- f.write [metadata, metadata.size].pack( 'a*N' )
153
- end
159
+ afr << [metadata, metadata.size].pack( 'a*N' )
154
160
 
155
- File.expand_path( location )
161
+ afr
156
162
  end
157
163
 
158
164
  # @return [Hash]
@@ -19,7 +19,7 @@ class State
19
19
  #
20
20
  # @author Tasos "Zapotek" Laskos <tasos.laskos@arachni-scanner.com>
21
21
  class Audit
22
- extend Forwardable
22
+ extend ::Forwardable
23
23
 
24
24
  def initialize
25
25
  @collection = Support::LookUp::HashSet.new( hasher: :persistent_hash )
@@ -6,6 +6,7 @@
6
6
  web site for more information on licensing and terms of use.
7
7
  =end
8
8
 
9
+ require 'sys/proctable'
9
10
  require 'ruby-mass'
10
11
  require 'stackprof'
11
12
 
@@ -15,6 +16,22 @@ module Support
15
16
  # @author Tasos "Zapotek" Laskos <tasos.laskos@arachni-scanner.com>
16
17
  class Profiler
17
18
 
19
+ def self.write_samples_to_disk( file, options = {} )
20
+ profiler = Support::Profiler.new
21
+
22
+ Thread.new do
23
+ begin
24
+ loop do
25
+ profiler.write_object_space( file, options )
26
+ sleep options[:interval] || 1
27
+ end
28
+ rescue => e
29
+ ap e
30
+ ap e.backtrace
31
+ end
32
+ end
33
+ end
34
+
18
35
  def trace_allocations
19
36
  require 'objspace'
20
37
  ObjectSpace.trace_object_allocations_start
@@ -60,26 +77,19 @@ class Profiler
60
77
  ap find_references( o )
61
78
  end
62
79
 
63
- def print_object_space( options = {} )
64
- klass = options[:class]
65
- namespaces = options[:namespaces] || [Arachni]
66
- with_allocation_info = options[:with_allocation_info]
67
- with_references = options[:with_references]
68
- with_dependencies = options[:with_dependencies]
69
- max_entries = options[:max_entries] || 50
80
+ def object_space( options = {} )
81
+ klass = options[:class]
82
+ namespaces = options[:namespaces] || [Arachni]
83
+ max_entries = options[:max_entries] || 50
70
84
 
71
85
  object_space = Hash.new(0)
72
86
  @object_space ||= Hash.new(0)
73
87
 
74
88
  ObjectSpace.each_object do |o|
75
- next if o.class != klass || !object_within_namespace?( o, namespaces )
76
-
77
- print_object_allocations( o ) if with_allocation_info
78
- print_references( o ) if with_references
79
- print_dependencies( o ) if with_dependencies
80
-
89
+ next if o.class != klass && !object_within_namespace?( o, namespaces )
81
90
  object_space[o.class] += 1
82
91
  end
92
+
83
93
  object_space = Hash[object_space.sort_by { |_, v| v }.reverse[0..max_entries]]
84
94
 
85
95
  with_deltas = object_space.dup
@@ -91,9 +101,30 @@ class Profiler
91
101
  end
92
102
  end
93
103
 
94
- ap with_deltas
95
-
96
104
  @object_space = object_space.dup
105
+ with_deltas
106
+ end
107
+
108
+ def write_object_space( file, options = {} )
109
+ consumption = resource_consumption
110
+
111
+ str = "RAM: #{consumption[:memory_usage].round(3)}MB"
112
+ str << " (#{consumption[:memory_utilization]}%)"
113
+ str << " - CPU: #{consumption[:cpu_utilization]}%\n\n"
114
+
115
+ os = object_space( options )
116
+ maxsize = os.keys.map(&:to_s).map(&:size).sort.reverse.first
117
+
118
+ os.each do |klass, info|
119
+ offset = maxsize - klass.to_s.size
120
+ str << "#{klass}: #{' ' * offset}#{info}\n"
121
+ end
122
+
123
+ IO.write( file, str )
124
+ end
125
+
126
+ def print_object_space( options = {} )
127
+ ap object_space( options )
97
128
  end
98
129
 
99
130
  def count_objects( klass )
@@ -101,8 +132,6 @@ class Profiler
101
132
  end
102
133
 
103
134
  def resource_consumption
104
- require 'sys/proctable'
105
-
106
135
  procinfo = ::Sys::ProcTable.ps( Process.pid )
107
136
  {
108
137
  cpu_utilization: procinfo[:pctcpu],
@@ -92,6 +92,11 @@ module Output
92
92
  def debug?(*)
93
93
  end
94
94
 
95
+ 1.upto( 3 ) do |i|
96
+ define_method( "debug_level_#{i}?" ) {}
97
+ define_method( "debug_level_#{i}" ) {}
98
+ end
99
+
95
100
  def only_positives
96
101
  end
97
102
 
@@ -1 +1 @@
1
- 1.0.1
1
+ 1.0.2
@@ -101,6 +101,36 @@ describe Arachni::Element::Form do
101
101
  end
102
102
  end
103
103
 
104
+ describe '#audit' do
105
+ describe :each_mutation do
106
+ it 'ignores #mutation_with_original_values' do
107
+ had_mutation_with_original_values = false
108
+ each_mutation = proc do |mutation|
109
+ had_mutation_with_original_values ||=
110
+ mutation.mutation_with_original_values?
111
+ end
112
+
113
+ subject.audit( 'stuff', each_mutation: each_mutation ) {}
114
+ subject.http.run
115
+
116
+ had_mutation_with_original_values.should be_false
117
+ end
118
+
119
+ it 'ignores mutation_with_sample_values' do
120
+ had_mutation_with_sample_values = false
121
+ each_mutation = proc do |mutation|
122
+ had_mutation_with_sample_values ||=
123
+ mutation.mutation_with_sample_values?
124
+ end
125
+
126
+ subject.audit( 'stuff', each_mutation: each_mutation ) {}
127
+ subject.http.run
128
+
129
+ had_mutation_with_sample_values.should be_false
130
+ end
131
+ end
132
+ end
133
+
104
134
  describe '#name_or_id' do
105
135
  context 'when a #name is available' do
106
136
  it 'returns it' do
@@ -221,6 +221,14 @@ describe Arachni::Report do
221
221
  end
222
222
  end
223
223
 
224
+ describe '#to_afr' do
225
+ it 'returns the object in AFR format' do
226
+ @report_file = report.save
227
+
228
+ IO.binread( @report_file ).should == report.to_afr
229
+ end
230
+ end
231
+
224
232
  describe '#to_h' do
225
233
  it 'returns the object as a hash' do
226
234
  report.to_h.should == {
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: arachni
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tasos Laskos
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-09-07 00:00:00.000000000 Z
11
+ date: 2014-09-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler