Class: Arachni::State::Framework

Inherits:
Object
  • Object
show all
Defined in:
lib/arachni/state/framework.rb,
lib/arachni/state/framework/rpc.rb

Overview

State information for Framework.

Author:

  • Tasos “Zapotek” Laskos <tasos.laskos@arachni-scanner.com>

Defined Under Namespace

Classes: Error, RPC

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeFramework

Returns a new instance of Framework.



68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/arachni/state/framework.rb', line 68

def initialize
    @rpc = RPC.new
    @audited_page_count = 0

    @browser_skip_states = Support::LookUp::HashSet.new( hasher: :persistent_hash )

    @page_queue_filter = Support::LookUp::HashSet.new( hasher: :persistent_hash )
    @url_queue_filter  = Support::LookUp::HashSet.new( hasher: :persistent_hash )

    @element_pre_check_filter = Support::LookUp::HashSet.new( hasher: :coverage_hash )

    @running = false
    @pre_pause_status = nil

    @pause_signals    = Set.new
    @paused_signal    = Queue.new
    @suspended_signal = Queue.new
    @aborted_signal   = Queue.new

    @status_messages = []
end

Instance Attribute Details

#audited_page_countInteger

Returns:

  • (Integer)


60
61
62
# File 'lib/arachni/state/framework.rb', line 60

def audited_page_count
  @audited_page_count
end

#browser_skip_statesSet (readonly)

Returns:



51
52
53
# File 'lib/arachni/state/framework.rb', line 51

def browser_skip_states
  @browser_skip_states
end

#element_pre_check_filterSupport::LookUp::HashSet (readonly)



48
49
50
# File 'lib/arachni/state/framework.rb', line 48

def element_pre_check_filter
  @element_pre_check_filter
end

#page_queue_filterSupport::LookUp::HashSet (readonly)



42
43
44
# File 'lib/arachni/state/framework.rb', line 42

def page_queue_filter
  @page_queue_filter
end

#pause_signalsArray (readonly)

Returns:



63
64
65
# File 'lib/arachni/state/framework.rb', line 63

def pause_signals
  @pause_signals
end

#rpcRPC

Returns:



39
40
41
# File 'lib/arachni/state/framework.rb', line 39

def rpc
  @rpc
end

#runningBool

Returns:

  • (Bool)


57
58
59
# File 'lib/arachni/state/framework.rb', line 57

def running
  @running
end

#statusSymbol

Returns:

  • (Symbol)


54
55
56
# File 'lib/arachni/state/framework.rb', line 54

def status
  @status
end

#status_messagesArray<String> (readonly)

Returns:



66
67
68
# File 'lib/arachni/state/framework.rb', line 66

def status_messages
  @status_messages
end

#url_queue_filterSupport::LookUp::HashSet (readonly)



45
46
47
# File 'lib/arachni/state/framework.rb', line 45

def url_queue_filter
  @url_queue_filter
end

Class Method Details

.load(directory) ⇒ Object



420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
# File 'lib/arachni/state/framework.rb', line 420

def self.load( directory )
    framework = new

    framework.rpc = RPC.load( "#{directory}/rpc/" )

    %w(element_pre_check_filter page_queue_filter url_queue_filter
        browser_skip_states).each do |attribute|
        path = "#{directory}/#{attribute}"
        next if !File.exist?( path )

        framework.send(attribute).merge Marshal.load( IO.binread( path ) )
    end

    framework.audited_page_count = Marshal.load( IO.binread( "#{directory}/audited_page_count" ) )
    framework
end

Instance Method Details

#abort(block = true) ⇒ Bool

Returns `true` if the abort request was successful, `false` if the system is already #suspended? or is #suspending?.

Parameters:

  • block (Bool) (defaults to: true)

    `true` if the method should block until an abortion has completed, `false` otherwise.

Returns:

  • (Bool)

    `true` if the abort request was successful, `false` if the system is already #suspended? or is #suspending?.

Raises:

  • (StateNotAbortable)

    When not #running?.



225
226
227
228
229
230
231
232
233
234
235
236
237
238
# File 'lib/arachni/state/framework.rb', line 225

def abort( block = true )
    return false if aborting? || aborted?

    if !running?
        fail Error::StateNotAbortable, 'Cannot abort an idle state.'
    end

    set_status_message :aborting
    @status = :aborting
    @abort = true

    @aborted_signal.pop if block
    true
end

#abort?Bool

Returns `true` if a #abort signal is in place , `false` otherwise.

Returns:

  • (Bool)

    `true` if a #abort signal is in place , `false` otherwise.



242
243
244
# File 'lib/arachni/state/framework.rb', line 242

def abort?
    !!@abort
end

#abortedObject

Signals a completed abort operation.



247
248
249
250
251
252
# File 'lib/arachni/state/framework.rb', line 247

def aborted
    @abort = false
    @status = :aborted
    @aborted_signal << true
    nil
end

#aborted?Bool

Returns `true` if the system has been aborted, `false` otherwise.

Returns:

  • (Bool)

    `true` if the system has been aborted, `false` otherwise.



256
257
258
# File 'lib/arachni/state/framework.rb', line 256

def aborted?
    @status == :aborted
end

#aborting?Bool

Returns `true` if the system is being aborted, `false` otherwise.

Returns:

  • (Bool)

    `true` if the system is being aborted, `false` otherwise.



262
263
264
# File 'lib/arachni/state/framework.rb', line 262

def aborting?
    @status == :aborting
end

#add_status_message(message, *sprintf) ⇒ Object

Pushes a message to #status_messages.

Parameters:



131
132
133
134
135
136
137
138
139
140
141
142
# File 'lib/arachni/state/framework.rb', line 131

def add_status_message( message, *sprintf )
    if message.is_a? Symbol
        if !available_status_messages.include?( message )
            fail Error::InvalidStatusMessage,
                 "Could not find status message for: '#{message}'"
        end

        message = available_status_messages[message] % sprintf
    end

    @status_messages << message.to_s
end

#available_status_messagesHash{Symbol=>String}

Returns All possible #status_messages by type.

Returns:



100
101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/arachni/state/framework.rb', line 100

def available_status_messages
    {
        suspending:                       'Will suspend as soon as the current page is audited.',
        waiting_for_browser_cluster_jobs: 'Waiting for %i browser cluster jobs to finish.',
        suspending_plugins:               'Suspending plugins.',
        saving_snapshot:                  'Saving snapshot at: %s',
        snapshot_location:                'Snapshot location: %s',
        browser_cluster_startup:          'Initialising the browser cluster.',
        browser_cluster_shutdown:         'Shutting down the browser cluster.',
        clearing_queues:                  'Clearing the audit queues.',
        waiting_for_plugins:              'Waiting for the plugins to finish.',
        aborting:                         'Aborting the scan.'
    }
end

#clearObject



437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
# File 'lib/arachni/state/framework.rb', line 437

def clear
    rpc.clear

    @element_pre_check_filter.clear

    @page_queue_filter.clear
    @url_queue_filter.clear

    @pause_signals.clear
    @paused_signal.clear
    @suspended_signal.clear

    @running = false
    @pre_pause_status = nil

    @browser_skip_states.clear
    @audited_page_count = 0
end

#clear_status_messagesObject



145
146
147
# File 'lib/arachni/state/framework.rb', line 145

def clear_status_messages
    @status_messages.clear
end

#done?Bool

Returns `true` if the system has completed successfully, `false` otherwise.

Returns:

  • (Bool)

    `true` if the system has completed successfully, `false` otherwise.



268
269
270
# File 'lib/arachni/state/framework.rb', line 268

def done?
    @status == :done
end

#dump(directory) ⇒ Object



409
410
411
412
413
414
415
416
417
418
# File 'lib/arachni/state/framework.rb', line 409

def dump( directory )
    FileUtils.mkdir_p( directory )

    rpc.dump( "#{directory}/rpc/" )

    %w(element_pre_check_filter page_queue_filter url_queue_filter
        browser_skip_states audited_page_count).each do |attribute|
        IO.binwrite( "#{directory}/#{attribute}", Marshal.dump( send(attribute) ) )
    end
end

#element_checked(e) ⇒ Object

Parameters:

  • e (Page)

    Element to mark as seen.

See Also:



207
208
209
# File 'lib/arachni/state/framework.rb', line 207

def element_checked( e )
    @element_pre_check_filter << e
end

#element_checked?(e) ⇒ Bool

Returns `true` if the element has already been seen (based on the #element_pre_check_filter), `false` otherwise.

Parameters:

  • e (#coverage_hash)

Returns:

See Also:



199
200
201
# File 'lib/arachni/state/framework.rb', line 199

def element_checked?( e )
    @element_pre_check_filter.include? e
end

#force_resumeObject



403
404
405
406
407
# File 'lib/arachni/state/framework.rb', line 403

def force_resume
    @pause_signals.to_a.each do |ref|
        resume ref
    end
end

#page_seen(page) ⇒ Object

Parameters:

  • page (Page)

    Page to mark as seen.

See Also:



164
165
166
# File 'lib/arachni/state/framework.rb', line 164

def page_seen( page )
    @page_queue_filter << page
end

#page_seen?(page) ⇒ Bool

Returns `true` if the `page` has already been seen (based on the #page_queue_filter), `false` otherwise.

Parameters:

Returns:

  • (Bool)

    `true` if the `page` has already been seen (based on the #page_queue_filter), `false` otherwise.

See Also:



156
157
158
# File 'lib/arachni/state/framework.rb', line 156

def page_seen?( page )
    @page_queue_filter.include? page
end

#pause(caller, block = true) ⇒ TrueClass

Returns Pauses the framework on a best effort basis, might take a while to take effect.

Parameters:

  • caller (Object)

    Identification for the caller which issued the pause signal.

  • block (Bool) (defaults to: true)

    `true` if the method should block until the pause has completed, `false` otherwise.

Returns:

  • (TrueClass)

    Pauses the framework on a best effort basis, might take a while to take effect.



342
343
344
345
346
347
348
349
350
351
352
353
354
355
# File 'lib/arachni/state/framework.rb', line 342

def pause( caller, block = true )
    @pre_pause_status ||= @status if !paused? && !pausing?

    if !paused?
        @status = :pausing
    end

    @pause_signals << caller

    paused if !running?

    @paused_signal.pop if block && !paused?
    true
end

#pause?Bool

Returns `true` if the framework should pause, `false` otherwise.

Returns:

  • (Bool)

    `true` if the framework should pause, `false` otherwise.



378
379
380
# File 'lib/arachni/state/framework.rb', line 378

def pause?
    @pause_signals.any?
end

#pausedObject

Signals that the system has been paused..



358
359
360
361
362
# File 'lib/arachni/state/framework.rb', line 358

def paused
    clear_status_messages
    @status = :paused
    @paused_signal << nil
end

#paused?Bool

Returns `true` if the framework is paused.

Returns:

  • (Bool)

    `true` if the framework is paused.



366
367
368
# File 'lib/arachni/state/framework.rb', line 366

def paused?
    @status == :paused
end

#pausing?Bool

Returns `true` if the system is being paused, `false` otherwise.

Returns:

  • (Bool)

    `true` if the system is being paused, `false` otherwise.



372
373
374
# File 'lib/arachni/state/framework.rb', line 372

def pausing?
    @status == :pausing
end

#resume(caller) ⇒ Bool

Resumes a paused system

Parameters:

  • caller (Object)

    Identification for the caller whose #pause signal to remove. The system is resumed once there are no more #pause signals left.

Returns:

  • (Bool)

    `true` if the system is resumed, `false` if there are more #pause signals pending.



391
392
393
394
395
396
397
398
399
400
401
# File 'lib/arachni/state/framework.rb', line 391

def resume( caller )
    @pause_signals.delete( caller )

    if @pause_signals.empty?
        @status = @pre_pause_status
        @pre_pause_status = nil
        return true
    end

    false
end

#running?Boolean

Returns:

  • (Boolean)


211
212
213
# File 'lib/arachni/state/framework.rb', line 211

def running?
    !!@running
end

#scanning?Bool

Returns `true` if the system is scanning, `false` otherwise.

Returns:

  • (Bool)

    `true` if the system is scanning, `false` otherwise.



329
330
331
# File 'lib/arachni/state/framework.rb', line 329

def scanning?
    @status == :scanning
end

#set_status_message(*args) ⇒ Object

Sets a message as #status_messages.

Parameters:



119
120
121
122
# File 'lib/arachni/state/framework.rb', line 119

def set_status_message( *args )
    clear_status_messages
    add_status_message( *args )
end

#statisticsObject



90
91
92
93
94
95
96
# File 'lib/arachni/state/framework.rb', line 90

def statistics
    {
        rpc:                @rpc.statistics,
        audited_page_count: @audited_page_count,
        browser_states:     @browser_skip_states.size
    }
end

#suspend(block = true) ⇒ Bool

Returns `true` if the suspend request was successful, `false` if the system is already #suspended? or is #suspending?.

Parameters:

  • block (Bool) (defaults to: true)

    `true` if the method should block until a suspend has completed, `false` otherwise.

Returns:

  • (Bool)

    `true` if the suspend request was successful, `false` if the system is already #suspended? or is #suspending?.

Raises:



282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
# File 'lib/arachni/state/framework.rb', line 282

def suspend( block = true )
    return false if suspending? || suspended?

    if paused? || pausing?
        fail Error::StateNotSuspendable, 'Cannot suspend a paused state.'
    end

    if !running?
        fail Error::StateNotSuspendable, 'Cannot suspend an idle state.'
    end

    set_status_message :suspending
    @status = :suspending
    @suspend = true

    @suspended_signal.pop if block
    true
end

#suspend?Bool

Returns `true` if an #abort signal is in place , `false` otherwise.

Returns:

  • (Bool)

    `true` if an #abort signal is in place , `false` otherwise.



303
304
305
# File 'lib/arachni/state/framework.rb', line 303

def suspend?
    !!@suspend
end

#suspendedObject

Signals a completed suspension.



308
309
310
311
312
313
# File 'lib/arachni/state/framework.rb', line 308

def suspended
    @suspend = false
    @status = :suspended
    @suspended_signal << true
    nil
end

#suspended?Bool

Returns `true` if the system has been suspended, `false` otherwise.

Returns:

  • (Bool)

    `true` if the system has been suspended, `false` otherwise.



317
318
319
# File 'lib/arachni/state/framework.rb', line 317

def suspended?
    @status == :suspended
end

#suspending?Bool

Returns `true` if the system is being suspended, `false` otherwise.

Returns:

  • (Bool)

    `true` if the system is being suspended, `false` otherwise.



323
324
325
# File 'lib/arachni/state/framework.rb', line 323

def suspending?
    @status == :suspending
end

#update_browser_skip_states(states) ⇒ Object

Parameters:



188
189
190
# File 'lib/arachni/state/framework.rb', line 188

def update_browser_skip_states( states )
    @browser_skip_states.merge states
end

#url_seen(url) ⇒ Object

Parameters:

  • url (Page)

    URL to mark as seen.

See Also:



183
184
185
# File 'lib/arachni/state/framework.rb', line 183

def url_seen( url )
    @url_queue_filter << url
end

#url_seen?(url) ⇒ Bool

Returns `true` if the `url` has already been seen (based on the #url_queue_filter), `false` otherwise.

Parameters:

Returns:

  • (Bool)

    `true` if the `url` has already been seen (based on the #url_queue_filter), `false` otherwise.

See Also:



175
176
177
# File 'lib/arachni/state/framework.rb', line 175

def url_seen?( url )
    @url_queue_filter.include? url
end