class Arachni::Report

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

Attributes

finish_datetime[RW]

@return [Time]

The date and time when the scan finished.
options[R]

@return [Hash]

{Options#to_h}
plugins[RW]

@return [Hash]

Plugin results.
seed[RW]

@return [String]

Scan seed.
sitemap[RW]

@return [Hash<String, Integer>]

List of crawled URLs with their HTTP codes.
start_datetime[RW]

@return [Time]

The date and time when the scan started.
version[RW]

@return [String]

{Arachni::VERSION}

Public Class Methods

from_rpc_data( data ) click to toggle source

@param [Hash] data {#to_rpc_data} @return [DOM]

# File lib/arachni/report.rb, line 263
def self.from_rpc_data( data )
    data['start_datetime']  = Time.parse( data['start_datetime'] )
    data['finish_datetime'] = Time.parse( data['finish_datetime'] )

    data['issues'] = data['issues'].map { |i| Arachni::Issue.from_rpc_data( i ) }

    data['plugins'] = data['plugins'].inject({}) do |h, (k, v)|
        k    = k.to_sym
        h[k] = v.my_symbolize_keys(false)
        next h if !h[k][:options]

        h[k][:options] = v['options'].map do |option|
            klass = option['class'].split( '::' ).last.to_sym
            Component::Options.const_get( klass ).from_rpc_data( option )
        end
        h
    end

    new data
end
load( file ) click to toggle source

Loads and a {#save saved} {Report} object from file.

@param [String] file

File created by {#save}.

@return [Report]

Loaded instance.
# File lib/arachni/report.rb, line 138
def self.load( file )
    File.open( file, 'rb' ) do |f|
        f.seek -4, IO::SEEK_END
        summary_size = f.read( 4 ).unpack( 'N' ).first

        f.rewind
        from_rpc_data RPC::Serializer.load( f.read( f.size - summary_size ) )
    end
end
new( options = {} ) click to toggle source
# File lib/arachni/report.rb, line 45
def initialize( options = {} )
    options.each { |k, v| send( "#{k}=", v ) }

    @version     ||= Arachni::VERSION
    @seed        ||= Arachni::Utilities.random_seed
    @plugins     ||= {}
    @sitemap     ||= {}
    self.options ||= Options
    @issues      ||= {}

    @start_datetime  ||= Time.now
    @finish_datetime ||= Time.now
end
read_summary( report ) click to toggle source

@param [String] report

Location of the report.

@return [Hash]

{#summary} associated with the given report.
# File lib/arachni/report.rb, line 121
def self.read_summary( report )
    File.open( report ) do |f|
        f.seek -4, IO::SEEK_END
        summary_size = f.read( 4 ).unpack( 'N' ).first

        f.seek -summary_size-4, IO::SEEK_END
        RPC::Serializer.load( f.read( summary_size ) )
    end
end

Public Instance Methods

==( other ) click to toggle source
# File lib/arachni/report.rb, line 284
def ==( other )
    hash == other.hash
end
delta_time() click to toggle source

@note If no {#finish_datetime} has been provided, it will use ‘Time.now`.

@return [String]

`{#start_datetime} - {#finish_datetime}` in `00:00:00`
(`hours:minutes:seconds`) format.
# File lib/arachni/report.rb, line 68
def delta_time
    seconds_to_hms( (@finish_datetime || Time.now) - @start_datetime )
end
hash() click to toggle source
# File lib/arachni/report.rb, line 288
def hash
    h = to_hash
    [:start_datetime, :finish_datetime, :delta_datetime].each do |k|
        h.delete k
    end
    h.hash
end
issue_by_digest( digest ) click to toggle source

@param [Issue#digest] digest

@return [Issue]

# File lib/arachni/report.rb, line 112
def issue_by_digest( digest )
    @issues[digest]
end
issues() click to toggle source

@return [Array<Issue>]

Logged issues.
# File lib/arachni/report.rb, line 105
def issues
    @issues.values
end
issues=( issues ) click to toggle source

@param [Array<Issue>] issues

Logged issues.

@return [Array<Issue>]

Logged issues.
# File lib/arachni/report.rb, line 85
def issues=( issues )
    @issues = {}
    issues.each do |issue|
        @issues[issue.digest] = issue
    end
    self.issues
end
issues_by_check( check ) click to toggle source

@param [String] check

Check shortname.

@return [Array<Issue>]

# File lib/arachni/report.rb, line 97
def issues_by_check( check )
    @issues.map do |_, issue|
        issue if issue.check[:shortname] == check.to_s
    end.compact
end
options=( options ) click to toggle source

@param [Options, Hash] options

Scan {Options options}.

@return [Hash]

# File lib/arachni/report.rb, line 76
def options=( options )
    @options = prepare_options( options )
end
save( location = nil ) click to toggle source

@param [String] location

Location for the {#to_afr dumped} report file.

@return [String]

Absolute location of the report.
# File lib/arachni/report.rb, line 153
def save( location = nil )
    default_filename = "#{URI(url).host} #{@finish_datetime.to_s.gsub( ':', '_' )}.afr"

    if !location
        location = default_filename
    elsif File.directory? location
        location += "/#{default_filename}"
    end

    IO.binwrite( location, to_afr )

    File.expand_path( location )
end
summary() click to toggle source

@return [Hash]

Summary data of the report.
# File lib/arachni/report.rb, line 207
def summary
    by_severity = Hash.new(0)
    @issues.each { |_, issue| by_severity[issue.severity.to_sym] += 1 }

    by_type = Hash.new(0)
    @issues.each { |_, issue| by_type[issue.name] += 1 }

    by_check = Hash.new(0)
    @issues.each { |_, issue| by_check[issue.check[:shortname]] += 1 }

    {
        version:         @version,
        seed:            @seed,
        url:             url,
        checks:          @options[:checks],
        plugins:         @options[:plugins].keys,
        issues: {
            total:       @issues.size,
            by_severity: by_severity,
            by_type:     by_type,
            by_check:    by_check
        },
        sitemap_size:    @sitemap.size,
        start_datetime:  @start_datetime.to_s,
        finish_datetime: @finish_datetime.to_s,
        delta_time:      delta_time
    }
end
to_afr() click to toggle source

@return [String]

Report serialized in the Arachni Framework Report format.
# File lib/arachni/report.rb, line 169
def to_afr
    afr = RPC::Serializer.dump( self )

    # Append metadata to the end of the dump.
    metadata = RPC::Serializer.dump( summary )
    afr << [metadata, metadata.size].pack( 'a*N' )

    afr
end
to_h() click to toggle source

@return [Hash]

Hash representation of `self`.
# File lib/arachni/report.rb, line 181
def to_h
    h = {
        version:         @version,
        seed:            @seed,
        options:         Arachni::Options.hash_to_rpc_data( @options ),
        sitemap:         @sitemap,
        start_datetime:  @start_datetime.to_s,
        finish_datetime: @finish_datetime.to_s,
        delta_time:      delta_time,
        issues:          issues.map(&:to_h),
        plugins:         @plugins.dup
    }

    h[:plugins].each do |plugin, data|
        next if !data[:options]
        h[:plugins][plugin] = h[:plugins][plugin].dup
        h[:plugins][plugin][:options] = h[:plugins][plugin][:options].dup
        h[:plugins][plugin][:options] = data[:options].map(&:to_h)
    end

    h#.recode
end
Also aliased as: to_hash
to_hash()
Alias for: to_h
to_rpc_data() click to toggle source

@return [Hash]

Data representing this instance that are suitable the RPC transmission.
# File lib/arachni/report.rb, line 238
def to_rpc_data
    data = {}
    instance_variables.each do |ivar|
        data[ivar.to_s.gsub('@','')] = instance_variable_get( ivar )
    end

    data['options'] = Arachni::Options.hash_to_rpc_data( data['options'] )

    data['plugins'].each do |plugin, d|
        next if !d[:options]

        data['plugins'] = data['plugins'].dup
        data['plugins'][plugin] = data['plugins'][plugin].dup
        data['plugins'][plugin][:options] = data['plugins'][plugin][:options].dup
        data['plugins'][plugin][:options] = d[:options].map(&:to_rpc_data)
    end

    data['issues']          = data['issues'].values.map(&:to_rpc_data)
    data['start_datetime']  = data['start_datetime'].to_s
    data['finish_datetime'] = data['finish_datetime'].to_s
    data
end
url() click to toggle source
# File lib/arachni/report.rb, line 59
def url
    @options[:url]
end

Private Instance Methods

prepare_options( options ) click to toggle source

Prepares the hash to be stored in {Report#options}.

The value of the ‘options’ key of the hash that initializes AuditObjects needs some more processing before being saved in {Report#options}.

@param [Hash] options @return [Hash]

# File lib/arachni/report.rb, line 305
def prepare_options( options )
    Arachni::Options.rpc_data_to_hash( options.to_rpc_data_or_self )
end