class Arachni::Options

Provides access to all of {Arachni}‘s runtime options.

To make management of options for different subsystems easier, some options are {OptionGroups grouped together}.

{OptionGroups Option groups} are initialized and added as attribute readers to this class dynamically. Their attribute readers are named after the group’s filename and can be accessed, like so:

Arachni::Options.scope.page_limit = 10

@author Tasos “Zapotek” Laskos <tasos.laskos@arachni-scanner.com> @see OptionGroups

Attributes

authorized_by[RW]

@return [String]

E-mail address of the person that authorized the scan. It will be added
to the HTTP `From` headers.

@see HTTP::Client#headers

checks[RW]

@return [Array<String, Symbol>]

Checks to load, by name.

@see Checks @see Check::Base @see Check::Manager

no_fingerprinting[RW]

@return [Bool]

Disable platform fingeprinting.

@see Platform::Fingerprinter @see Platform::Fingerprinters @see Platform::List @see Platform::Manager

parsed_url[R]

@return [Arachni::URI]

platforms[RW]

@return [Array<Symbol>]

Platforms to use instead of (or in addition to, depending on the
{#no_fingerprinting option}) fingerprinting.

@see Platform @see Platform::List @see Platform::Manager

plugins[RW]

@return [Hash{<String, Symbol> => Hash{String => String}}]

Plugins to load, by name, as keys and their options as values.

@see Plugins @see Plugin::Base @see Plugin::Manager

spawns[RW]

@return [Integer]

Amount of child {RPC::Server::Instance}s to spawn when performing
multi-{RPC::Server::Instance} scans.

@see UI::CLI::RPC::Instance#scan

url[R]

@return [String]

The URL to audit.

Public Class Methods

group_classes() click to toggle source

@return [Hash<Symbol,OptionGroup>]

{OptionGroups Option group} classes by name.
# File lib/arachni/options.rb, line 73
def group_classes
    @group_classes ||= {}
end
method_missing( sym, *args, &block ) click to toggle source
Calls superclass method
# File lib/arachni/options.rb, line 55
def method_missing( sym, *args, &block )
    if instance.respond_to?( sym )
        instance.send( sym, *args, &block )
    else
        super( sym, *args, &block )
    end
end
new() click to toggle source
# File lib/arachni/options.rb, line 150
def initialize
    reset
end
register_group( group ) click to toggle source

Should be called by {OptionGroup.inherited}. @private

# File lib/arachni/options.rb, line 79
def register_group( group )
    name = Utilities.caller_name

    # Prepare an attribute reader for this group...
    attr_reader name

    # ... and initialize it.
    instance_variable_set "@#{name}".to_sym, group.new

    group_classes[name.to_sym] = group
end
respond_to?( *args ) click to toggle source
Calls superclass method
# File lib/arachni/options.rb, line 63
def respond_to?( *args )
    super || instance.respond_to?( *args )
end

Public Instance Methods

do_not_fingerprint() click to toggle source

Disables platform fingerprinting.

# File lib/arachni/options.rb, line 185
def do_not_fingerprint
    self.no_fingerprinting = true
end
fingerprint() click to toggle source

Enables platform fingerprinting.

# File lib/arachni/options.rb, line 190
def fingerprint
    self.no_fingerprinting = false
end
fingerprint?() click to toggle source

@return [Bool]

`true` if platform fingerprinting is enabled, `false` otherwise.
# File lib/arachni/options.rb, line 196
def fingerprint?
    !@no_fingerprinting
end
hash_to_rpc_data( hash ) click to toggle source

@param [Hash] hash

Hash to convert into {#to_rpc_data} format.

@return [Hash]

`hash` in {#to_rpc_data} format.
# File lib/arachni/options.rb, line 391
def hash_to_rpc_data( hash )
    self.class.allocate.reset.update( hash ).to_rpc_data
end
hash_to_save_data( hash ) click to toggle source
# File lib/arachni/options.rb, line 395
def hash_to_save_data( hash )
    self.class.allocate.reset.update( hash ).to_save_data
end
load( filepath ) click to toggle source

Loads a file created by {#save}.

@param [String] filepath

Path to the file created by {#save}.

@return [Arachni::Options]

# File lib/arachni/options.rb, line 331
def load( filepath )
    update( YAML.load_file( filepath ) )
end
reset() click to toggle source

Restores everything to their default values.

@return [Options] ‘self`

# File lib/arachni/options.rb, line 157
def reset
    # nil everything out.
    instance_variables.each { |var| instance_variable_set( var.to_s, nil ) }

    # Set fresh option groups.
    group_classes.each do |name, klass|
        instance_variable_set "@#{name}".to_sym, klass.new
    end

    @checks    = []
    @platforms = []
    @plugins   = {}
    @spawns    = 0

    @no_fingerprinting = false
    @authorized_by     = nil

    self
end
rpc_data_to_hash( hash ) click to toggle source

@param [Hash] hash

Hash to convert into {#to_hash} format.

@return [Hash]

`hash` in {#to_hash} format.
# File lib/arachni/options.rb, line 382
def rpc_data_to_hash( hash )
    self.class.allocate.reset.update( hash ).to_hash
end
save( file ) click to toggle source

@param [String] file

Saves `self` to `file` using YAML.
# File lib/arachni/options.rb, line 314
def save( file )
    File.open( file, 'w' ) do |f|
        f.write to_save_data
        f.path
    end
end
set( options )
Alias for: update
spawns=( spawns ) click to toggle source

@param [Integer] spawns

@see spawns

# File lib/arachni/options.rb, line 180
def spawns=( spawns )
    @spawns = spawns.to_i
end
to_h()
Alias for: to_hash
to_hash() click to toggle source

@return [Hash]

`self` converted to a Hash.
# File lib/arachni/options.rb, line 360
def to_hash
    hash = {}
    instance_variables.each do |var|
        val = instance_variable_get( var )
        next if (var = normalize_name( var )) == :instance

        hash[var] = (val.is_a? OptionGroup) ? val.to_h : val
    end

    hash.delete( :url ) if !hash[:url]
    hash.delete( :parsed_url )
    hash.delete(:paths)

    hash.deep_clone
end
Also aliased as: to_h
to_rpc_data() click to toggle source

@return [Hash]

`self` converted to a Hash suitable for RPC transmission.
# File lib/arachni/options.rb, line 337
def to_rpc_data
    ignore = Set.new([:instance, :rpc, :dispatcher, :paths, :spawns,
                      :snapshot, :output])

    hash = {}
    instance_variables.each do |var|
        val = instance_variable_get( var )
        var = normalize_name( var )

        next if ignore.include?( var )

        hash[var.to_s] = (val.is_a? OptionGroup) ? val.to_rpc_data : val
    end
    hash = hash.deep_clone

    hash.delete( 'url' ) if !hash['url']
    hash.delete( 'parsed_url' )

    hash
end
to_save_data() click to toggle source
# File lib/arachni/options.rb, line 321
def to_save_data
    to_rpc_data.to_yaml
end
update( options ) click to toggle source

Configures options via a Hash object.

@example Configuring direct and {OptionGroups} attributes.

{
    # Direct Options#url attribute.
    url:    'http://test.com/',
    # Options#audit attribute pointing to an OptionGroups::Audit instance.
    audit:  {
        # Works due to the OptionGroups::Audit#elements= helper method.
        elements: [ :links, :forms, :cookies ]
    },
    # Direct Options#checks attribute.
    checks: [ :xss, 'sql_injection*' ],
    # Options#scope attribute pointing to an OptionGroups::Scope instance.
    scope:  {
        # OptionGroups::Scope#page_limit
        page_limit:            10,
        # OptionGroups::Scope#directory_depth_limit
        directory_depth_limit: 3
    },
    # Options#http attribute pointing to an OptionGroups::HTTP instance.
    http:  {
        # OptionGroups::HTTP#request_concurrency
        request_concurrency: 25,
        # OptionGroups::HTTP#request_timeout
        request_timeout:     10_000
    }
}

@param [Hash] options

If the key refers to a class attribute, the attribute will be assigned
the given value, if it refers to one of the {OptionGroups} the value
should be a hash with data to update that {OptionGroup group} using
{OptionGroup#update}.

@return [Options]

@see OptionGroups

# File lib/arachni/options.rb, line 287
def update( options )
    options.each do |k, v|
        k = k.to_sym
        if group_classes.include? k
            send( k ).update v
        else
            send( "#{k.to_s}=", v )
        end
    end

    self
end
Also aliased as: set
url=( url ) click to toggle source

Normalizes and sets ‘url` as the target URL.

@param [String] url

Absolute URL of the targeted web app.

@return [String]

Normalized `url`

@raise [Error::InvalidURL]

If the given `url` is not valid.
# File lib/arachni/options.rb, line 210
def url=( url )
    return @url = nil if !url

    parsed = Arachni::URI( url.to_s )

    if parsed.to_s.empty? || !parsed.absolute?

        fail Error::InvalidURL,
             'Invalid URL argument, please provide a full absolute URL and try again.'

    # PhantomJS won't proxy localhost.
    elsif parsed.host == 'localhost' || parsed.host.start_with?( '127.' )

        fail Error::ReservedHostname,
             "Loopback interfaces (like #{parsed.host}) are not supported," <<
                 ' please use a different IP address or hostname.'

    else

        if scope.https_only? && parsed.scheme != 'https'

            fail Error::InvalidURL,
                 "Invalid URL argument, the 'https-only' option requires"+
                     ' an HTTPS URL.'

        elsif !%w(http https).include?( parsed.scheme )

            fail Error::InvalidURL,
                 'Invalid URL scheme, please provide an HTTP or HTTPS URL and try again.'

        end

    end

    @parsed_url = parsed
    @url        = parsed.to_s
end
validate() click to toggle source

@return [Hash]

Hash of errors with the name of the invalid options/groups as the keys.
# File lib/arachni/options.rb, line 303
def validate
    errors = {}
    group_classes.keys.each do |name|
        next if (group_errors = send(name).validate).empty?
        errors[name] = group_errors
    end
    errors
end

Private Instance Methods

group_classes() click to toggle source
# File lib/arachni/options.rb, line 401
def group_classes
    self.class.group_classes
end
normalize_name( name ) click to toggle source
# File lib/arachni/options.rb, line 405
def normalize_name( name )
    name.to_s.gsub( '@', '' ).to_sym
end