Class: Arachni::Plugin::Manager

Inherits:
Component::Manager show all
Extended by:
Utilities
Includes:
Utilities
Defined in:
lib/arachni/plugin/manager.rb

Overview

Holds and manages the plugins.

Author:

Direct Known Subclasses

RPC::Server::Plugin::Manager

Constant Summary collapse

NAMESPACE =

Namespace under which all plugins reside.

Arachni::Plugins
DEFAULT =

Expressions matching default plugins.

%w(defaults/*)

Constants inherited from Component::Manager

Component::Manager::EXCLUDE, Component::Manager::WILDCARD

Instance Attribute Summary

Attributes inherited from Component::Manager

#lib, #namespace

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Utilities

available_port, cookie_encode, cookies_from_document, cookies_from_file, cookies_from_response, exception_jail, exclude_path?, extract_domain, follow_protocol?, form_decode, form_encode, form_parse_request_body, forms_from_document, forms_from_response, generate_token, get_path, html_decode, html_encode, include_path?, links_from_document, links_from_response, normalize_url, page_from_response, page_from_url, parse_query, parse_set_cookie, parse_url_vars, path_in_domain?, path_too_deep?, port_available?, rand_port, redundant_path?, remove_constants, seed, skip_page?, skip_path?, skip_resource?, to_absolute, uri_decode, uri_encode, uri_parse, uri_parser, url_sanitize

Methods inherited from Component::Manager

#[], #available, #clear, #delete, #include?, #load, #load_all, #load_by_tags, #loaded, #name_to_path, #parse, #path_to_name, #paths, #prep_opts

Methods included from UI::Output

#debug?, #debug_off, #debug_on, #disable_only_positives, #error_logfile, #flush_buffer, #log_error, #mute, #muted?, old_reset_output_options, #only_positives, #only_positives?, #print_bad, #print_debug, #print_debug_backtrace, #print_debug_pp, #print_error, #print_error_backtrace, #print_info, #print_line, #print_ok, #print_status, #print_verbose, #reroute_to_file, #reroute_to_file?, reset_output_options, #set_buffer_cap, #set_error_logfile, #uncap_buffer, #unmute, #verbose, #verbose?

Methods inherited from Hash

#downcase, #find_symbol_keys_recursively, #recode, #stringify_keys, #symbolize_keys

Constructor Details

#initialize(framework) ⇒ Manager

Returns a new instance of Manager.

Parameters:



48
49
50
51
52
53
# File 'lib/arachni/plugin/manager.rb', line 48

def initialize( framework )
    super( framework.opts.dir['plugins'], NAMESPACE )
    @framework = framework

    @jobs = []
end

Class Method Details

.mutexObject



229
230
231
# File 'lib/arachni/plugin/manager.rb', line 229

def self.mutex
    @mutex ||= Mutex.new
end

.resetObject



250
251
252
253
# File 'lib/arachni/plugin/manager.rb', line 250

def self.reset
    results.clear
    remove_constants( NAMESPACE )
end

.resultsObject



236
237
238
# File 'lib/arachni/plugin/manager.rb', line 236

def self.results
    @results ||= {}
end

.results=(v) ⇒ Object



243
244
245
# File 'lib/arachni/plugin/manager.rb', line 243

def self.results=( v )
    @results = v
end

Instance Method Details

#blockObject

Blocks until all plug-ins have finished executing.



155
156
157
158
159
160
161
162
163
164
165
166
# File 'lib/arachni/plugin/manager.rb', line 155

def block
    while !@jobs.empty?
        print_debug
        print_debug "Waiting on the following (#{@jobs.size}) plugins to finish:"
        print_debug job_names.join( ', ' )
        print_debug

        @jobs.delete_if { |j| !j.alive? }
        ::IO::select( nil, nil, nil, 1 )
    end
    nil
end

#busy?Bool

Returns ‘false` if all plug-ins have finished executing, `true` otherwise.

Returns:

  • (Bool)

    ‘false` if all plug-ins have finished executing, `true` otherwise.



170
171
172
# File 'lib/arachni/plugin/manager.rb', line 170

def busy?
    !@jobs.reject{ |j| j.alive? }.empty?
end

#create(name, opts = {}) ⇒ Object



150
151
152
# File 'lib/arachni/plugin/manager.rb', line 150

def create( name, opts ={} )
    self[name].new( @framework, opts )
end

#defaultArray<String> Also known as: defaults

Returns Components to load, by name.

Returns:



64
65
66
# File 'lib/arachni/plugin/manager.rb', line 64

def default
    parse DEFAULT
end

#get(name) ⇒ Thread

Gets a running plug-in by name.

Parameters:

Returns:

  • (Thread)


202
203
204
205
# File 'lib/arachni/plugin/manager.rb', line 202

def get( name )
    @jobs.each { |job| return job if job[:name] == name }
    nil
end

#job_namesArray

Returns Names of all running plug-ins.

Returns:

  • (Array)

    Names of all running plug-ins.



175
176
177
# File 'lib/arachni/plugin/manager.rb', line 175

def job_names
    @jobs.map{ |j| j[:name] }
end

#jobsArray<Thread>

Returns All the running threads.

Returns:

  • (Array<Thread>)

    All the running threads.



180
181
182
# File 'lib/arachni/plugin/manager.rb', line 180

def jobs
    @jobs
end

#kill(name) ⇒ Object

Kills a plug-in by ‘name`.

Parameters:



189
190
191
192
193
# File 'lib/arachni/plugin/manager.rb', line 189

def kill( name )
    job = get( name )
    return true if job && job.kill
    false
end

#load_defaultObject Also known as: load_defaults

Loads the default plugins.

See Also:



58
59
60
# File 'lib/arachni/plugin/manager.rb', line 58

def load_default
    load DEFAULT
end

#mutexObject



232
233
234
# File 'lib/arachni/plugin/manager.rb', line 232

def mutex
    self.class.mutex
end

#register_results(plugin, results) ⇒ Object

Registers plugin results.

Parameters:



213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
# File 'lib/arachni/plugin/manager.rb', line 213

def register_results( plugin, results )
    mutex.synchronize {
        name = nil
        self.each do |k, v|
            if plugin.class.name == v.name
                name = k
                break
            end
        end

        return if !name
        self.class.results[name] =
            { results: results }.merge( plugin.class.info )
    }
end

#resetObject



254
255
256
# File 'lib/arachni/plugin/manager.rb', line 254

def reset
    self.class.reset
end

#resultsObject



239
240
241
# File 'lib/arachni/plugin/manager.rb', line 239

def results
    self.class.results
end

#results=(v) ⇒ Object



246
247
248
# File 'lib/arachni/plugin/manager.rb', line 246

def results=( v )
    self.class.results = v
end

#runObject

Runs each plug-in in its own thread.

Raises:



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# File 'lib/arachni/plugin/manager.rb', line 73

def run
    ordered   = []
    unordered = []

    loaded.each do |name|
        ph = { name => self[name] }
        if order = self[name].info[:priority]
            ordered[order] ||= []
            ordered[order] << ph
        else
            unordered << ph
        end
    end
    ordered << unordered
    ordered.flatten!

    ordered.each do |ph|
        name   = ph.keys.first
        plugin = ph.values.first

        if( ret = sane_env?( plugin ) ) != true
            deps = ''
            if !ret[:gem_errors].empty?
                print_bad "[#{name}] The following plug-in dependencies aren't satisfied:"
                ret[:gem_errors].each { |gem| print_bad "\t* #{gem}" }

                deps = ret[:gem_errors].join( ' ' )
                print_bad 'Try installing them by running:'
                print_bad "\tgem install #{deps}"
            end

            fail Error::UnsatisfiedDependency,
                 "Plug-in dependencies not met: #{name} -- #{deps}"
        end

        opts = @framework.opts.plugins[name]
        opts = prep_opts( name, self[name], opts )

        @jobs << Thread.new {

            exception_jail( false ) {
                Thread.current[:name]     = name
                Thread.current[:instance] = plugin_new = create( name, opts )

                plugin_new.prepare
                plugin_new.run
                plugin_new.clean_up
            }

        }
    end

    return if @jobs.empty?

    print_status 'Waiting for plugins to settle...'
    ::IO::select( nil, nil, nil, 1 )
end

#sane_env?(plugin) ⇒ TrueClass, Hash

Checks whether or not the environment satisfies all plugin dependencies.

Returns:

  • (TrueClass, Hash)

    ‘true` if the environment is sane, a hash with errors otherwise.



135
136
137
138
139
140
141
142
143
144
145
146
147
148
# File 'lib/arachni/plugin/manager.rb', line 135

def sane_env?( plugin )
    gem_errors = []

    plugin.gems.each do |gem|
        begin
            require gem
        rescue LoadError
            gem_errors << gem
        end
    end

    return { gem_errors: gem_errors } if !gem_errors.empty?
    true
end