Class: Arachni::Data::Issues

Inherits:
Object
  • Object
show all
Includes:
Support::Mixins::Observable
Defined in:
lib/arachni/data/issues.rb

Overview

Stores and provides access to all logged Issues.

Author:

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Support::Mixins::Observable

included

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?, #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

Constructor Details

#initializeIssues

Returns a new instance of Issues.



34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/arachni/data/issues.rb', line 34

def initialize
    super

    # Stores all issues with Issue#digest as the key as a way to deduplicate
    # and group variations.
    @collection = {}

    # We also use this Set for deduplication in case #do_not_store has been
    # called.
    @digests = Set.new

    store
end

Instance Attribute Details

#collectionHash{Integer=>Issue} (readonly)

Returns Issues by their Issue#digest.

Returns:



28
29
30
# File 'lib/arachni/data/issues.rb', line 28

def collection
  @collection
end

#digestsSet<Integer> (readonly)

Returns Issue#digests.

Returns:



32
33
34
# File 'lib/arachni/data/issues.rb', line 32

def digests
  @digests
end

Class Method Details

.load(directory) ⇒ Object



197
198
199
200
201
202
203
204
205
206
207
208
# File 'lib/arachni/data/issues.rb', line 197

def self.load( directory )
    issues = new

    Dir["#{directory}/issue_*"].each do |issue_file|
        issue = Marshal.load( IO.binread( issue_file ) )
        issues.collection[issue.digest] = issue
    end

    issues.digests.merge Marshal.load( IO.binread( "#{directory}/digests" ) )

    issues
end

Instance Method Details

#<<(issue) ⇒ Issues

Note:

Will deduplicate and group issues as variations.

Returns ‘self`.

Parameters:

  • issue (Issue)

    Issue to push to the collection.

Returns:



133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
# File 'lib/arachni/data/issues.rb', line 133

def <<( issue )
    notify_on_new_pre_deduplication( issue )

    # Only allow passive issues to have variations.
    return self if include?( issue ) && issue.active?

    @digests << issue.digest

    synchronize do
        notify_on_new( issue )

        if store?
            id = issue.digest
            @collection[id] ||= issue.with_variations
            @collection[id].variations << issue.as_variation
        end
    end

    self
end

#==(other) ⇒ Object



210
211
212
# File 'lib/arachni/data/issues.rb', line 210

def ==( other )
    hash == other.hash
end

#[](digest) ⇒ Issue

Parameters:

Returns:



157
158
159
# File 'lib/arachni/data/issues.rb', line 157

def []( digest )
    @collection[digest]
end

#allArray<Issue>

Returns All logged issues grouped as variations.

Returns:

  • (Array<Issue>)

    All logged issues grouped as variations.



96
97
98
# File 'lib/arachni/data/issues.rb', line 96

def all
    @collection.values
end

#any?Boolean

Returns:

  • (Boolean)


175
176
177
# File 'lib/arachni/data/issues.rb', line 175

def any?
    @collection.any?
end

#clearObject



218
219
220
221
222
# File 'lib/arachni/data/issues.rb', line 218

def clear
    @digests.clear
    @collection.clear
    clear_observers
end

#do_not_storeObject

Disables issue storage via #<<.

See Also:



89
90
91
92
# File 'lib/arachni/data/issues.rb', line 89

def do_not_store
    @store = false
    self
end

#dump(directory) ⇒ Object



187
188
189
190
191
192
193
194
195
# File 'lib/arachni/data/issues.rb', line 187

def dump( directory )
    FileUtils.mkdir_p( directory )

    @collection.each do |digest, issue|
        IO.binwrite( "#{directory}/issue_#{digest}", Marshal.dump( issue ) )
    end

    IO.binwrite( "#{directory}/digests", Marshal.dump( digests ) )
end

#each(&block) ⇒ Object



113
114
115
# File 'lib/arachni/data/issues.rb', line 113

def each( &block )
    all.each( &block )
end

#empty?Boolean

Returns:

  • (Boolean)


179
180
181
# File 'lib/arachni/data/issues.rb', line 179

def empty?
    !any?
end

#firstObject



167
168
169
# File 'lib/arachni/data/issues.rb', line 167

def first
    @collection.values.first
end

#flattenArray<Issue>

Returns All logged issues as solo objects, without variations.

Returns:

  • (Array<Issue>)

    All logged issues as solo objects, without variations.



109
110
111
# File 'lib/arachni/data/issues.rb', line 109

def flatten
    all.map { |issue| issue.variations.map { |v| v.to_solo issue } }.flatten
end

#hashObject



214
215
216
# File 'lib/arachni/data/issues.rb', line 214

def hash
    @digests.hash
end

#include?(issue) ⇒ Bool

Returns ‘true` if `issue` is.

Returns:

  • (Bool)

    ‘true` if `issue` is



123
124
125
# File 'lib/arachni/data/issues.rb', line 123

def include?( issue )
    @digests.include? issue.digest
end

#lastObject



171
172
173
# File 'lib/arachni/data/issues.rb', line 171

def last
    @collection.values.last
end

#map(&block) ⇒ Object



117
118
119
# File 'lib/arachni/data/issues.rb', line 117

def map( &block )
    all.map( &block )
end

#on_new_pre_deduplication(&block) ⇒ Object

Parameters:

  • block (Block)

    Block to be passed each issue passed to #<<.



23
# File 'lib/arachni/data/issues.rb', line 23

advertise :on_new_pre_deduplication

#sizeObject



183
184
185
# File 'lib/arachni/data/issues.rb', line 183

def size
    @collection.size
end

#sortArray<Issue>

Returns Sorted array of Issues.

Returns:



163
164
165
# File 'lib/arachni/data/issues.rb', line 163

def sort
    all.sort_by(&:severity).reverse
end

#statisticsObject



48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/arachni/data/issues.rb', line 48

def statistics
    by_severity = Hash.new(0)
    each { |issue| by_severity[issue.severity.to_sym] += 1 }

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

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

    {
        total:       size,
        by_severity: by_severity,
        by_type:     by_type,
        by_check:    by_check
    }
end

#storeObject

Enables issue storage via #<<.

See Also:



80
81
82
83
# File 'lib/arachni/data/issues.rb', line 80

def store
    @store = true
    self
end

#store?Bool

Note:

Defaults to ‘true`.

Returns ‘true` if #<< is configured to store issues, `false` otherwise.

Returns:

  • (Bool)

    ‘true` if #<< is configured to store issues, `false` otherwise.

See Also:



72
73
74
# File 'lib/arachni/data/issues.rb', line 72

def store?
    @store
end

#summaryArray<Issue>

Returns First variation of all issues (as solo issues) sorted by severity.

Returns:

  • (Array<Issue>)

    First variation of all issues (as solo issues) sorted by severity.



102
103
104
105
# File 'lib/arachni/data/issues.rb', line 102

def summary
    all.map { |issue| issue.variations.first.to_solo issue }.flatten.
        sort_by(&:severity).reverse
end