class Nexpose::Node

This class represents each of the /NexposeReport/nodes/node elements in the Nexpose Full XML document.

It provides a convenient way to access the information scattered all over the XML in attributes and nested tags.

Instead of providing separate methods for each supported property we rely on Ruby's method_missing to do most of the work.

Public Class Methods

new(xml_node) click to toggle source

Accepts an XML node from Nokogiri::XML.

# File lib/nexpose/node.rb, line 12
def initialize(xml_node)
  @xml = xml_node
end

Public Instance Methods

endpoints() click to toggle source

Each of the endpoints associated with this node. Returns an array of Nexpose::Endpoint objects

# File lib/nexpose/node.rb, line 42
def endpoints
  @xml.xpath('./endpoints/endpoint').collect { |xml_endpoint| Endpoint.new(xml_endpoint) }
end
method_missing(method, *args) click to toggle source

This method is invoked by Ruby when a method that is not defined in this instance is called.

In our case we inspect the @method@ parameter and try to find the attribute, simple descendent or collection that it maps to in the XML tree.

Calls superclass method
# File lib/nexpose/node.rb, line 60
def method_missing(method, *args)

  # We could remove this check and return nil for any non-recognized tag.
  # The problem would be that it would make tricky to debug problems with
  # typos. For instance: <>.potr would return nil instead of raising an
  # exception
  unless supported_tags.include?(method)
    super
    return
  end

  # First we try the attributes. In Ruby we use snake_case, but in XML
  # hyphenated-case is used for some attributes
  translations_table = {
    device_id: 'device-id',
    hardware_address: 'hardware-address',
    risk_score: 'risk-score',
    site_name: 'site-name'
  }

  method_name = translations_table.fetch(method, method.to_s)
  return @xml.attributes[method_name].value if @xml.attributes.key?(method_name)

  # Then we try simple children tags: description, solution

  # Finally the enumerations: names
  if method_name == 'names'
    @xml.xpath("./names/name").collect(&:text)

  elsif ['fingerprints', 'software'].include?(method_name)

    xpath_selector = {
      'fingerprints' => './fingerprints/os',
      'software' => './software/fingerprint'
    }[method_name]

    @xml.xpath(xpath_selector).collect do |xml_os|
      Hash[
        xml_os.attributes.collect do |name, xml_attribute|
          next if name == 'arch'
          [name.sub(/-/,'_').to_sym, xml_attribute.value]
        end
      ]
    end
  else
    # nothing found, the tag is valid but not present in this ReportItem
    return nil
  end
end
respond_to?(method, include_private=false) click to toggle source

This allows external callers (and specs) to check for implemented properties

Calls superclass method
# File lib/nexpose/node.rb, line 49
def respond_to?(method, include_private=false)
  return true if supported_tags.include?(method.to_sym)
  super
end
supported_tags() click to toggle source

List of supported tags. They can be attributes, simple descendans or collections (e.g. <references/>, <tags/>)

# File lib/nexpose/node.rb, line 18
def supported_tags
  [
    # attributes
    :address, :device_id, :hardware_address, :risk_score, :site_name, :status,

    # simple tags

    # multiple tags
    :fingerprints, :names,

    # compounded tags
    :endpoints, :software, :tests
  ]
end
tests(*args) click to toggle source

Convert each ./test/test entry into a simple hash

# File lib/nexpose/node.rb, line 34
def tests(*args)
  @xml.xpath('./tests/test').collect do |xml_test|
    Nexpose::Test.new(xml_test)
  end
end