Class: Arachni::Component::Manager

Inherits:
Hash show all
Extended by:
Utilities
Includes:
UI::Output, Utilities
Defined in:
lib/arachni/component/manager.rb

Overview

Handles checks, reports, path extractor checks, plug-ins, pretty much every modular aspect of the framework.

It is usually extended to fill-in for system specific functionality.

Examples:


# create a namespace for our components
module Components
end

LIB       = "#{File.dirname( __FILE__ )}/lib/"
NAMESPACE = Components

# $ ls LIB
#   component1.rb  component2.rb
#
# $ cat LIB/component1.rb
#   class Components::Component1
#   end
#
# $ cat LIB/component2.rb
#   class Components::Component2
#   end

p components = Arachni::Component::Manager.new( LIB, NAMESPACE )
#=> {}

p components.available
#=> ["component2", "component1"]

p components.load_all
#=> ["component2", "component1"]

p components
#=> {"component2"=>Components::Component2, "component1"=>Components::Component1}

p components.clear
#=> {}

p components.load :component1
#=> ["component1"]

p components
#=> {"component1"=>Components::Component1}

p components.clear
#=> {}

p components[:component2]
#=> Components::Component2

Author:

Constant Summary collapse

WILDCARD =
'*'
EXCLUDE =
'-'

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Utilities

available_port, caller_name, caller_path, cookie_decode, cookie_encode, cookies_from_document, cookies_from_file, cookies_from_response, exception_jail, exclude_path?, follow_protocol?, form_decode, form_encode, forms_from_document, forms_from_response, generate_token, get_path, hms_to_seconds, html_decode, html_encode, include_path?, links_from_document, links_from_response, normalize_url, page_from_response, page_from_url, parse_set_cookie, path_in_domain?, path_too_deep?, port_available?, rand_port, random_seed, redundant_path?, regexp_array_match, remove_constants, request_parse_body, seconds_to_hms, skip_page?, skip_path?, skip_resource?, skip_response?, to_absolute, uri_decode, uri_encode, uri_parse, uri_parse_query, uri_parser, uri_rewrite

Methods included from UI::Output

#debug?, #debug_off, #debug_on, #disable_only_positives, #included, #mute, #muted?, #only_positives, #only_positives?, #print_bad, #print_debug, #print_debug_backtrace, #print_debug_level_1, #print_debug_level_2, #print_debug_level_3, #print_error, #print_error_backtrace, #print_exception, #print_info, #print_line, #print_ok, #print_status, #print_verbose, #reroute_to_file, #reroute_to_file?, reset_output_options, #unmute, #verbose?, #verbose_on

Methods inherited from Hash

#apply_recursively, #downcase, #find_symbol_keys_recursively, #my_stringify, #my_stringify_keys, #my_symbolize_keys, #recode, #stringify_recursively_and_freeze

Constructor Details

#initialize(lib, namespace) ⇒ Manager

Returns a new instance of Manager.

Parameters:

  • lib (String)

    The path to the component library/directory.

  • namespace (Module, Class)

    Namespace under which all components are directly defined.



104
105
106
107
# File 'lib/arachni/component/manager.rb', line 104

def initialize( lib, namespace )
    @lib       = lib
    @namespace = namespace
end

Instance Attribute Details

#libString (readonly)

Returns The path to the component library/directory.

Returns:

  • (String)

    The path to the component library/directory.



94
95
96
# File 'lib/arachni/component/manager.rb', line 94

def lib
  @lib
end

#namespaceModule (readonly)

Returns Namespace under which all components are directly defined.

Returns:

  • (Module)

    Namespace under which all components are directly defined.



98
99
100
# File 'lib/arachni/component/manager.rb', line 98

def namespace
  @namespace
end

Instance Method Details

#[](name) ⇒ Component::Base

Fetches a component’s class by name, loading it on the fly if need be.

Parameters:

  • name (String, Symbol)

    Component name.

Returns:



281
282
283
284
285
# File 'lib/arachni/component/manager.rb', line 281

def []( name )
    name = name.to_s
    return fetch( name ) if include?( name )
    self[name] = load_from_path( name_to_path( name ) )
end

#availableArray

Returns Names of available components.

Returns:

  • (Array)

    Names of available components.



314
315
316
# File 'lib/arachni/component/manager.rb', line 314

def available
    paths.map{ |path| path_to_name( path ) }
end

#clearObject Also known as: unload_all

Unloads all loaded components.



293
294
295
# File 'lib/arachni/component/manager.rb', line 293

def clear
    keys.each { |l| delete( l ) }
end

#delete(name) ⇒ Object Also known as: unload

Unloads a component by name.

Parameters:

  • name (String, Symbol)

    Component name.



302
303
304
305
306
307
308
309
# File 'lib/arachni/component/manager.rb', line 302

def delete( name )
    name = name.to_s
    begin
        @namespace.send( :remove_const, fetch( name ).to_s.split( ':' ).last.to_sym )
    rescue
    end
    super( name )
end

#include?(k) ⇒ Boolean Also known as: loaded?

Returns:

  • (Boolean)


287
288
289
# File 'lib/arachni/component/manager.rb', line 287

def include?( k )
    super( k.to_s )
end

#load(*components) ⇒ Array

Loads components.

Parameters:

  • components (Array<String,Symbol>)

    Components to load.

Returns:

  • (Array)

    Names of loaded components.



116
117
118
# File 'lib/arachni/component/manager.rb', line 116

def load( *components )
    parse( [components].flatten ).each { |component| self.[]( component ) }
end

#load_allArray

Loads all components, equivalent of ‘load ’*‘`.

Returns:

  • (Array)

    Names of loaded components.



124
125
126
# File 'lib/arachni/component/manager.rb', line 124

def load_all
    load '*'
end

#load_by_tags(tags) ⇒ Array

Loads components by the tags found in the ‘Hash` returned by their `.info` method (tags should be in either: `:tags` or `:issue`).

Parameters:

  • tags (Array)

    Tags to look for in components.

Returns:

  • (Array)

    Components loaded.



136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/arachni/component/manager.rb', line 136

def load_by_tags( tags )
    return [] if !tags

    tags = [tags].flatten.compact.map( &:to_s )
    return [] if tags.empty?

    load_all
    map do |k, v|
        component_tags  = [v.info[:tags]]
        component_tags |= [v.info[:issue][:tags]] if v.info[:issue]
        component_tags  = [component_tags].flatten.uniq.compact

        if !component_tags.includes_tags?( tags )
            delete( k )
            next
        end
        k
    end.compact
end

#loadedArray

Returns Names of loaded components.

Returns:

  • (Array)

    Names of loaded components.



320
321
322
# File 'lib/arachni/component/manager.rb', line 320

def loaded
    keys
end

#name_to_path(name) ⇒ String

Converts the name of a component to a its file’s path.

Parameters:

  • name (String)

    Name of the component.

Returns:

  • (String)

    Path to component file.



331
332
333
334
# File 'lib/arachni/component/manager.rb', line 331

def name_to_path( name )
    paths.each { |path| return path if name.to_s == path_to_name( path ) }
    nil
end

#parse(components) ⇒ Array

It parses the component array making sure that its structure is valid and takes into consideration wildcard and exclusion modifiers.

Parameters:

  • components (Array<String,Symbol>)

    Component names.

Returns:

  • (Array)

    Components to load.



224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
# File 'lib/arachni/component/manager.rb', line 224

def parse( components )
    unload = []
    load   = []

    components = [components].flatten.map( &:to_s )

    return load if components[0] == EXCLUDE

    components = components.deep_clone

    components.each do |component|
        if component[0] == EXCLUDE
            component[0] = ''

            if component[WILDCARD]
                unload |= wilcard_to_names( component )
            else
                unload << component
            end

        end
    end

    if !components.include?( WILDCARD )

        avail_components  = available(  )

        components.each do |component|

            if component.include?( WILDCARD )
                load |= wilcard_to_names( component )
            else

                if avail_components.include?( component )
                    load << component
                else
                    fail Error::NotFound,
                         "Component '#{component}' could not be found."
                end
            end
        end

        load.flatten!
    else
        available.each{ |component| load << component }
    end

    load - unload
end

#path_to_name(path) ⇒ String

Converts the path of a component to a component name.

Parameters:

  • path (String)

    File-path of the component.

Returns:

  • (String)

    Component name.



343
344
345
# File 'lib/arachni/component/manager.rb', line 343

def path_to_name( path )
    File.basename( path, '.rb' )
end

#pathsArray

Returns Paths of all available components (excluding helper files).

Returns:

  • (Array)

    Paths of all available components (excluding helper files).



349
350
351
# File 'lib/arachni/component/manager.rb', line 349

def paths
    Dir.glob( File.join( "#{@lib}**", "*.rb" ) ).reject{ |path| helper?( path ) }
end

#prepare_options(component_name, component, user_opts = {}) ⇒ Hash

Validates and prepares options for a given component.

Parameters:

  • component_name (String)

    Name of the component.

  • component (Component::Base)

    Component.

  • user_opts (Hash) (defaults to: {})

    User options.

Returns:

  • (Hash)

    Prepared options to be passed to the component.

Raises:



170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
# File 'lib/arachni/component/manager.rb', line 170

def prepare_options( component_name, component, user_opts = {} )
    info = component.info
    return {} if !info.include?( :options ) || info[:options].empty?

    user_opts ||= {}
    user_opts   = user_opts.my_symbolize_keys(false)

    options     = {}
    errors      = {}
    info[:options].each do |option|
        option.value = user_opts[option.name]

        if option.missing_value?
            errors[option.name] = {
                option: option,
                value:  option.value,
                type:   :missing_value
            }

            break
        end

        next if option.effective_value.nil?

        if !option.valid?
            errors[option.name] = {
                option: option,
                value:  option.value,
                type:   :invalid
            }

            break
        end

        options.merge! option.for_component
    end

    if !errors.empty?
        fail Component::Options::Error::Invalid,
             format_error_string( component_name, errors )
    end

    options.my_symbolize_keys( false )
end