Class: Fingerprinter::Technologies

Inherits:
Object
  • Object
show all
Defined in:
lib/fingerprinter.rb,
lib/fingerprinter/core/detector.rb

Overview

Technologies : Groups the different detection methods

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ Technologies

Returns a new instance of Technologies.



28
29
30
31
# File 'lib/fingerprinter.rb', line 28

def initialize(options = {})
  ScanOptions.build(options)
  @results ||= Concurrent::Hash.new
end

Instance Attribute Details

#http_clientObject (readonly)

Returns the value of attribute http_client.



26
27
28
# File 'lib/fingerprinter.rb', line 26

def http_client
  @http_client
end

#resultsObject

Returns the value of attribute results.



25
26
27
# File 'lib/fingerprinter.rb', line 25

def results
  @results
end

Class Method Details

.kbObject



33
34
35
36
37
# File 'lib/fingerprinter.rb', line 33

def self.kb
  @kb ||= {
    inspected: Concurrent::Array.new
  }
end

.meta_detection(doc, regexes, type = 'generator') ⇒ Object



32
33
34
35
36
37
38
39
# File 'lib/fingerprinter/core/detector.rb', line 32

def self.meta_detection(doc, regexes, type = 'generator')
  nodes = doc.xpath("//meta[@name='#{type}']/@content")
  nodes&.each do |node|
    return true if regexes.any? { |regex| node.value.match?(regex) }
  end

  false
end

.response_headers_check(response, regexes) ⇒ Object



7
8
9
10
11
12
13
14
15
16
17
18
19
20
# File 'lib/fingerprinter/core/detector.rb', line 7

def self.response_headers_check(response, regexes)
  response.headers&.each do |header, value|
    regex = regexes[header.downcase]
    next unless regex

    if value.is_a?(Array)
      return true if value.any? { |v| regex.match?(v) }
    elsif regex.match?(value)
      return true
    end
  end

  false
end

.title_detection(doc, title) ⇒ Object



41
42
43
# File 'lib/fingerprinter/core/detector.rb', line 41

def self.title_detection(doc, title)
  doc.title&.downcase == title.downcase
end

.whole_body_check(response, regexes) ⇒ Object



22
23
24
25
26
27
28
29
30
# File 'lib/fingerprinter/core/detector.rb', line 22

def self.whole_body_check(response, regexes)
  return false if response.body.nil?

  regexes.each do |regex|
    return true if response.body.match?(regex)
  end

  false
end

Instance Method Details

#run(urls) ⇒ Object



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/fingerprinter.rb', line 39

def run(urls)
  pool = Concurrent::FixedThreadPool.new(ScanOptions.http_concurrency)
  urls.each do |url|
    next if EXCLUSIONS.any? { |exclusion| url.match?(exclusion) }

    pool.post do
      response = get_response(url)
      next unless response
      next if wildcard?(response)

      url = effective_url(response, url)

      responses = response.redirections
      responses << response

      responses.each do |response|
        doc = Utilities::Parser.doc(response.body)

        results[url] = Concurrent::Array.new
        data = { response:, doc:, url: }
        Technologies.subclasses.each { |technology| results[url] << technology.run(data) }
      end
    end
  end

  pool.shutdown
  pool.wait_for_termination

  results.transform_values! { |v| v.compact.uniq }
  results
end