Skip to content

Commit

Permalink
Merge branch 'master' into feature/MSP-10028/mdm-host-os-search
Browse files Browse the repository at this point in the history
MSP-10028

Conflicts:
	config/locales/en.yml
	spec/app/models/metasploit_data_models/search/visitor/relation_spec.rb
  • Loading branch information
limhoff-r7 committed Jun 27, 2014
2 parents ac5b394 + 55bc810 commit 917939e
Show file tree
Hide file tree
Showing 20 changed files with 1,188 additions and 156 deletions.
13 changes: 12 additions & 1 deletion app/models/mdm/service.rb
Expand Up @@ -176,13 +176,25 @@ class Mdm::Service < ActiveRecord::Base
])
}

#
#
# Search
#
#

#
# Search Attributes
#

search_attribute :name,
type: :string

#
# Search Withs
#

search_with MetasploitDataModels::Search::Operator::Port::List

#
# Validations
#
Expand All @@ -204,4 +216,3 @@ def normalize_host_os

Metasploit::Concern.run(self)
end

25 changes: 25 additions & 0 deletions app/models/metasploit_data_models/search/operation/port/number.rb
@@ -0,0 +1,25 @@
# Search operation on an attribute that holds a port number and is being searched with a single Integer port number.
class MetasploitDataModels::Search::Operation::Port::Number < Metasploit::Model::Search::Operation::Integer
#
# CONSTANTS
#

# The number of bits in a port number
BITS = 16
# The maximum port number
MAXIMUM = (1 << BITS) - 1
# The minimum port number
MINIMUM = 0

# The range of valid port numbers from {MINIMUM} to {MAXIMUM}, inclusive.
RANGE = (MINIMUM..MAXIMUM)

#
# Validations
#

validates :value,
inclusion: {
in: RANGE
}
end
79 changes: 79 additions & 0 deletions app/models/metasploit_data_models/search/operation/port/range.rb
@@ -0,0 +1,79 @@
# Search operation on an attribute that holds a port number and is being search with a range of port numbers. The
# range is specified as `<min>-<max>` with `<min>` being less than `<max>` and both being within
# {MetasploitDataModels::Search::Operation::Port::Range the valid port range}.
class MetasploitDataModels::Search::Operation::Port::Range < MetasploitDataModels::Search::Operation::Range
#
# Validations
#

validate :ports

#
# Instance Methods
#

# Sets `#value` to a range of ports.
#
# @param formatted_value [#to_s] '\d+-\d+'
def value=(formatted_value)
super(formatted_value)

# could not be a `Range` if super conversion failed
# setters return the argument, not the return value from the method, so access `#value` directly
if value.is_a? Range
begin
# use Integer() instead of String#to_i as String#to_i will ignore trailing letters (i.e. '1two' -> 1) and turn all
# string without an integer in it to 0.
integer_begin = Integer(value.begin.to_s)
integer_end = Integer(value.end.to_s)
rescue ArgumentError
# setter returned is ignored in MRI, but do it anyway for other implementation
@value
else
@value = Range.new(integer_begin, integer_end)
end
else
# setter returned is ignored in MRI, but do it anyway for other implementation
# return unconvertible value from `super`
@value
end
end

private

# @note `#value` should be check to be a `Range` before calling {#port}.
#
# Validate that either `Range#begin` or `Range#end` is a valid port number in `#value`
#
# @param extreme [:begin, :end] Which extreme of the `Range` in `value` to validate.
# @return [void]
def port(extreme)
extreme_value = value.send(extreme)

if extreme_value.is_a? Integer
unless MetasploitDataModels::Search::Operation::Port::Number::RANGE.cover?(extreme_value)
errors.add(
:value,
:port_range_extreme_inclusion,
extreme: extreme,
extreme_value: extreme_value,
maximum: MetasploitDataModels::Search::Operation::Port::Number::MAXIMUM,
minimum: MetasploitDataModels::Search::Operation::Port::Number::MINIMUM
)
end
else
errors.add(:value, :port_range_extreme_not_an_integer, extreme: extreme, extreme_value: extreme_value)
end
end

# Validates that the `Range#begin` and `Range#end` of `#value` are valid port numbers.
#
# @return [void]
def ports
if value.is_a? Range
[:begin, :end].each do |extreme|
port(extreme)
end
end
end
end
56 changes: 56 additions & 0 deletions app/models/metasploit_data_models/search/operation/range.rb
@@ -0,0 +1,56 @@
# Search operation on a `Range`.
class MetasploitDataModels::Search::Operation::Range < Metasploit::Model::Search::Operation::Base
#
# CONSTANTS
#

# Separates beginning from end of the range.
SEPARATOR = '-'

#
# Validation
#

validate :ordered
validate :range

#
# Instance Methods
#

# Sets `#value` to a `Range` composed by separating `formatted_value` by `-`.
#
# @param formatted_value [#to_s]
# @return [Range<String>]
def value=(formatted_value)
range_arguments = formatted_value.to_s.split(SEPARATOR, 2)

begin
@value = Range.new(*range_arguments)
rescue ArgumentError
@value = formatted_value
end

@value
end

private

# Validates that `#value` is a `Range` with `Range#begin` less than or equal to `Range#begin`
#
# @return [void]
def ordered
if value.is_a?(Range) && value.begin > value.end
errors.add(:value, :order, begin: value.begin.inspect, end: value.end.inspect)
end
end

# Validates that `#value` is a `Range`
#
# @return [void]
def range
unless value.is_a? Range
errors.add(:value, :range)
end
end
end
67 changes: 67 additions & 0 deletions app/models/metasploit_data_models/search/operator/port/list.rb
@@ -0,0 +1,67 @@
# Searches for a network port attribute. Ports can be given as a single number or range of numbers and either or both
# forms can be combined into a comma separated list. Individual port numbers are validated to be greater than 0 and
class MetasploitDataModels::Search::Operator::Port::List < Metasploit::Model::Search::Operator::Union
#
# CONSTANTS
#

# Separates port number and/or port ranges
SEPARATOR = ','

#
# Attributes
#

# @!attribute [rw] attribute
# Attribute holding port number.
#
# @return [Symbol] `:port`
attr_writer :attribute

#
# Class Methods
#

# @note Can't be called `name` because it would alias `Class#name`
#
# Name of this operator.
#
# @return [String] `'port_list'`
def self.operator_name
'port_list'
end

#
# Instance Methods
#

# Defaults to `:port`.
#
# @return [Symbol]
def attribute
@attribute ||= :port
end

# Turns `{#attribute}:<number>,<range>` into the union of port <number> and port <range> searches.
#
# @param formatted_value [String] comma separated list of port numbers and ranges.
# @return [Array<Metasploit::Model::Search::Operation::Base]
def children(formatted_value)
separated_formatted_values = formatted_value.split(SEPARATOR)

separated_formatted_values.collect { |separated_formatted_value|
operation_class = MetasploitDataModels::Search::Operation::Port::Number

if separated_formatted_value.include? MetasploitDataModels::Search::Operation::Range::SEPARATOR
operation_class = MetasploitDataModels::Search::Operation::Port::Range
end

operation_class.new(
value: separated_formatted_value,
operator: self
)
}
end

alias_method :name, :attribute
end
Expand Up @@ -6,7 +6,8 @@ class MetasploitDataModels::Search::Visitor::Attribute
visit operator.attribute_operator
end

visit 'Metasploit::Model::Search::Operator::Attribute' do |operator|
visit 'Metasploit::Model::Search::Operator::Attribute',
'MetasploitDataModels::Search::Operator::Port::List' do |operator|
table = operator.klass.arel_table
table[operator.attribute]
end
Expand Down
3 changes: 2 additions & 1 deletion app/models/metasploit_data_models/search/visitor/includes.rb
Expand Up @@ -22,7 +22,8 @@ class MetasploitDataModels::Search::Visitor::Includes
[operator.association]
end

visit 'Metasploit::Model::Search::Operator::Attribute' do |_operator|
visit 'Metasploit::Model::Search::Operator::Attribute',
'MetasploitDataModels::Search::Operator::Port::List' do |_operator|
[]
end

Expand Down
3 changes: 2 additions & 1 deletion app/models/metasploit_data_models/search/visitor/joins.rb
Expand Up @@ -41,7 +41,8 @@ class MetasploitDataModels::Search::Visitor::Joins
[operator.association]
end

visit 'Metasploit::Model::Search::Operator::Attribute' do |_|
visit 'Metasploit::Model::Search::Operator::Attribute',
'MetasploitDataModels::Search::Operator::Port::List' do |_|
[]
end

Expand Down
8 changes: 7 additions & 1 deletion app/models/metasploit_data_models/search/visitor/where.rb
Expand Up @@ -43,7 +43,13 @@ class MetasploitDataModels::Search::Visitor::Where
match_value = "%#{operation.value}%"

attribute.matches(match_value)
end
end

visit 'MetasploitDataModels::Search::Operation::Port::Range' do |range_operation|
attribute = attribute_visitor.visit range_operation.operator

attribute.in(range_operation.value)
end

#
# Methods
Expand Down
12 changes: 11 additions & 1 deletion config/locales/en.yml
Expand Up @@ -10,4 +10,14 @@ en:
metasploit_data_models/search/operator/multitext:
attributes:
operator_names:
too_short: "is too short (minimum is %{count} operator names)"
too_short: "is too short (minimum is %{count} operator names)"
metasploit_data_models/search/operation/port/range:
attributes:
value:
port_range_extreme_inclusion: "has extreme (%{extreme}) value (%{extreme_value}) outside range (%{minimum}-%{maximum})."
port_range_extreme_not_an_integer: "has extreme (%{extreme}) value (%{extreme_value}) that is not an integer."
metasploit_data_models/search/operation/range:
attributes:
value:
order: "is not in order: begin (%{begin} is greater than end (%{end})."
range: "is not a range"
@@ -0,0 +1,41 @@
require 'spec_helper'

describe MetasploitDataModels::Search::Operation::Port::Number do
context 'CONSTANTS' do
context 'BITS' do
subject(:bits) {
described_class::BITS
}

it { should == 16 }
end

context 'MAXIMUM' do
subject(:maxium) {
described_class::MAXIMUM
}

it { should == 65535 }
end

context 'MINIMUM' do
subject(:minimum) {
described_class::MINIMUM
}

it { should == 0 }
end

context 'RANGE' do
subject(:range) {
described_class::RANGE
}

it { should == (0..65535) }
end
end

context 'validations' do
it { should ensure_inclusion_of(:value).in_range(described_class::RANGE) }
end
end

0 comments on commit 917939e

Please sign in to comment.