Merge branch 'master' of git://github.com/rapid7/metasploit-framework
commit
3273d93960
|
@ -6,6 +6,8 @@
|
||||||
.yardoc
|
.yardoc
|
||||||
# Mac OS X files
|
# Mac OS X files
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
# simplecov coverage data
|
||||||
|
coverage
|
||||||
data/meterpreter/ext_server_pivot.dll
|
data/meterpreter/ext_server_pivot.dll
|
||||||
data/meterpreter/ext_server_pivot.x64.dll
|
data/meterpreter/ext_server_pivot.x64.dll
|
||||||
doc
|
doc
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
language: ruby
|
||||||
|
rvm:
|
||||||
|
# - '1.8.7'
|
||||||
|
- '1.9.3'
|
3
Gemfile
3
Gemfile
|
@ -24,4 +24,7 @@ end
|
||||||
group :test do
|
group :test do
|
||||||
# testing framework
|
# testing framework
|
||||||
gem 'rspec'
|
gem 'rspec'
|
||||||
|
# code coverage for tests
|
||||||
|
# any version newer than 0.5.4 gives an Encoding error when trying to read the source files.
|
||||||
|
gem 'simplecov', '0.5.4', :require => false
|
||||||
end
|
end
|
||||||
|
|
|
@ -45,6 +45,10 @@ GEM
|
||||||
rspec-expectations (2.11.3)
|
rspec-expectations (2.11.3)
|
||||||
diff-lcs (~> 1.1.3)
|
diff-lcs (~> 1.1.3)
|
||||||
rspec-mocks (2.11.3)
|
rspec-mocks (2.11.3)
|
||||||
|
simplecov (0.5.4)
|
||||||
|
multi_json (~> 1.0.3)
|
||||||
|
simplecov-html (~> 0.5.3)
|
||||||
|
simplecov-html (0.5.3)
|
||||||
slop (3.3.3)
|
slop (3.3.3)
|
||||||
tzinfo (0.3.33)
|
tzinfo (0.3.33)
|
||||||
yard (0.8.2.1)
|
yard (0.8.2.1)
|
||||||
|
@ -60,4 +64,5 @@ DEPENDENCIES
|
||||||
rake
|
rake
|
||||||
redcarpet
|
redcarpet
|
||||||
rspec
|
rspec
|
||||||
|
simplecov (= 0.5.4)
|
||||||
yard
|
yard
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
|
|
||||||
Metasploit [![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/rapid7/metasploit-framework)
|
Metasploit [![Build Status](https://travis-ci.org/rapid7/metasploit-framework.png)](https://travis-ci.org/rapid7/metasploit-framework) [![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/rapid7/metasploit-framework)
|
||||||
==
|
==
|
||||||
The Metasploit Framework is released under a BSD-style license. See
|
The Metasploit Framework is released under a BSD-style license. See
|
||||||
COPYING for more details.
|
COPYING for more details.
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
# Base error class for all error under {Msf::Modules}
|
||||||
|
class Msf::Modules::Error < StandardError
|
||||||
|
def initialize(attributes={})
|
||||||
|
@module_path = attributes[:module_path]
|
||||||
|
@module_reference_name = attributes[:module_reference_name]
|
||||||
|
|
||||||
|
message_parts = []
|
||||||
|
message_parts << "Failed to load module"
|
||||||
|
|
||||||
|
if module_reference_name or module_path
|
||||||
|
clause_parts = []
|
||||||
|
|
||||||
|
if module_reference_name
|
||||||
|
clause_parts << module_reference_name
|
||||||
|
end
|
||||||
|
|
||||||
|
if module_path
|
||||||
|
clause_parts << "from #{module_path}"
|
||||||
|
end
|
||||||
|
|
||||||
|
clause = clause_parts.join(' ')
|
||||||
|
message_parts << "(#{clause})"
|
||||||
|
end
|
||||||
|
|
||||||
|
causal_message = attributes[:causal_message]
|
||||||
|
|
||||||
|
if causal_message
|
||||||
|
message_parts << "due to #{causal_message}"
|
||||||
|
end
|
||||||
|
|
||||||
|
message = message_parts.join(' ')
|
||||||
|
|
||||||
|
super(message)
|
||||||
|
end
|
||||||
|
|
||||||
|
attr_reader :module_reference_name
|
||||||
|
attr_reader :module_path
|
||||||
|
end
|
|
@ -3,6 +3,7 @@
|
||||||
#
|
#
|
||||||
require 'msf/core/modules/loader'
|
require 'msf/core/modules/loader'
|
||||||
require 'msf/core/modules/namespace'
|
require 'msf/core/modules/namespace'
|
||||||
|
require 'msf/core/modules/metasploit_class_compatibility_error'
|
||||||
require 'msf/core/modules/version_compatibility_error'
|
require 'msf/core/modules/version_compatibility_error'
|
||||||
|
|
||||||
# Responsible for loading modules for {Msf::ModuleManager}.
|
# Responsible for loading modules for {Msf::ModuleManager}.
|
||||||
|
@ -117,12 +118,17 @@ class Msf::Modules::Loader::Base
|
||||||
|
|
||||||
metasploit_class = nil
|
metasploit_class = nil
|
||||||
|
|
||||||
|
module_content = read_module_content(parent_path, type, module_reference_name)
|
||||||
|
|
||||||
|
if module_content.empty?
|
||||||
|
# read_module_content is responsible for calling {#load_error}, so just return here.
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
loaded = namespace_module_transaction(type + "/" + module_reference_name, :reload => reload) { |namespace_module|
|
loaded = namespace_module_transaction(type + "/" + module_reference_name, :reload => reload) { |namespace_module|
|
||||||
# set the parent_path so that the module can be reloaded with #load_module
|
# set the parent_path so that the module can be reloaded with #load_module
|
||||||
namespace_module.parent_path = parent_path
|
namespace_module.parent_path = parent_path
|
||||||
|
|
||||||
module_content = read_module_content(parent_path, type, module_reference_name)
|
|
||||||
|
|
||||||
begin
|
begin
|
||||||
namespace_module.module_eval_with_lexical_scope(module_content, module_path)
|
namespace_module.module_eval_with_lexical_scope(module_content, module_path)
|
||||||
# handle interrupts as pass-throughs unlike other Exceptions so users can bail with Ctrl+C
|
# handle interrupts as pass-throughs unlike other Exceptions so users can bail with Ctrl+C
|
||||||
|
@ -133,45 +139,33 @@ class Msf::Modules::Loader::Base
|
||||||
begin
|
begin
|
||||||
namespace_module.version_compatible!(module_path, module_reference_name)
|
namespace_module.version_compatible!(module_path, module_reference_name)
|
||||||
rescue Msf::Modules::VersionCompatibilityError => version_compatibility_error
|
rescue Msf::Modules::VersionCompatibilityError => version_compatibility_error
|
||||||
error_message = "Failed to load module (#{module_path}) due to error and #{version_compatibility_error}"
|
load_error(module_path, version_compatibility_error)
|
||||||
else
|
else
|
||||||
error_message = "#{error.class} #{error}"
|
load_error(module_path, error)
|
||||||
end
|
end
|
||||||
|
|
||||||
# record the error message without the backtrace for the console
|
|
||||||
module_manager.module_load_error_by_path[module_path] = error_message
|
|
||||||
|
|
||||||
error_message_with_backtrace = "#{error_message}:\n#{error.backtrace.join("\n")}"
|
|
||||||
elog(error_message_with_backtrace)
|
|
||||||
|
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
begin
|
begin
|
||||||
namespace_module.version_compatible!(module_path, module_reference_name)
|
namespace_module.version_compatible!(module_path, module_reference_name)
|
||||||
rescue Msf::Modules::VersionCompatibilityError => version_compatibility_error
|
rescue Msf::Modules::VersionCompatibilityError => version_compatibility_error
|
||||||
error_message = version_compatibility_error.to_s
|
load_error(module_path, version_compatibility_error)
|
||||||
|
|
||||||
elog(error_message)
|
|
||||||
module_manager.module_load_error_by_path[module_path] = error_message
|
|
||||||
|
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
metasploit_class = namespace_module.metasploit_class
|
begin
|
||||||
|
metasploit_class = namespace_module.metasploit_class!(module_path, module_reference_name)
|
||||||
unless metasploit_class
|
rescue Msf::Modules::MetasploitClassCompatibilityError => error
|
||||||
error_message = "Missing Metasploit class constant"
|
load_error(module_path, error)
|
||||||
|
|
||||||
elog(error_message)
|
|
||||||
module_manager.module_load_error_by_path[module_path] = error_message
|
|
||||||
|
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
unless usable?(metasploit_class)
|
unless usable?(metasploit_class)
|
||||||
ilog(
|
ilog(
|
||||||
"Skipping module #{module_reference_name} under #{parent_path} because is_usable returned false.",
|
"Skipping module (#{module_reference_name} from #{module_path}) because is_usable returned false.",
|
||||||
'core',
|
'core',
|
||||||
LEV_1
|
LEV_1
|
||||||
)
|
)
|
||||||
|
@ -409,6 +403,29 @@ class Msf::Modules::Loader::Base
|
||||||
raise ::NotImplementedError
|
raise ::NotImplementedError
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Records the load error to {Msf::ModuleManager::Loading#module_load_error_by_path} and the log.
|
||||||
|
#
|
||||||
|
# @param [String] module_path Path to the module as returned by {#module_path}.
|
||||||
|
# @param [Exception, #class, #to_s, #backtrace] error the error that cause the module not to load.
|
||||||
|
# @return [void]
|
||||||
|
#
|
||||||
|
# @see #module_path
|
||||||
|
def load_error(module_path, error)
|
||||||
|
# module_load_error_by_path does not get the backtrace because the value is echoed to the msfconsole where
|
||||||
|
# backtraces should not appear.
|
||||||
|
module_manager.module_load_error_by_path[module_path] = "#{error.class} #{error}"
|
||||||
|
|
||||||
|
log_lines = []
|
||||||
|
log_lines << "#{module_path} failed to load due to the following error:"
|
||||||
|
log_lines << error.class.to_s
|
||||||
|
log_lines << error.to_s
|
||||||
|
log_lines << "Call stack:"
|
||||||
|
log_lines += error.backtrace
|
||||||
|
|
||||||
|
log_message = log_lines.join("\n")
|
||||||
|
elog(log_message)
|
||||||
|
end
|
||||||
|
|
||||||
# @return [Msf::ModuleManager] The module manager for which this loader is loading modules.
|
# @return [Msf::ModuleManager] The module manager for which this loader is loading modules.
|
||||||
attr_reader :module_manager
|
attr_reader :module_manager
|
||||||
|
|
||||||
|
|
|
@ -75,6 +75,7 @@ class Msf::Modules::Loader::Directory < Msf::Modules::Loader::Base
|
||||||
|
|
||||||
module_content = ''
|
module_content = ''
|
||||||
|
|
||||||
|
begin
|
||||||
# force to read in binary mode so Pro modules won't be truncated on Windows
|
# force to read in binary mode so Pro modules won't be truncated on Windows
|
||||||
File.open(full_path, 'rb') do |f|
|
File.open(full_path, 'rb') do |f|
|
||||||
# Pass the size of the file as it leads to faster reads due to fewer buffer resizes. Greatest effect on Windows.
|
# Pass the size of the file as it leads to faster reads due to fewer buffer resizes. Greatest effect on Windows.
|
||||||
|
@ -83,6 +84,9 @@ class Msf::Modules::Loader::Directory < Msf::Modules::Loader::Base
|
||||||
# @see https://github.com/ruby/ruby/blob/ruby_1_9_3/io.c#L2038
|
# @see https://github.com/ruby/ruby/blob/ruby_1_9_3/io.c#L2038
|
||||||
module_content = f.read(f.stat.size)
|
module_content = f.read(f.stat.size)
|
||||||
end
|
end
|
||||||
|
rescue Errno::ENOENT => error
|
||||||
|
load_error(full_path, error)
|
||||||
|
end
|
||||||
|
|
||||||
module_content
|
module_content
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
require 'msf/core/modules/error'
|
||||||
|
|
||||||
|
# Error raised by {Msf::Modules::Namespace#metasploit_class!} if it cannot the namespace_module does not have a constant
|
||||||
|
# with {Msf::Framework::Major} or lower as a number after 'Metasploit', which indicates a compatible Msf::Module.
|
||||||
|
class Msf::Modules::MetasploitClassCompatibilityError < Msf::Modules::Error
|
||||||
|
def initialize(attributes={})
|
||||||
|
super_attributes = {
|
||||||
|
:causal_message => 'Missing compatible Metasploit<major_version> class constant',
|
||||||
|
}.merge(attributes)
|
||||||
|
|
||||||
|
super(super_attributes)
|
||||||
|
end
|
||||||
|
end
|
|
@ -10,8 +10,6 @@ module Msf::Modules::Namespace
|
||||||
# @return [nil] if such as class is not defined.
|
# @return [nil] if such as class is not defined.
|
||||||
def metasploit_class
|
def metasploit_class
|
||||||
metasploit_class = nil
|
metasploit_class = nil
|
||||||
# don't search ancestors for the metasploit_class
|
|
||||||
#inherit = false
|
|
||||||
|
|
||||||
::Msf::Framework::Major.downto(1) do |major|
|
::Msf::Framework::Major.downto(1) do |major|
|
||||||
# Since we really only care about the deepest namespace, we don't
|
# Since we really only care about the deepest namespace, we don't
|
||||||
|
@ -29,6 +27,19 @@ module Msf::Modules::Namespace
|
||||||
metasploit_class
|
metasploit_class
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def metasploit_class!(module_path, module_reference_name)
|
||||||
|
metasploit_class = self.metasploit_class
|
||||||
|
|
||||||
|
unless metasploit_class
|
||||||
|
raise Msf::Modules::MetasploitClassCompatibilityError.new(
|
||||||
|
:module_path => module_path,
|
||||||
|
:module_reference_name => module_reference_name
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
metasploit_class
|
||||||
|
end
|
||||||
|
|
||||||
# Raises an error unless {Msf::Framework::VersionCore} and {Msf::Framework::VersionAPI} meet the minimum required
|
# Raises an error unless {Msf::Framework::VersionCore} and {Msf::Framework::VersionAPI} meet the minimum required
|
||||||
# versions defined in RequiredVersions in the module content.
|
# versions defined in RequiredVersions in the module content.
|
||||||
#
|
#
|
||||||
|
|
|
@ -1,20 +1,43 @@
|
||||||
|
require 'msf/core/modules/error'
|
||||||
|
|
||||||
# Error raised by {Msf::Modules::Namespace#version_compatible!} on {Msf::Modules::Loader::Base#create_namespace_module}
|
# Error raised by {Msf::Modules::Namespace#version_compatible!} on {Msf::Modules::Loader::Base#create_namespace_module}
|
||||||
# if the API or Core version does not meet the minimum requirements defined in the RequiredVersions constant in the
|
# if the API or Core version does not meet the minimum requirements defined in the RequiredVersions constant in the
|
||||||
# {Msf::Modules::Loader::Base#read_module_content module content}.
|
# {Msf::Modules::Loader::Base#read_module_content module content}.
|
||||||
class Msf::Modules::VersionCompatibilityError < StandardError
|
class Msf::Modules::VersionCompatibilityError < Msf::Modules::Error
|
||||||
# @param [Hash{Symbol => Float}] attributes
|
# @param [Hash{Symbol => Float}] attributes
|
||||||
# @option attributes [Float] :minimum_api_version The minimum {Msf::Framework::VersionAPI} as defined in
|
# @option attributes [Float] :minimum_api_version The minimum {Msf::Framework::VersionAPI} as defined in
|
||||||
# RequiredVersions.
|
# RequiredVersions.
|
||||||
# @option attributes [Float] :minimum_core_version The minimum {Msf::Framework::VersionCore} as defined in
|
# @option attributes [Float] :minimum_core_version The minimum {Msf::Framework::VersionCore} as defined in
|
||||||
# RequiredVersions.
|
# RequiredVersions.
|
||||||
def initialize(attributes={})
|
def initialize(attributes={})
|
||||||
@module_path = attributes[:module_path]
|
|
||||||
@module_reference_name = attributes[:module_reference_name]
|
|
||||||
@minimum_api_version = attributes[:minimum_api_version]
|
@minimum_api_version = attributes[:minimum_api_version]
|
||||||
@minimum_core_version = attributes[:minimum_core_version]
|
@minimum_core_version = attributes[:minimum_core_version]
|
||||||
|
|
||||||
super("Failed to reload module (#{module_reference_name} from #{module_path}) due to version check " \
|
message_parts = []
|
||||||
"(requires API:#{minimum_api_version} Core:#{minimum_core_version})")
|
message_parts << 'version check'
|
||||||
|
|
||||||
|
if minimum_api_version or minimum_core_version
|
||||||
|
clause_parts = []
|
||||||
|
|
||||||
|
if minimum_api_version
|
||||||
|
clause_parts << "API >= #{minimum_api_version}"
|
||||||
|
end
|
||||||
|
|
||||||
|
if minimum_core_version
|
||||||
|
clause_parts << "Core >= #{minimum_core_version}"
|
||||||
|
end
|
||||||
|
|
||||||
|
clause = clause_parts.join(' and ')
|
||||||
|
message_parts << "(requires #{clause})"
|
||||||
|
end
|
||||||
|
|
||||||
|
causal_message = message_parts.join(' ')
|
||||||
|
|
||||||
|
super_attributes = {
|
||||||
|
:causal_message => causal_message
|
||||||
|
}.merge(attributes)
|
||||||
|
|
||||||
|
super(super_attributes)
|
||||||
end
|
end
|
||||||
|
|
||||||
# @return [Float] The minimum value of {Msf::Framework::VersionAPI} for the module to be compatible.
|
# @return [Float] The minimum value of {Msf::Framework::VersionAPI} for the module to be compatible.
|
||||||
|
|
|
@ -0,0 +1,101 @@
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
describe Msf::Modules::Error do
|
||||||
|
context 'instance methods' do
|
||||||
|
context '#initialize' do
|
||||||
|
include_context 'Msf::Modules::Error attributes'
|
||||||
|
|
||||||
|
context 'with :causal_message' do
|
||||||
|
subject do
|
||||||
|
described_class.new(:causal_message => causal_message)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should include causal_message in error' do
|
||||||
|
subject.to_s.should == "Failed to load module due to #{causal_message}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with :causal_message and :module_path' do
|
||||||
|
subject do
|
||||||
|
described_class.new(
|
||||||
|
:causal_message => causal_message,
|
||||||
|
:module_path => module_path
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should include causal_message and module_path in error' do
|
||||||
|
subject.to_s.should == "Failed to load module (from #{module_path}) due to #{causal_message}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with :causal_message and :module_reference_name' do
|
||||||
|
subject do
|
||||||
|
described_class.new(
|
||||||
|
:causal_message => causal_message,
|
||||||
|
:module_reference_name => module_reference_name
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should include causal_message and module_reference_name in error' do
|
||||||
|
subject.to_s.should == "Failed to load module (#{module_reference_name}) due to #{causal_message}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with :causal_message, :module_path, and :module_reference_nam' do
|
||||||
|
subject do
|
||||||
|
described_class.new(
|
||||||
|
:causal_message => causal_message,
|
||||||
|
:module_path => module_path,
|
||||||
|
:module_reference_name => module_reference_name
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should include causal_message, module_path, and module_reference_name in error' do
|
||||||
|
subject.to_s.should == "Failed to load module (#{module_reference_name} from #{module_path}) due to #{causal_message}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with :module_path' do
|
||||||
|
subject do
|
||||||
|
described_class.new(:module_path => module_path)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should use :module_path for module_path' do
|
||||||
|
subject.module_path.should == module_path
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should include module_path in error' do
|
||||||
|
subject.to_s.should == "Failed to load module (from #{module_path})"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with :module_path and :module_reference_name' do
|
||||||
|
subject do
|
||||||
|
described_class.new(
|
||||||
|
:module_path => module_path,
|
||||||
|
:module_reference_name => module_reference_name
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should include module_path and module_reference_name in error' do
|
||||||
|
subject.to_s.should == "Failed to load module (#{module_reference_name} from #{module_path})"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with :module_reference_name' do
|
||||||
|
subject do
|
||||||
|
described_class.new(:module_reference_name => module_reference_name)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should use :module_reference_name for module_reference_name' do
|
||||||
|
subject.module_reference_name.should == module_reference_name
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should include module_reference_name in error' do
|
||||||
|
subject.to_s.should == "Failed to load module (#{module_reference_name})"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -3,6 +3,8 @@ require 'spec_helper'
|
||||||
require 'msf/core'
|
require 'msf/core'
|
||||||
|
|
||||||
describe Msf::Modules::Loader::Base do
|
describe Msf::Modules::Loader::Base do
|
||||||
|
include_context 'Msf::Modules::Loader::Base'
|
||||||
|
|
||||||
let(:described_class_pathname) do
|
let(:described_class_pathname) do
|
||||||
root_pathname.join('lib', 'msf', 'core', 'modules', 'loader', 'base.rb')
|
root_pathname.join('lib', 'msf', 'core', 'modules', 'loader', 'base.rb')
|
||||||
end
|
end
|
||||||
|
@ -37,18 +39,6 @@ describe Msf::Modules::Loader::Base do
|
||||||
'rspec/mock'
|
'rspec/mock'
|
||||||
end
|
end
|
||||||
|
|
||||||
let(:parent_path) do
|
|
||||||
parent_pathname.to_s
|
|
||||||
end
|
|
||||||
|
|
||||||
let(:parent_pathname) do
|
|
||||||
root_pathname.join('modules')
|
|
||||||
end
|
|
||||||
|
|
||||||
let(:root_pathname) do
|
|
||||||
Pathname.new(Msf::Config.install_root)
|
|
||||||
end
|
|
||||||
|
|
||||||
let(:type) do
|
let(:type) do
|
||||||
Msf::MODULE_AUX
|
Msf::MODULE_AUX
|
||||||
end
|
end
|
||||||
|
@ -230,7 +220,7 @@ describe Msf::Modules::Loader::Base do
|
||||||
|
|
||||||
context 'instance methods' do
|
context 'instance methods' do
|
||||||
let(:module_manager) do
|
let(:module_manager) do
|
||||||
mock('Module Manager')
|
mock('Module Manager', :module_load_error_by_path => {})
|
||||||
end
|
end
|
||||||
|
|
||||||
subject do
|
subject do
|
||||||
|
@ -323,13 +313,14 @@ describe Msf::Modules::Loader::Base do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should call #namespace_module_transaction with the module full name and :reload => true' do
|
it 'should call #namespace_module_transaction with the module full name and :reload => true' do
|
||||||
|
subject.stub(:read_module_content => module_content)
|
||||||
|
|
||||||
subject.should_receive(:namespace_module_transaction).with(module_full_name, hash_including(:reload => true))
|
subject.should_receive(:namespace_module_transaction).with(module_full_name, hash_including(:reload => true))
|
||||||
|
|
||||||
subject.load_module(parent_path, type, module_reference_name)
|
subject.load_module(parent_path, type, module_reference_name)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should set the parent_path on the namespace_module to match the parent_path passed to #load_module' do
|
it 'should set the parent_path on the namespace_module to match the parent_path passed to #load_module' do
|
||||||
module_manager.stub(:module_load_error_by_path => {})
|
|
||||||
module_manager.stub(:on_module_load)
|
module_manager.stub(:on_module_load)
|
||||||
|
|
||||||
subject.stub(:read_module_content => module_content)
|
subject.stub(:read_module_content => module_content)
|
||||||
|
@ -339,7 +330,6 @@ describe Msf::Modules::Loader::Base do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should call #read_module_content to get the module content so that #read_module_content can be overridden to change loading behavior' do
|
it 'should call #read_module_content to get the module content so that #read_module_content can be overridden to change loading behavior' do
|
||||||
module_manager.stub(:module_load_error_by_path => {})
|
|
||||||
module_manager.stub(:on_module_load)
|
module_manager.stub(:on_module_load)
|
||||||
|
|
||||||
subject.should_receive(:read_module_content).with(parent_path, type, module_reference_name).and_return(module_content)
|
subject.should_receive(:read_module_content).with(parent_path, type, module_reference_name).and_return(module_content)
|
||||||
|
@ -348,7 +338,6 @@ describe Msf::Modules::Loader::Base do
|
||||||
|
|
||||||
it 'should call namespace_module.module_eval_with_lexical_scope with the module_path' do
|
it 'should call namespace_module.module_eval_with_lexical_scope with the module_path' do
|
||||||
subject.stub(:read_module_content => malformed_module_content)
|
subject.stub(:read_module_content => malformed_module_content)
|
||||||
module_manager.stub(:module_load_error_by_path => {})
|
|
||||||
module_manager.stub(:on_module_load)
|
module_manager.stub(:on_module_load)
|
||||||
|
|
||||||
# if the module eval error includes the module_path then the module_path was passed along correctly
|
# if the module eval error includes the module_path then the module_path was passed along correctly
|
||||||
|
@ -356,13 +345,29 @@ describe Msf::Modules::Loader::Base do
|
||||||
subject.load_module(parent_path, type, module_reference_name, :reload => true).should be_false
|
subject.load_module(parent_path, type, module_reference_name, :reload => true).should be_false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'with empty module content' do
|
||||||
|
before(:each) do
|
||||||
|
subject.stub(:read_module_content).with(parent_path, type, module_reference_name).and_return('')
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should return false' do
|
||||||
|
subject.load_module(parent_path, type, module_reference_name).should be_false
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should not attempt to make a new namespace_module' do
|
||||||
|
subject.should_not_receive(:namespace_module_transaction)
|
||||||
|
subject.load_module(parent_path, type, module_reference_name).should be_false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context 'with errors from namespace_module_eval_with_lexical_scope' do
|
context 'with errors from namespace_module_eval_with_lexical_scope' do
|
||||||
before(:each) do
|
before(:each) do
|
||||||
@namespace_module = mock('Namespace Module')
|
@namespace_module = mock('Namespace Module')
|
||||||
@namespace_module.stub(:parent_path=)
|
@namespace_module.stub(:parent_path=)
|
||||||
|
|
||||||
subject.stub(:namespace_module_transaction).and_yield(@namespace_module)
|
subject.stub(:namespace_module_transaction).and_yield(@namespace_module)
|
||||||
subject.stub(:read_module_content)
|
module_content = mock('Module Content', :empty? => false)
|
||||||
|
subject.stub(:read_module_content).and_return(module_content)
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'with Interrupt' do
|
context 'with Interrupt' do
|
||||||
|
@ -409,16 +414,8 @@ describe Msf::Modules::Loader::Base do
|
||||||
@namespace_module.stub(:version_compatible!).with(module_path, module_reference_name)
|
@namespace_module.stub(:version_compatible!).with(module_path, module_reference_name)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should report error class and string in module_manager.module_load_error_by_path' do
|
it 'should record the load error using the original error' do
|
||||||
subject.load_module(parent_path, type, module_reference_name).should be_false
|
subject.should_receive(:load_error).with(module_path, error)
|
||||||
@module_load_error_by_path[module_path].should == "#{error_class} #{error}"
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'should report error class, string, and backtrace in the log' do
|
|
||||||
subject.should_receive(:elog).with(
|
|
||||||
# don't use join on backtrace as that will match implementation too closely
|
|
||||||
"#{error_class} #{error}:\n#{backtrace[0]}\n#{backtrace[1]}"
|
|
||||||
)
|
|
||||||
subject.load_module(parent_path, type, module_reference_name).should be_false
|
subject.load_module(parent_path, type, module_reference_name).should be_false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -448,18 +445,8 @@ describe Msf::Modules::Loader::Base do
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should report module_path and version compatibility error string in module_manager.module_load_error_by_path' do
|
it 'should record the load error using the Msf::Modules::VersionCompatibilityError' do
|
||||||
subject.load_module(parent_path, type, module_reference_name).should be_false
|
subject.should_receive(:load_error).with(module_path, version_compatibility_error)
|
||||||
|
|
||||||
@module_load_error_by_path[module_path].should include(module_path)
|
|
||||||
@module_load_error_by_path[module_path].should include(version_compatibility_error.to_s)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'should report backtrace of original error in the log' do
|
|
||||||
formatted_backtrace = "\n#{backtrace[0]}\n#{backtrace[1]}"
|
|
||||||
escaped_backtrace = Regexp.escape(formatted_backtrace)
|
|
||||||
|
|
||||||
subject.should_receive(:elog).with(/#{escaped_backtrace}/)
|
|
||||||
subject.load_module(parent_path, type, module_reference_name).should be_false
|
subject.load_module(parent_path, type, module_reference_name).should be_false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -479,7 +466,7 @@ describe Msf::Modules::Loader::Base do
|
||||||
@namespace_module.stub(:module_eval_with_lexical_scope).with(module_content, module_path)
|
@namespace_module.stub(:module_eval_with_lexical_scope).with(module_content, module_path)
|
||||||
|
|
||||||
metasploit_class = mock('Metasploit Class', :parent => @namespace_module)
|
metasploit_class = mock('Metasploit Class', :parent => @namespace_module)
|
||||||
@namespace_module.stub(:metasploit_class => metasploit_class)
|
@namespace_module.stub(:metasploit_class! => metasploit_class)
|
||||||
|
|
||||||
subject.stub(:namespace_module_transaction).and_yield(@namespace_module)
|
subject.stub(:namespace_module_transaction).and_yield(@namespace_module)
|
||||||
|
|
||||||
|
@ -521,13 +508,8 @@ describe Msf::Modules::Loader::Base do
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should report error in module_manage.module_load_error_by_path' do
|
it 'should record the load error' do
|
||||||
subject.load_module(parent_path, type, module_reference_name).should be_false
|
subject.should_receive(:load_error).with(module_path, version_compatibility_error)
|
||||||
@module_load_error_by_path[module_path].should == version_compatibility_error.to_s
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'should log error' do
|
|
||||||
subject.should_receive(:elog).with(version_compatibility_error.to_s)
|
|
||||||
subject.load_module(parent_path, type, module_reference_name).should be_false
|
subject.load_module(parent_path, type, module_reference_name).should be_false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -548,24 +530,27 @@ describe Msf::Modules::Loader::Base do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'without metasploit_class' do
|
context 'without metasploit_class' do
|
||||||
|
let(:error) do
|
||||||
|
Msf::Modules::MetasploitClassCompatibilityError.new(
|
||||||
|
:module_path => module_path,
|
||||||
|
:module_reference_name => module_reference_name
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
before(:each) do
|
before(:each) do
|
||||||
@namespace_module.stub(:metasploit_class).and_return(nil)
|
@namespace_module.stub(:metasploit_class!).with(module_path, module_reference_name).and_raise(error)
|
||||||
end
|
end
|
||||||
|
|
||||||
let(:error_message) do
|
it 'should record load error' do
|
||||||
'Missing Metasploit class constant'
|
subject.should_receive(
|
||||||
end
|
:load_error
|
||||||
|
).with(
|
||||||
it 'should log missing Metasploit class' do
|
module_path,
|
||||||
subject.should_receive(:elog).with(error_message)
|
kind_of(Msf::Modules::MetasploitClassCompatibilityError)
|
||||||
|
)
|
||||||
subject.load_module(parent_path, type, module_reference_name).should be_false
|
subject.load_module(parent_path, type, module_reference_name).should be_false
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should record error in module_manager.module_load_error_by_path' do
|
|
||||||
subject.load_module(parent_path, type, module_reference_name).should be_false
|
|
||||||
@module_load_error_by_path[module_path].should == error_message
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'should return false' do
|
it 'should return false' do
|
||||||
subject.load_module(parent_path, type, module_reference_name).should be_false
|
subject.load_module(parent_path, type, module_reference_name).should be_false
|
||||||
end
|
end
|
||||||
|
@ -583,7 +568,7 @@ describe Msf::Modules::Loader::Base do
|
||||||
end
|
end
|
||||||
|
|
||||||
before(:each) do
|
before(:each) do
|
||||||
@namespace_module.stub(:metasploit_class => metasploit_class)
|
@namespace_module.stub(:metasploit_class! => metasploit_class)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should check if it is usable' do
|
it 'should check if it is usable' do
|
||||||
|
|
|
@ -2,6 +2,126 @@ require 'spec_helper'
|
||||||
require 'msf/core'
|
require 'msf/core'
|
||||||
require 'msf/core/modules/loader/directory'
|
require 'msf/core/modules/loader/directory'
|
||||||
|
|
||||||
describe Msf::Modules::Loader::Directory do
|
require 'msf/core'
|
||||||
|
|
||||||
|
describe Msf::Modules::Loader::Directory do
|
||||||
|
context 'instance methods' do
|
||||||
|
include_context 'Msf::Modules::Loader::Base'
|
||||||
|
|
||||||
|
let(:module_manager) do
|
||||||
|
mock('Module Manager')
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:module_path) do
|
||||||
|
"#{parent_path}/exploits/#{module_reference_name}.rb"
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:type) do
|
||||||
|
'exploit'
|
||||||
|
end
|
||||||
|
|
||||||
|
subject do
|
||||||
|
described_class.new(module_manager)
|
||||||
|
end
|
||||||
|
|
||||||
|
context '#load_module' do
|
||||||
|
context 'with existent module_path' do
|
||||||
|
let(:framework) do
|
||||||
|
framework = mock('Msf::Framework', :datastore => {})
|
||||||
|
|
||||||
|
events = mock('Events')
|
||||||
|
events.stub(:on_module_load)
|
||||||
|
events.stub(:on_module_created)
|
||||||
|
framework.stub(:events => events)
|
||||||
|
|
||||||
|
framework
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:module_full_name) do
|
||||||
|
"#{type}/#{module_reference_name}"
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:module_manager) do
|
||||||
|
Msf::ModuleManager.new(framework)
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:module_reference_name) do
|
||||||
|
'windows/smb/ms08_067_netapi'
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should load a module that can be created' do
|
||||||
|
subject.load_module(parent_path, type, module_reference_name).should be_true
|
||||||
|
|
||||||
|
created_module = module_manager.create(module_full_name)
|
||||||
|
|
||||||
|
created_module.name.should == 'Microsoft Server Service Relative Path Stack Corruption'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'without existent module_path' do
|
||||||
|
let(:module_reference_name) do
|
||||||
|
'osx/armle/safari_libtiff'
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:error) do
|
||||||
|
Errno::ENOENT.new(module_path)
|
||||||
|
end
|
||||||
|
|
||||||
|
before(:each) do
|
||||||
|
module_manager.stub(:file_changed? => true)
|
||||||
|
module_manager.stub(:module_load_error_by_path => {})
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should not raise an error' do
|
||||||
|
File.exist?(module_path).should be_false
|
||||||
|
|
||||||
|
expect {
|
||||||
|
subject.load_module(parent_path, type, module_reference_name)
|
||||||
|
}.to_not raise_error
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should return false' do
|
||||||
|
File.exist?(module_path).should be_false
|
||||||
|
|
||||||
|
subject.load_module(parent_path, type, module_reference_name).should be_false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context '#read_module_content' do
|
||||||
|
context 'with non-existent module_path' do
|
||||||
|
let(:module_reference_name) do
|
||||||
|
'osx/armle/safari_libtiff'
|
||||||
|
end
|
||||||
|
|
||||||
|
before(:each) do
|
||||||
|
subject.stub(:load_error).with(module_path, kind_of(Errno::ENOENT))
|
||||||
|
end
|
||||||
|
|
||||||
|
# this ensures that the File.exist?(module_path) checks are checking the same path as the code under test
|
||||||
|
it 'should attempt to open the expected module_path' do
|
||||||
|
File.should_receive(:open).with(module_path, 'rb')
|
||||||
|
File.exist?(module_path).should be_false
|
||||||
|
|
||||||
|
subject.send(:read_module_content, parent_path, type, module_reference_name)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should not raise an error' do
|
||||||
|
expect {
|
||||||
|
subject.send(:read_module_content, parent_path, type, module_reference_name)
|
||||||
|
}.to_not raise_error
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should return an empty string' do
|
||||||
|
subject.send(:read_module_content, parent_path, type, module_reference_name).should == ''
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should record the load error' do
|
||||||
|
subject.should_receive(:load_error).with(module_path, kind_of(Errno::ENOENT))
|
||||||
|
|
||||||
|
subject.send(:read_module_content, parent_path, type, module_reference_name).should == ''
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
require 'msf/core/modules/metasploit_class_compatibility_error'
|
||||||
|
|
||||||
|
describe Msf::Modules::MetasploitClassCompatibilityError do
|
||||||
|
it_should_behave_like 'Msf::Modules::Error subclass #initialize'
|
||||||
|
end
|
|
@ -0,0 +1,267 @@
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
require 'msf/core'
|
||||||
|
require 'msf/core/modules/namespace'
|
||||||
|
|
||||||
|
describe Msf::Modules::Namespace do
|
||||||
|
let(:module_path) do
|
||||||
|
"parent/path/type_directory/#{module_reference_name}.rb"
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:module_reference_name) do
|
||||||
|
'module/reference/name'
|
||||||
|
end
|
||||||
|
|
||||||
|
subject do
|
||||||
|
mod = Module.new
|
||||||
|
mod.extend described_class
|
||||||
|
|
||||||
|
mod
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'metasploit_class' do
|
||||||
|
before(:each) do
|
||||||
|
if major
|
||||||
|
subject.const_set("Metasploit#{major}", Class.new)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'without Metasploit<n> constant defined' do
|
||||||
|
let(:major) do
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should not be defined' do
|
||||||
|
metasploit_constants = subject.constants.select { |constant|
|
||||||
|
constant.to_s =~ /Metasploit/
|
||||||
|
}
|
||||||
|
|
||||||
|
metasploit_constants.should be_empty
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with Metasploit1 constant defined' do
|
||||||
|
let(:major) do
|
||||||
|
1
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should be defined' do
|
||||||
|
subject.const_defined?('Metasploit1').should be_true
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should return the class' do
|
||||||
|
subject.metasploit_class.should be_a Class
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with Metasploit2 constant defined' do
|
||||||
|
let(:major) do
|
||||||
|
2
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should be defined' do
|
||||||
|
subject.const_defined?('Metasploit2').should be_true
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should return the class' do
|
||||||
|
subject.metasploit_class.should be_a Class
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with Metasploit3 constant defined' do
|
||||||
|
let(:major) do
|
||||||
|
3
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should be defined' do
|
||||||
|
subject.const_defined?('Metasploit3').should be_true
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should return the class' do
|
||||||
|
subject.metasploit_class.should be_a Class
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with Metasploit4 constant defined' do
|
||||||
|
let(:major) do
|
||||||
|
4
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should be defined' do
|
||||||
|
subject.const_defined?('Metasploit4').should be_true
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should return the class' do
|
||||||
|
subject.metasploit_class.should be_a Class
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with Metasploit5 constant defined' do
|
||||||
|
let(:major) do
|
||||||
|
5
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should be defined' do
|
||||||
|
subject.const_defined?('Metasploit5').should be_true
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should be newer than Msf::Framework::Major' do
|
||||||
|
major.should > Msf::Framework::Major
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should return nil' do
|
||||||
|
subject.metasploit_class.should be_nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'metasploit_class!' do
|
||||||
|
it 'should call metasploit_class' do
|
||||||
|
subject.should_receive(:metasploit_class).and_return(Class.new)
|
||||||
|
|
||||||
|
subject.metasploit_class!(module_path, module_reference_name)
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with metasploit_class' do
|
||||||
|
let(:metasploit_class) do
|
||||||
|
Class.new
|
||||||
|
end
|
||||||
|
|
||||||
|
before(:each) do
|
||||||
|
subject.stub(:metasploit_class => metasploit_class)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should return the metasploit_class' do
|
||||||
|
subject.metasploit_class!(module_path, module_reference_name).should == metasploit_class
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'without metasploit_class' do
|
||||||
|
before(:each) do
|
||||||
|
subject.stub(:metasploit_class => nil)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should raise a Msf::Modules::MetasploitClassCompatibilityError' do
|
||||||
|
expect {
|
||||||
|
subject.metasploit_class!(module_path, module_reference_name)
|
||||||
|
}.to raise_error(Msf::Modules::MetasploitClassCompatibilityError)
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'the Msf::Modules::MetasploitClassCompatibilityError' do
|
||||||
|
it 'should include the module path' do
|
||||||
|
error = nil
|
||||||
|
|
||||||
|
begin
|
||||||
|
subject.metasploit_class!(module_path, module_reference_name)
|
||||||
|
rescue Msf::Modules::MetasploitClassCompatibilityError => error
|
||||||
|
end
|
||||||
|
|
||||||
|
error.should_not be_nil
|
||||||
|
error.to_s.should include(module_path)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should include the module reference name' do
|
||||||
|
error = nil
|
||||||
|
|
||||||
|
begin
|
||||||
|
subject.metasploit_class!(module_path, module_reference_name)
|
||||||
|
rescue Msf::Modules::MetasploitClassCompatibilityError => error
|
||||||
|
end
|
||||||
|
|
||||||
|
error.should_not be_nil
|
||||||
|
error.to_s.should include(module_reference_name)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'version_compatible!' do
|
||||||
|
context 'without RequiredVersions' do
|
||||||
|
it 'should not be defined' do
|
||||||
|
subject.const_defined?('RequiredVersions').should be_false
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should not raise an error' do
|
||||||
|
expect {
|
||||||
|
subject.version_compatible!(module_path, module_reference_name)
|
||||||
|
}.to_not raise_error
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with RequiredVersions defined' do
|
||||||
|
let(:minimum_api_version) do
|
||||||
|
1
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:minimum_core_version) do
|
||||||
|
1
|
||||||
|
end
|
||||||
|
|
||||||
|
before(:each) do
|
||||||
|
subject.const_set(
|
||||||
|
:RequiredVersions,
|
||||||
|
[
|
||||||
|
minimum_core_version,
|
||||||
|
minimum_api_version
|
||||||
|
]
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with minimum Core version' do
|
||||||
|
it 'should be <= Msf::Framework::VersionCore' do
|
||||||
|
minimum_core_version.should <= Msf::Framework::VersionCore
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'without minimum API version' do
|
||||||
|
let(:minimum_api_version) do
|
||||||
|
2
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should be > Msf::Framework::VersionAPI' do
|
||||||
|
minimum_api_version.should > Msf::Framework::VersionAPI
|
||||||
|
end
|
||||||
|
|
||||||
|
it_should_behave_like 'Msf::Modules::VersionCompatibilityError'
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with minimum API version' do
|
||||||
|
it 'should not raise an error' do
|
||||||
|
expect {
|
||||||
|
subject.version_compatible!(module_path, module_reference_name)
|
||||||
|
}.to_not raise_error(Msf::Modules::VersionCompatibilityError)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'without minimum Core version' do
|
||||||
|
let(:minimum_core_version) do
|
||||||
|
5
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should be > Msf::Framework::VersionCore' do
|
||||||
|
minimum_core_version.should > Msf::Framework::VersionCore
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'without minimum API version' do
|
||||||
|
let(:minimum_api_version) do
|
||||||
|
2
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should be > Msf::Framework::VersionAPI' do
|
||||||
|
minimum_api_version.should > Msf::Framework::VersionAPI
|
||||||
|
end
|
||||||
|
|
||||||
|
it_should_behave_like 'Msf::Modules::VersionCompatibilityError'
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with minimum API version' do
|
||||||
|
it 'should be <= Msf::Framework::VersionAPI' do
|
||||||
|
minimum_api_version <= Msf::Framework::VersionAPI
|
||||||
|
end
|
||||||
|
|
||||||
|
it_should_behave_like 'Msf::Modules::VersionCompatibilityError'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,62 @@
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
describe Msf::Modules::VersionCompatibilityError do
|
||||||
|
it_should_behave_like 'Msf::Modules::Error subclass #initialize' do
|
||||||
|
let(:minimum_api_version) do
|
||||||
|
1
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:minimum_core_version) do
|
||||||
|
2
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should say cause was version check' do
|
||||||
|
subject.to_s.should match(/due to version check/)
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with :minimum_api_version' do
|
||||||
|
subject do
|
||||||
|
described_class.new(
|
||||||
|
:minimum_api_version => minimum_api_version
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should set minimum_api_version' do
|
||||||
|
subject.minimum_api_version.should == minimum_api_version
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should include minimum_api_version in error' do
|
||||||
|
subject.to_s.should match(/due to version check \(requires API >= #{minimum_api_version}\)/)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with :minimum_api_version and :minimum_core_version' do
|
||||||
|
subject do
|
||||||
|
described_class.new(
|
||||||
|
:minimum_api_version => minimum_api_version,
|
||||||
|
:minimum_core_version => minimum_core_version
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should include minimum_api_version and minimum_core_version in error' do
|
||||||
|
subject.to_s.should match(/due to version check \(requires API >= #{minimum_api_version} and Core >= #{minimum_core_version}\)/)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with :minimum_core_version' do
|
||||||
|
subject do
|
||||||
|
described_class.new(
|
||||||
|
:minimum_core_version => minimum_core_version
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should set minimum_core_version' do
|
||||||
|
subject.minimum_core_version.should == minimum_core_version
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should include minimum_core_version in error' do
|
||||||
|
subject.to_s.should match(/due to version check \(requires Core >= #{minimum_core_version}\)/)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -8,6 +8,11 @@ root_pathname = spec_pathname.join('..').expand_path
|
||||||
lib_pathname = root_pathname.join('lib')
|
lib_pathname = root_pathname.join('lib')
|
||||||
$LOAD_PATH.unshift(lib_pathname.to_s)
|
$LOAD_PATH.unshift(lib_pathname.to_s)
|
||||||
|
|
||||||
|
# must be first require and started before any other requires so that it can measure coverage of all following required
|
||||||
|
# code. It is after the rubygems and bundler only because Bundler.setup supplies the LOAD_PATH to simplecov.
|
||||||
|
require 'simplecov'
|
||||||
|
SimpleCov.start
|
||||||
|
|
||||||
require 'rspec/core'
|
require 'rspec/core'
|
||||||
|
|
||||||
# Requires supporting ruby files with custom matchers and macros, etc,
|
# Requires supporting ruby files with custom matchers and macros, etc,
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
shared_context 'Msf::Modules::Error attributes' do
|
||||||
|
let(:causal_message) do
|
||||||
|
'rspec'
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:module_path) do
|
||||||
|
"parent/path/type/#{module_reference_name}.rb"
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:module_reference_name) do
|
||||||
|
'module/reference/name'
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,13 @@
|
||||||
|
shared_context "Msf::Modules::Loader::Base" do
|
||||||
|
let(:parent_path) do
|
||||||
|
parent_pathname.to_s
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:parent_pathname) do
|
||||||
|
root_pathname.join('modules')
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:root_pathname) do
|
||||||
|
Pathname.new(Msf::Config.install_root)
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,26 @@
|
||||||
|
shared_examples_for 'Msf::Modules::Error subclass #initialize' do
|
||||||
|
context 'instance methods' do
|
||||||
|
context '#initialize' do
|
||||||
|
include_context 'Msf::Modules::Error attributes'
|
||||||
|
|
||||||
|
subject do
|
||||||
|
described_class.new(
|
||||||
|
:module_path => module_path,
|
||||||
|
:module_reference_name => module_reference_name
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should include causal message in error' do
|
||||||
|
subject.to_s.should match(/due to .*/)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should set module_path' do
|
||||||
|
subject.module_path.should == module_path
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should set module_reference_name' do
|
||||||
|
subject.module_reference_name.should == module_reference_name
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,32 @@
|
||||||
|
shared_examples_for 'Msf::Modules::VersionCompatibilityError' do
|
||||||
|
let(:error) do
|
||||||
|
begin
|
||||||
|
subject.version_compatible!(module_path, module_reference_name)
|
||||||
|
rescue Msf::Modules::VersionCompatibilityError => error
|
||||||
|
end
|
||||||
|
|
||||||
|
error
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should be raised' do
|
||||||
|
expect {
|
||||||
|
subject.version_compatible!(module_path, module_reference_name)
|
||||||
|
}.to raise_error(Msf::Modules::VersionCompatibilityError)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should include minimum API version' do
|
||||||
|
error.to_s.should include(minimum_api_version.to_s)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should include minimum Core version' do
|
||||||
|
error.to_s.should include(minimum_core_version.to_s)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should include module path' do
|
||||||
|
error.to_s.should include(module_path)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should include module reference name' do
|
||||||
|
error.to_s.should include(module_reference_name)
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in New Issue