Class: Arachni::Component::Manager

Inherits:
Hash
  • Object
show all
Includes:
UI::Output
Defined in:
lib/arachni/component/manager.rb

Overview

Handles modules, reports, path extractor modules, 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:

Defined Under Namespace

Classes: InvalidOptions

Constant Summary collapse

WILDCARD =

The following are used by #parse:

* '*' means all modules
* module names prefixed with '-' will be excluded
'*'
EXCLUDE =
'-'

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from UI::Output

#debug?, #debug_off, #debug_on, #disable_only_positives, #flush_buffer, #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, #uncap_buffer, #unmute, #verbose, #verbose?

Constructor Details

#initialize(lib, namespace) ⇒ Manager

Returns a new instance of Manager.

Parameters:

  • lib (String)

    the path to the component library/folder

  • namespace (Module, Class)

    the namespace of the components



101
102
103
104
# File 'lib/arachni/component/manager.rb', line 101

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

Instance Attribute Details

#libObject (readonly)

Returns the value of attribute lib.



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

def lib
  @lib
end

#namespaceObject (readonly)

Returns the value of attribute namespace.



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

def namespace
  @namespace
end

Instance Method Details

#[](name) ⇒ Class

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

Parameters:

  • name (String, Symbol)

    component name

Returns:

  • (Class)

    component



266
267
268
269
270
# File 'lib/arachni/component/manager.rb', line 266

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

#availableArray

Returns an array of available component names.

Returns:



303
304
305
# File 'lib/arachni/component/manager.rb', line 303

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

#clearObject Also known as: unload_all

Unloads all loaded components.



278
279
280
# File 'lib/arachni/component/manager.rb', line 278

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



288
289
290
291
292
293
294
295
# File 'lib/arachni/component/manager.rb', line 288

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)


272
273
274
# File 'lib/arachni/component/manager.rb', line 272

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

#load(*components) ⇒ Array

Loads components.

Parameters:

  • components (Array)

    array of names of components to load

Returns:

  • (Array)

    names of loaded components



113
114
115
# File 'lib/arachni/component/manager.rb', line 113

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



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

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[:tags]

Parameters:

  • tags (Array)

    tags to look for in components

Returns:

  • (Array)

    components loaded



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

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 an array of loaded component names.

Returns:



312
313
314
# File 'lib/arachni/component/manager.rb', line 312

def loaded
    keys
end

#name_to_path(name) ⇒ String

Converts the name of a component to a file-path.

Parameters:

  • name (String)

    the name of the component

Returns:

  • (String)

    path to component file



323
324
325
326
# File 'lib/arachni/component/manager.rb', line 323

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

#parse(components) ⇒ Array

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

Parameters:

  • components (Array)

    array of component names

Returns:

  • (Array)

    array of modules to load



209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
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
# File 'lib/arachni/component/manager.rb', line 209

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.substring?( WILDCARD )
                load |= wilcard_to_names( component )
            else

                if avail_components.include?( component )
                    load << component
                else
                    fail( Exceptions::ComponentNotFound,
                        "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)

    the file-path of the component

Returns:



335
336
337
# File 'lib/arachni/component/manager.rb', line 335

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

#pathsArray

Returns the paths of all available components (excluding helper files).

Returns:



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

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

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

Validates and prepares options for a given component.

Parameters:

  • component_name (String)

    the name of the component

  • component (Class)

    the component

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

    the user options

Returns:

  • (Hash)

    the prepared options to be passed to the component



166
167
168
169
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
# File 'lib/arachni/component/manager.rb', line 166

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

    user_opts ||= {}
    options = {}
    errors  = {}
    info[:options].each do |opt|
        name = opt.name
        val  = user_opts[name] || opt.default

        if opt.empty_required_value?( val )
            errors[name] = {
                opt:   opt,
                value: val,
                type:  :empty_required_value
            }
        elsif !opt.valid?( val )
            errors[name] = {
                opt:   opt,
                value: val,
                type:  :invalid
            }
        end

        options[name] = opt.normalize( val )
    end

    if !errors.empty?
        fail InvalidOptions.new( format_error_string( component_name, errors ) )
    end

    options
end