Retab all the things (except external/)
This commit is contained in:
@@ -1,480 +1,480 @@
|
||||
shared_examples_for 'Msf::ModuleManager::Cache' do
|
||||
let(:parent_path) do
|
||||
parent_pathname.to_path
|
||||
end
|
||||
|
||||
let(:parent_pathname) do
|
||||
Metasploit::Framework.root.join('modules')
|
||||
end
|
||||
|
||||
let(:reference_name) do
|
||||
'windows/smb/ms08_067_netapi'
|
||||
end
|
||||
|
||||
let(:type) do
|
||||
'exploit'
|
||||
end
|
||||
|
||||
let(:path) do
|
||||
pathname.to_path
|
||||
end
|
||||
|
||||
let(:pathname) do
|
||||
parent_pathname.join(
|
||||
'exploits',
|
||||
"#{reference_name}.rb"
|
||||
)
|
||||
end
|
||||
|
||||
let(:pathname_modification_time) do
|
||||
pathname.mtime
|
||||
end
|
||||
|
||||
context '#cache_empty?' do
|
||||
subject(:cache_empty?) do
|
||||
module_manager.cache_empty?
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
module_manager.send(:module_info_by_path=, module_info_by_path)
|
||||
end
|
||||
|
||||
context 'with empty' do
|
||||
let(:module_info_by_path) do
|
||||
{}
|
||||
end
|
||||
|
||||
it { should be_true }
|
||||
end
|
||||
|
||||
context 'without empty' do
|
||||
let(:module_info_by_path) do
|
||||
{
|
||||
'path/to/module' => {}
|
||||
}
|
||||
end
|
||||
|
||||
it { should be_false }
|
||||
end
|
||||
end
|
||||
|
||||
context '#cache_in_memory' do
|
||||
def cache_in_memory
|
||||
module_manager.cache_in_memory(
|
||||
class_or_module,
|
||||
:path => path,
|
||||
:reference_name => reference_name,
|
||||
:type => type
|
||||
)
|
||||
end
|
||||
|
||||
def module_info_by_path
|
||||
module_manager.send(:module_info_by_path)
|
||||
end
|
||||
|
||||
let(:class_or_module) do
|
||||
double('Class<Msf::Module> or Module', :parent => namespace_module)
|
||||
end
|
||||
|
||||
let(:namespace_module) do
|
||||
double('Msf::Modules::Namespace', :parent_path => parent_path)
|
||||
end
|
||||
|
||||
context 'with existing :path' do
|
||||
it 'should update module_info_by_path' do
|
||||
expect {
|
||||
cache_in_memory
|
||||
}.to change { module_info_by_path }
|
||||
end
|
||||
|
||||
context 'module_info_by_path' do
|
||||
subject(:module_info_by_path) do
|
||||
module_manager.send(:module_info_by_path)
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
cache_in_memory
|
||||
end
|
||||
|
||||
it 'should have entry for path' do
|
||||
module_info_by_path[path].should be_a Hash
|
||||
end
|
||||
|
||||
context 'value' do
|
||||
subject(:value) do
|
||||
module_info_by_path[path]
|
||||
end
|
||||
|
||||
it 'should have modification time of :path option for :modification_time' do
|
||||
value[:modification_time].should == pathname_modification_time
|
||||
end
|
||||
|
||||
it 'should have parent path from namespace module for :parent_path' do
|
||||
value[:parent_path].should == namespace_module.parent_path
|
||||
end
|
||||
|
||||
it 'should use :reference_name option' do
|
||||
value[:reference_name].should == reference_name
|
||||
end
|
||||
|
||||
it 'should use :type option' do
|
||||
value[:type].should == type
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'without existing :path' do
|
||||
let(:path) do
|
||||
'non/existent/path'
|
||||
end
|
||||
|
||||
it 'should not raise error' do
|
||||
expect {
|
||||
cache_in_memory
|
||||
}.to_not raise_error
|
||||
end
|
||||
|
||||
it 'should not update module_info_by_path' do
|
||||
expect {
|
||||
cache_in_memory
|
||||
}.to_not change { module_info_by_path }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context '#load_cached_module' do
|
||||
subject(:load_cached_module) do
|
||||
module_manager.load_cached_module(type, reference_name)
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
module_manager.send(:module_info_by_path=, module_info_by_path)
|
||||
end
|
||||
|
||||
context 'with module info in cache' do
|
||||
let(:module_info_by_path) do
|
||||
{
|
||||
'path/to/module' => {
|
||||
:parent_path => parent_path,
|
||||
:reference_name => reference_name,
|
||||
:type => type
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it 'should enumerate loaders until if it find the one where loadable?(parent_path) is true' do
|
||||
module_manager.send(:loaders).each do |loader|
|
||||
loader.should_receive(:loadable?).with(parent_path).and_call_original
|
||||
end
|
||||
|
||||
load_cached_module
|
||||
end
|
||||
|
||||
it 'should force load using #load_module on the loader' do
|
||||
Msf::Modules::Loader::Directory.any_instance.should_receive(
|
||||
:load_module
|
||||
).with(
|
||||
parent_path,
|
||||
type,
|
||||
reference_name,
|
||||
:force => true
|
||||
).and_call_original
|
||||
|
||||
load_cached_module
|
||||
end
|
||||
|
||||
context 'return from load_module' do
|
||||
before(:each) do
|
||||
module_manager.send(:loaders).each do |loader|
|
||||
loader.stub(:load_module => module_loaded)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with false' do
|
||||
let(:module_loaded) do
|
||||
false
|
||||
end
|
||||
|
||||
it { should be_false }
|
||||
end
|
||||
|
||||
context 'with true' do
|
||||
let(:module_loaded) do
|
||||
true
|
||||
end
|
||||
|
||||
it { should be_true }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'without module info in cache' do
|
||||
let(:module_info_by_path) do
|
||||
{}
|
||||
end
|
||||
|
||||
it { should be_false }
|
||||
end
|
||||
end
|
||||
|
||||
context '#refresh_cache_from_module_files' do
|
||||
before(:each) do
|
||||
module_manager.stub(:framework_migrated? => framework_migrated?)
|
||||
end
|
||||
|
||||
context 'with framework migrated' do
|
||||
let(:framework_migrated?) do
|
||||
true
|
||||
end
|
||||
|
||||
context 'with module argument' do
|
||||
def refresh_cache_from_module_files
|
||||
module_manager.refresh_cache_from_module_files(module_class_or_instance)
|
||||
end
|
||||
|
||||
let(:module_class_or_instance) do
|
||||
Class.new(Msf::Module)
|
||||
end
|
||||
|
||||
it 'should update database and then update in-memory cache from the database for the given module_class_or_instance' do
|
||||
framework.db.should_receive(:update_module_details).with(module_class_or_instance).ordered
|
||||
module_manager.should_receive(:refresh_cache_from_database).ordered
|
||||
|
||||
refresh_cache_from_module_files
|
||||
end
|
||||
end
|
||||
|
||||
context 'without module argument' do
|
||||
def refresh_cache_from_module_files
|
||||
module_manager.refresh_cache_from_module_files
|
||||
end
|
||||
|
||||
it 'should update database and then update in-memory cache from the database for all modules' do
|
||||
framework.db.should_receive(:update_all_module_details).ordered
|
||||
module_manager.should_receive(:refresh_cache_from_database)
|
||||
|
||||
refresh_cache_from_module_files
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'without framework migrated' do
|
||||
def refresh_cache_from_module_files
|
||||
module_manager.refresh_cache_from_module_files
|
||||
end
|
||||
|
||||
let(:framework_migrated?) do
|
||||
false
|
||||
end
|
||||
|
||||
it 'should not call Msf::DBManager#update_module_details' do
|
||||
framework.db.should_not_receive(:update_module_details)
|
||||
|
||||
refresh_cache_from_module_files
|
||||
end
|
||||
|
||||
it 'should not call Msf::DBManager#update_all_module_details' do
|
||||
framework.db.should_not_receive(:update_all_module_details)
|
||||
|
||||
refresh_cache_from_module_files
|
||||
end
|
||||
|
||||
it 'should not call #refresh_cache_from_database' do
|
||||
module_manager.should_not_receive(:refresh_cache_from_database)
|
||||
|
||||
refresh_cache_from_module_files
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context '#refresh_cache_from_database' do
|
||||
def refresh_cache_from_database
|
||||
module_manager.refresh_cache_from_database
|
||||
end
|
||||
|
||||
it 'should call #module_info_by_path_from_database!' do
|
||||
module_manager.should_receive(:module_info_by_path_from_database!)
|
||||
|
||||
refresh_cache_from_database
|
||||
end
|
||||
end
|
||||
|
||||
context '#framework_migrated?' do
|
||||
subject(:framework_migrated?) do
|
||||
module_manager.send(:framework_migrated?)
|
||||
end
|
||||
|
||||
context 'with framework database' do
|
||||
before(:each) do
|
||||
framework.db.stub(:migrated => migrated)
|
||||
end
|
||||
|
||||
context 'with migrated' do
|
||||
let(:migrated) do
|
||||
true
|
||||
end
|
||||
|
||||
it { should be_true }
|
||||
end
|
||||
|
||||
context 'without migrated' do
|
||||
let(:migrated) do
|
||||
false
|
||||
end
|
||||
|
||||
it { should be_false }
|
||||
end
|
||||
end
|
||||
|
||||
context 'without framework database' do
|
||||
before(:each) do
|
||||
framework.stub(:db => nil)
|
||||
end
|
||||
|
||||
it { should be_false }
|
||||
end
|
||||
end
|
||||
|
||||
context '#module_info_by_path' do
|
||||
it { should respond_to(:module_info_by_path) }
|
||||
end
|
||||
|
||||
context '#module_info_by_path=' do
|
||||
it { should respond_to(:module_info_by_path=) }
|
||||
end
|
||||
|
||||
context '#module_info_by_path_from_database!' do
|
||||
def module_info_by_path
|
||||
module_manager.send(:module_info_by_path)
|
||||
end
|
||||
|
||||
def module_info_by_path_from_database!
|
||||
module_manager.send(:module_info_by_path_from_database!)
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
module_manager.stub(:framework_migrated? => framework_migrated?)
|
||||
end
|
||||
|
||||
context 'with framework migrated' do
|
||||
include_context 'DatabaseCleaner'
|
||||
|
||||
let(:framework_migrated?) do
|
||||
true
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
configurations = Metasploit::Framework::Database.configurations
|
||||
spec = configurations[Metasploit::Framework.env]
|
||||
|
||||
# Need to connect or ActiveRecord::Base.connection_pool will raise an
|
||||
# error.
|
||||
framework.db.connect(spec)
|
||||
end
|
||||
|
||||
it 'should call ActiveRecord::Base.connection_pool.with_connection' do
|
||||
# 1st is from with_established_connection
|
||||
# 2nd is from module_info_by_path_from_database!
|
||||
ActiveRecord::Base.connection_pool.should_receive(:with_connection).at_least(2).times
|
||||
|
||||
module_info_by_path_from_database!
|
||||
end
|
||||
|
||||
it 'should use ActiveRecord::Batches#find_each to enumerate Mdm::Module::Details in batches' do
|
||||
Mdm::Module::Detail.should_receive(:find_each)
|
||||
|
||||
module_info_by_path_from_database!
|
||||
let(:parent_path) do
|
||||
parent_pathname.to_path
|
||||
end
|
||||
|
||||
let(:parent_pathname) do
|
||||
Metasploit::Framework.root.join('modules')
|
||||
end
|
||||
|
||||
let(:reference_name) do
|
||||
'windows/smb/ms08_067_netapi'
|
||||
end
|
||||
|
||||
let(:type) do
|
||||
'exploit'
|
||||
end
|
||||
|
||||
let(:path) do
|
||||
pathname.to_path
|
||||
end
|
||||
|
||||
let(:pathname) do
|
||||
parent_pathname.join(
|
||||
'exploits',
|
||||
"#{reference_name}.rb"
|
||||
)
|
||||
end
|
||||
|
||||
let(:pathname_modification_time) do
|
||||
pathname.mtime
|
||||
end
|
||||
|
||||
context '#cache_empty?' do
|
||||
subject(:cache_empty?) do
|
||||
module_manager.cache_empty?
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
module_manager.send(:module_info_by_path=, module_info_by_path)
|
||||
end
|
||||
|
||||
context 'with empty' do
|
||||
let(:module_info_by_path) do
|
||||
{}
|
||||
end
|
||||
|
||||
context 'with database cache' do
|
||||
#
|
||||
# Let!s (let + before(:each))
|
||||
#
|
||||
it { should be_true }
|
||||
end
|
||||
|
||||
let!(:mdm_module_detail) do
|
||||
FactoryGirl.create(:mdm_module_detail,
|
||||
:file => path,
|
||||
:mtype => type,
|
||||
:mtime => pathname.mtime,
|
||||
:refname => reference_name
|
||||
)
|
||||
end
|
||||
context 'without empty' do
|
||||
let(:module_info_by_path) do
|
||||
{
|
||||
'path/to/module' => {}
|
||||
}
|
||||
end
|
||||
|
||||
it 'should create cache entry for path' do
|
||||
module_info_by_path_from_database!
|
||||
it { should be_false }
|
||||
end
|
||||
end
|
||||
|
||||
module_info_by_path.should have_key(path)
|
||||
end
|
||||
context '#cache_in_memory' do
|
||||
def cache_in_memory
|
||||
module_manager.cache_in_memory(
|
||||
class_or_module,
|
||||
:path => path,
|
||||
:reference_name => reference_name,
|
||||
:type => type
|
||||
)
|
||||
end
|
||||
|
||||
it 'should use Msf::Modules::Loader::Base.typed_path to derive parent_path' do
|
||||
Msf::Modules::Loader::Base.should_receive(:typed_path).with(type, reference_name).and_call_original
|
||||
def module_info_by_path
|
||||
module_manager.send(:module_info_by_path)
|
||||
end
|
||||
|
||||
module_info_by_path_from_database!
|
||||
end
|
||||
let(:class_or_module) do
|
||||
double('Class<Msf::Module> or Module', :parent => namespace_module)
|
||||
end
|
||||
|
||||
context 'cache entry' do
|
||||
subject(:cache_entry) do
|
||||
module_info_by_path[path]
|
||||
end
|
||||
let(:namespace_module) do
|
||||
double('Msf::Modules::Namespace', :parent_path => parent_path)
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
module_info_by_path_from_database!
|
||||
end
|
||||
context 'with existing :path' do
|
||||
it 'should update module_info_by_path' do
|
||||
expect {
|
||||
cache_in_memory
|
||||
}.to change { module_info_by_path }
|
||||
end
|
||||
|
||||
its([:modification_time]) { should be_within(1.second).of(pathname_modification_time) }
|
||||
its([:parent_path]) { should == parent_path }
|
||||
its([:reference_name]) { should == reference_name }
|
||||
its([:type]) { should == type }
|
||||
end
|
||||
context 'module_info_by_path' do
|
||||
subject(:module_info_by_path) do
|
||||
module_manager.send(:module_info_by_path)
|
||||
end
|
||||
|
||||
context 'typed module set' do
|
||||
let(:typed_module_set) do
|
||||
module_manager.module_set(type)
|
||||
end
|
||||
before(:each) do
|
||||
cache_in_memory
|
||||
end
|
||||
|
||||
context 'with reference_name' do
|
||||
before(:each) do
|
||||
typed_module_set[reference_name] = double('Msf::Module')
|
||||
end
|
||||
it 'should have entry for path' do
|
||||
module_info_by_path[path].should be_a Hash
|
||||
end
|
||||
|
||||
it 'should not change reference_name value' do
|
||||
expect {
|
||||
module_info_by_path_from_database!
|
||||
}.to_not change {
|
||||
typed_module_set[reference_name]
|
||||
}
|
||||
end
|
||||
end
|
||||
context 'value' do
|
||||
subject(:value) do
|
||||
module_info_by_path[path]
|
||||
end
|
||||
|
||||
context 'without reference_name' do
|
||||
it 'should set reference_name value to Msf::SymbolicModule' do
|
||||
module_info_by_path_from_database!
|
||||
it 'should have modification time of :path option for :modification_time' do
|
||||
value[:modification_time].should == pathname_modification_time
|
||||
end
|
||||
|
||||
# have to use fetch because [] will trigger de-symbolization and
|
||||
# instantiation.
|
||||
typed_module_set.fetch(reference_name).should == Msf::SymbolicModule
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
it 'should have parent path from namespace module for :parent_path' do
|
||||
value[:parent_path].should == namespace_module.parent_path
|
||||
end
|
||||
|
||||
context 'without framework migrated' do
|
||||
let(:framework_migrated?) do
|
||||
false
|
||||
end
|
||||
it 'should use :reference_name option' do
|
||||
value[:reference_name].should == reference_name
|
||||
end
|
||||
|
||||
it { should_not query_the_database.when_calling(:module_info_by_path_from_database!) }
|
||||
it 'should use :type option' do
|
||||
value[:type].should == type
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it 'should reset #module_info_by_path' do
|
||||
# pre-fill module_info_by_path so change can be detected
|
||||
module_manager.send(:module_info_by_path=, double('In-memory Cache'))
|
||||
context 'without existing :path' do
|
||||
let(:path) do
|
||||
'non/existent/path'
|
||||
end
|
||||
|
||||
module_info_by_path_from_database!
|
||||
it 'should not raise error' do
|
||||
expect {
|
||||
cache_in_memory
|
||||
}.to_not raise_error
|
||||
end
|
||||
|
||||
module_info_by_path.should be_empty
|
||||
end
|
||||
end
|
||||
end
|
||||
it 'should not update module_info_by_path' do
|
||||
expect {
|
||||
cache_in_memory
|
||||
}.to_not change { module_info_by_path }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context '#load_cached_module' do
|
||||
subject(:load_cached_module) do
|
||||
module_manager.load_cached_module(type, reference_name)
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
module_manager.send(:module_info_by_path=, module_info_by_path)
|
||||
end
|
||||
|
||||
context 'with module info in cache' do
|
||||
let(:module_info_by_path) do
|
||||
{
|
||||
'path/to/module' => {
|
||||
:parent_path => parent_path,
|
||||
:reference_name => reference_name,
|
||||
:type => type
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it 'should enumerate loaders until if it find the one where loadable?(parent_path) is true' do
|
||||
module_manager.send(:loaders).each do |loader|
|
||||
loader.should_receive(:loadable?).with(parent_path).and_call_original
|
||||
end
|
||||
|
||||
load_cached_module
|
||||
end
|
||||
|
||||
it 'should force load using #load_module on the loader' do
|
||||
Msf::Modules::Loader::Directory.any_instance.should_receive(
|
||||
:load_module
|
||||
).with(
|
||||
parent_path,
|
||||
type,
|
||||
reference_name,
|
||||
:force => true
|
||||
).and_call_original
|
||||
|
||||
load_cached_module
|
||||
end
|
||||
|
||||
context 'return from load_module' do
|
||||
before(:each) do
|
||||
module_manager.send(:loaders).each do |loader|
|
||||
loader.stub(:load_module => module_loaded)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with false' do
|
||||
let(:module_loaded) do
|
||||
false
|
||||
end
|
||||
|
||||
it { should be_false }
|
||||
end
|
||||
|
||||
context 'with true' do
|
||||
let(:module_loaded) do
|
||||
true
|
||||
end
|
||||
|
||||
it { should be_true }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'without module info in cache' do
|
||||
let(:module_info_by_path) do
|
||||
{}
|
||||
end
|
||||
|
||||
it { should be_false }
|
||||
end
|
||||
end
|
||||
|
||||
context '#refresh_cache_from_module_files' do
|
||||
before(:each) do
|
||||
module_manager.stub(:framework_migrated? => framework_migrated?)
|
||||
end
|
||||
|
||||
context 'with framework migrated' do
|
||||
let(:framework_migrated?) do
|
||||
true
|
||||
end
|
||||
|
||||
context 'with module argument' do
|
||||
def refresh_cache_from_module_files
|
||||
module_manager.refresh_cache_from_module_files(module_class_or_instance)
|
||||
end
|
||||
|
||||
let(:module_class_or_instance) do
|
||||
Class.new(Msf::Module)
|
||||
end
|
||||
|
||||
it 'should update database and then update in-memory cache from the database for the given module_class_or_instance' do
|
||||
framework.db.should_receive(:update_module_details).with(module_class_or_instance).ordered
|
||||
module_manager.should_receive(:refresh_cache_from_database).ordered
|
||||
|
||||
refresh_cache_from_module_files
|
||||
end
|
||||
end
|
||||
|
||||
context 'without module argument' do
|
||||
def refresh_cache_from_module_files
|
||||
module_manager.refresh_cache_from_module_files
|
||||
end
|
||||
|
||||
it 'should update database and then update in-memory cache from the database for all modules' do
|
||||
framework.db.should_receive(:update_all_module_details).ordered
|
||||
module_manager.should_receive(:refresh_cache_from_database)
|
||||
|
||||
refresh_cache_from_module_files
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'without framework migrated' do
|
||||
def refresh_cache_from_module_files
|
||||
module_manager.refresh_cache_from_module_files
|
||||
end
|
||||
|
||||
let(:framework_migrated?) do
|
||||
false
|
||||
end
|
||||
|
||||
it 'should not call Msf::DBManager#update_module_details' do
|
||||
framework.db.should_not_receive(:update_module_details)
|
||||
|
||||
refresh_cache_from_module_files
|
||||
end
|
||||
|
||||
it 'should not call Msf::DBManager#update_all_module_details' do
|
||||
framework.db.should_not_receive(:update_all_module_details)
|
||||
|
||||
refresh_cache_from_module_files
|
||||
end
|
||||
|
||||
it 'should not call #refresh_cache_from_database' do
|
||||
module_manager.should_not_receive(:refresh_cache_from_database)
|
||||
|
||||
refresh_cache_from_module_files
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context '#refresh_cache_from_database' do
|
||||
def refresh_cache_from_database
|
||||
module_manager.refresh_cache_from_database
|
||||
end
|
||||
|
||||
it 'should call #module_info_by_path_from_database!' do
|
||||
module_manager.should_receive(:module_info_by_path_from_database!)
|
||||
|
||||
refresh_cache_from_database
|
||||
end
|
||||
end
|
||||
|
||||
context '#framework_migrated?' do
|
||||
subject(:framework_migrated?) do
|
||||
module_manager.send(:framework_migrated?)
|
||||
end
|
||||
|
||||
context 'with framework database' do
|
||||
before(:each) do
|
||||
framework.db.stub(:migrated => migrated)
|
||||
end
|
||||
|
||||
context 'with migrated' do
|
||||
let(:migrated) do
|
||||
true
|
||||
end
|
||||
|
||||
it { should be_true }
|
||||
end
|
||||
|
||||
context 'without migrated' do
|
||||
let(:migrated) do
|
||||
false
|
||||
end
|
||||
|
||||
it { should be_false }
|
||||
end
|
||||
end
|
||||
|
||||
context 'without framework database' do
|
||||
before(:each) do
|
||||
framework.stub(:db => nil)
|
||||
end
|
||||
|
||||
it { should be_false }
|
||||
end
|
||||
end
|
||||
|
||||
context '#module_info_by_path' do
|
||||
it { should respond_to(:module_info_by_path) }
|
||||
end
|
||||
|
||||
context '#module_info_by_path=' do
|
||||
it { should respond_to(:module_info_by_path=) }
|
||||
end
|
||||
|
||||
context '#module_info_by_path_from_database!' do
|
||||
def module_info_by_path
|
||||
module_manager.send(:module_info_by_path)
|
||||
end
|
||||
|
||||
def module_info_by_path_from_database!
|
||||
module_manager.send(:module_info_by_path_from_database!)
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
module_manager.stub(:framework_migrated? => framework_migrated?)
|
||||
end
|
||||
|
||||
context 'with framework migrated' do
|
||||
include_context 'DatabaseCleaner'
|
||||
|
||||
let(:framework_migrated?) do
|
||||
true
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
configurations = Metasploit::Framework::Database.configurations
|
||||
spec = configurations[Metasploit::Framework.env]
|
||||
|
||||
# Need to connect or ActiveRecord::Base.connection_pool will raise an
|
||||
# error.
|
||||
framework.db.connect(spec)
|
||||
end
|
||||
|
||||
it 'should call ActiveRecord::Base.connection_pool.with_connection' do
|
||||
# 1st is from with_established_connection
|
||||
# 2nd is from module_info_by_path_from_database!
|
||||
ActiveRecord::Base.connection_pool.should_receive(:with_connection).at_least(2).times
|
||||
|
||||
module_info_by_path_from_database!
|
||||
end
|
||||
|
||||
it 'should use ActiveRecord::Batches#find_each to enumerate Mdm::Module::Details in batches' do
|
||||
Mdm::Module::Detail.should_receive(:find_each)
|
||||
|
||||
module_info_by_path_from_database!
|
||||
end
|
||||
|
||||
context 'with database cache' do
|
||||
#
|
||||
# Let!s (let + before(:each))
|
||||
#
|
||||
|
||||
let!(:mdm_module_detail) do
|
||||
FactoryGirl.create(:mdm_module_detail,
|
||||
:file => path,
|
||||
:mtype => type,
|
||||
:mtime => pathname.mtime,
|
||||
:refname => reference_name
|
||||
)
|
||||
end
|
||||
|
||||
it 'should create cache entry for path' do
|
||||
module_info_by_path_from_database!
|
||||
|
||||
module_info_by_path.should have_key(path)
|
||||
end
|
||||
|
||||
it 'should use Msf::Modules::Loader::Base.typed_path to derive parent_path' do
|
||||
Msf::Modules::Loader::Base.should_receive(:typed_path).with(type, reference_name).and_call_original
|
||||
|
||||
module_info_by_path_from_database!
|
||||
end
|
||||
|
||||
context 'cache entry' do
|
||||
subject(:cache_entry) do
|
||||
module_info_by_path[path]
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
module_info_by_path_from_database!
|
||||
end
|
||||
|
||||
its([:modification_time]) { should be_within(1.second).of(pathname_modification_time) }
|
||||
its([:parent_path]) { should == parent_path }
|
||||
its([:reference_name]) { should == reference_name }
|
||||
its([:type]) { should == type }
|
||||
end
|
||||
|
||||
context 'typed module set' do
|
||||
let(:typed_module_set) do
|
||||
module_manager.module_set(type)
|
||||
end
|
||||
|
||||
context 'with reference_name' do
|
||||
before(:each) do
|
||||
typed_module_set[reference_name] = double('Msf::Module')
|
||||
end
|
||||
|
||||
it 'should not change reference_name value' do
|
||||
expect {
|
||||
module_info_by_path_from_database!
|
||||
}.to_not change {
|
||||
typed_module_set[reference_name]
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
context 'without reference_name' do
|
||||
it 'should set reference_name value to Msf::SymbolicModule' do
|
||||
module_info_by_path_from_database!
|
||||
|
||||
# have to use fetch because [] will trigger de-symbolization and
|
||||
# instantiation.
|
||||
typed_module_set.fetch(reference_name).should == Msf::SymbolicModule
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'without framework migrated' do
|
||||
let(:framework_migrated?) do
|
||||
false
|
||||
end
|
||||
|
||||
it { should_not query_the_database.when_calling(:module_info_by_path_from_database!) }
|
||||
|
||||
it 'should reset #module_info_by_path' do
|
||||
# pre-fill module_info_by_path so change can be detected
|
||||
module_manager.send(:module_info_by_path=, double('In-memory Cache'))
|
||||
|
||||
module_info_by_path_from_database!
|
||||
|
||||
module_info_by_path.should be_empty
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,162 +1,162 @@
|
||||
shared_examples_for 'Msf::ModuleManager::Loading' do
|
||||
context '#file_changed?' do
|
||||
let(:module_basename) do
|
||||
[basename_prefix, '.rb']
|
||||
end
|
||||
context '#file_changed?' do
|
||||
let(:module_basename) do
|
||||
[basename_prefix, '.rb']
|
||||
end
|
||||
|
||||
it 'should return true if module info is not cached' do
|
||||
Tempfile.open(module_basename) do |tempfile|
|
||||
module_path = tempfile.path
|
||||
it 'should return true if module info is not cached' do
|
||||
Tempfile.open(module_basename) do |tempfile|
|
||||
module_path = tempfile.path
|
||||
|
||||
subject.send(:module_info_by_path)[module_path].should be_nil
|
||||
subject.file_changed?(module_path).should be_true
|
||||
end
|
||||
end
|
||||
subject.send(:module_info_by_path)[module_path].should be_nil
|
||||
subject.file_changed?(module_path).should be_true
|
||||
end
|
||||
end
|
||||
|
||||
it 'should return true if the cached type is Msf::MODULE_PAYLOAD' do
|
||||
Tempfile.open(module_basename) do |tempfile|
|
||||
module_path = tempfile.path
|
||||
modification_time = File.mtime(module_path)
|
||||
it 'should return true if the cached type is Msf::MODULE_PAYLOAD' do
|
||||
Tempfile.open(module_basename) do |tempfile|
|
||||
module_path = tempfile.path
|
||||
modification_time = File.mtime(module_path)
|
||||
|
||||
subject.send(:module_info_by_path)[module_path] = {
|
||||
# :modification_time must match so that it is the :type that is causing the `true` and not the
|
||||
# :modification_time causing the `true`.
|
||||
:modification_time => modification_time,
|
||||
:type => Msf::MODULE_PAYLOAD
|
||||
}
|
||||
subject.send(:module_info_by_path)[module_path] = {
|
||||
# :modification_time must match so that it is the :type that is causing the `true` and not the
|
||||
# :modification_time causing the `true`.
|
||||
:modification_time => modification_time,
|
||||
:type => Msf::MODULE_PAYLOAD
|
||||
}
|
||||
|
||||
subject.file_changed?(module_path).should be_true
|
||||
end
|
||||
end
|
||||
subject.file_changed?(module_path).should be_true
|
||||
end
|
||||
end
|
||||
|
||||
context 'with cache module info and not a payload module' do
|
||||
it 'should return true if the file does not exist on the file system' do
|
||||
tempfile = Tempfile.new(module_basename)
|
||||
module_path = tempfile.path
|
||||
modification_time = File.mtime(module_path).to_i
|
||||
context 'with cache module info and not a payload module' do
|
||||
it 'should return true if the file does not exist on the file system' do
|
||||
tempfile = Tempfile.new(module_basename)
|
||||
module_path = tempfile.path
|
||||
modification_time = File.mtime(module_path).to_i
|
||||
|
||||
subject.send(:module_info_by_path)[module_path] = {
|
||||
:modification_time => modification_time
|
||||
}
|
||||
subject.send(:module_info_by_path)[module_path] = {
|
||||
:modification_time => modification_time
|
||||
}
|
||||
|
||||
tempfile.unlink
|
||||
tempfile.unlink
|
||||
|
||||
File.exist?(module_path).should be_false
|
||||
subject.file_changed?(module_path).should be_true
|
||||
end
|
||||
File.exist?(module_path).should be_false
|
||||
subject.file_changed?(module_path).should be_true
|
||||
end
|
||||
|
||||
it 'should return true if modification time does not match the cached modification time' do
|
||||
Tempfile.open(module_basename) do |tempfile|
|
||||
module_path = tempfile.path
|
||||
modification_time = File.mtime(module_path).to_i
|
||||
cached_modification_time = (modification_time * rand).to_i
|
||||
it 'should return true if modification time does not match the cached modification time' do
|
||||
Tempfile.open(module_basename) do |tempfile|
|
||||
module_path = tempfile.path
|
||||
modification_time = File.mtime(module_path).to_i
|
||||
cached_modification_time = (modification_time * rand).to_i
|
||||
|
||||
subject.send(:module_info_by_path)[module_path] = {
|
||||
:modification_time => cached_modification_time
|
||||
}
|
||||
subject.send(:module_info_by_path)[module_path] = {
|
||||
:modification_time => cached_modification_time
|
||||
}
|
||||
|
||||
cached_modification_time.should_not == modification_time
|
||||
subject.file_changed?(module_path).should be_true
|
||||
end
|
||||
end
|
||||
cached_modification_time.should_not == modification_time
|
||||
subject.file_changed?(module_path).should be_true
|
||||
end
|
||||
end
|
||||
|
||||
it 'should return false if modification time does match the cached modification time' do
|
||||
Tempfile.open(module_basename) do |tempfile|
|
||||
module_path = tempfile.path
|
||||
modification_time = File.mtime(module_path).to_i
|
||||
cached_modification_time = modification_time
|
||||
it 'should return false if modification time does match the cached modification time' do
|
||||
Tempfile.open(module_basename) do |tempfile|
|
||||
module_path = tempfile.path
|
||||
modification_time = File.mtime(module_path).to_i
|
||||
cached_modification_time = modification_time
|
||||
|
||||
subject.send(:module_info_by_path)[module_path] = {
|
||||
:modification_time => cached_modification_time
|
||||
}
|
||||
subject.send(:module_info_by_path)[module_path] = {
|
||||
:modification_time => cached_modification_time
|
||||
}
|
||||
|
||||
cached_modification_time.should == modification_time
|
||||
subject.file_changed?(module_path).should be_false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
cached_modification_time.should == modification_time
|
||||
subject.file_changed?(module_path).should be_false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context '#on_module_load' do
|
||||
def on_module_load
|
||||
module_manager.on_module_load(klass, type, reference_name, options)
|
||||
end
|
||||
context '#on_module_load' do
|
||||
def on_module_load
|
||||
module_manager.on_module_load(klass, type, reference_name, options)
|
||||
end
|
||||
|
||||
let(:klass) do
|
||||
Class.new(Msf::Auxiliary)
|
||||
end
|
||||
let(:klass) do
|
||||
Class.new(Msf::Auxiliary)
|
||||
end
|
||||
|
||||
let(:module_set) do
|
||||
module_manager.module_set(type)
|
||||
end
|
||||
let(:module_set) do
|
||||
module_manager.module_set(type)
|
||||
end
|
||||
|
||||
let(:namespace_module) do
|
||||
double('Namespace Module', :parent_path => parent_path)
|
||||
end
|
||||
let(:namespace_module) do
|
||||
double('Namespace Module', :parent_path => parent_path)
|
||||
end
|
||||
|
||||
let(:options) do
|
||||
{
|
||||
'files' => [
|
||||
path
|
||||
],
|
||||
'paths' => [
|
||||
reference_name
|
||||
],
|
||||
'type' => type
|
||||
}
|
||||
end
|
||||
let(:options) do
|
||||
{
|
||||
'files' => [
|
||||
path
|
||||
],
|
||||
'paths' => [
|
||||
reference_name
|
||||
],
|
||||
'type' => type
|
||||
}
|
||||
end
|
||||
|
||||
let(:parent_path) do
|
||||
Metasploit::Framework.root.join('modules')
|
||||
end
|
||||
let(:parent_path) do
|
||||
Metasploit::Framework.root.join('modules')
|
||||
end
|
||||
|
||||
let(:path) do
|
||||
type_directory = Mdm::Module::Detail::DIRECTORY_BY_TYPE[type]
|
||||
let(:path) do
|
||||
type_directory = Mdm::Module::Detail::DIRECTORY_BY_TYPE[type]
|
||||
|
||||
File.join(parent_path, type_directory, "#{reference_name}.rb")
|
||||
end
|
||||
File.join(parent_path, type_directory, "#{reference_name}.rb")
|
||||
end
|
||||
|
||||
let(:reference_name) do
|
||||
'admin/2wire/xslt_password_reset'
|
||||
end
|
||||
let(:reference_name) do
|
||||
'admin/2wire/xslt_password_reset'
|
||||
end
|
||||
|
||||
let(:type) do
|
||||
klass.type
|
||||
end
|
||||
let(:type) do
|
||||
klass.type
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
klass.stub(:parent => namespace_module)
|
||||
end
|
||||
before(:each) do
|
||||
klass.stub(:parent => namespace_module)
|
||||
end
|
||||
|
||||
it "should add module to type's module_set" do
|
||||
module_set.should_receive(:add_module).with(
|
||||
klass,
|
||||
reference_name,
|
||||
options
|
||||
)
|
||||
it "should add module to type's module_set" do
|
||||
module_set.should_receive(:add_module).with(
|
||||
klass,
|
||||
reference_name,
|
||||
options
|
||||
)
|
||||
|
||||
on_module_load
|
||||
end
|
||||
on_module_load
|
||||
end
|
||||
|
||||
it 'should call cache_in_memory' do
|
||||
module_manager.should_receive(:cache_in_memory)
|
||||
it 'should call cache_in_memory' do
|
||||
module_manager.should_receive(:cache_in_memory)
|
||||
|
||||
on_module_load
|
||||
end
|
||||
on_module_load
|
||||
end
|
||||
|
||||
it 'should pass class to #auto_subscribe_module' do
|
||||
module_manager.should_receive(:auto_subscribe_module).with(klass)
|
||||
it 'should pass class to #auto_subscribe_module' do
|
||||
module_manager.should_receive(:auto_subscribe_module).with(klass)
|
||||
|
||||
on_module_load
|
||||
end
|
||||
on_module_load
|
||||
end
|
||||
|
||||
it 'should fire on_module_load event with class' do
|
||||
framework.events.should_receive(:on_module_load).with(
|
||||
reference_name,
|
||||
klass
|
||||
)
|
||||
it 'should fire on_module_load event with class' do
|
||||
framework.events.should_receive(:on_module_load).with(
|
||||
reference_name,
|
||||
klass
|
||||
)
|
||||
|
||||
on_module_load
|
||||
end
|
||||
end
|
||||
on_module_load
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,77 +1,77 @@
|
||||
shared_examples_for 'Msf::ModuleManager::ModulePaths' do
|
||||
def module_paths
|
||||
module_manager.send(:module_paths)
|
||||
end
|
||||
def module_paths
|
||||
module_manager.send(:module_paths)
|
||||
end
|
||||
|
||||
context '#add_module_path' do
|
||||
it 'should strip trailing File::SEPARATOR from the path' do
|
||||
Dir.mktmpdir do |path|
|
||||
path_with_trailing_separator = path + File::SEPARATOR
|
||||
module_manager.add_module_path(path_with_trailing_separator)
|
||||
context '#add_module_path' do
|
||||
it 'should strip trailing File::SEPARATOR from the path' do
|
||||
Dir.mktmpdir do |path|
|
||||
path_with_trailing_separator = path + File::SEPARATOR
|
||||
module_manager.add_module_path(path_with_trailing_separator)
|
||||
|
||||
module_paths.should_not include(path_with_trailing_separator)
|
||||
module_paths.should include(path)
|
||||
end
|
||||
end
|
||||
module_paths.should_not include(path_with_trailing_separator)
|
||||
module_paths.should include(path)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with Fastlib archive' do
|
||||
it 'should raise an ArgumentError unless the File exists' do
|
||||
file = Tempfile.new(archive_basename)
|
||||
# unlink will clear path, so copy it to a variable
|
||||
path = file.path
|
||||
file.unlink
|
||||
context 'with Fastlib archive' do
|
||||
it 'should raise an ArgumentError unless the File exists' do
|
||||
file = Tempfile.new(archive_basename)
|
||||
# unlink will clear path, so copy it to a variable
|
||||
path = file.path
|
||||
file.unlink
|
||||
|
||||
File.exist?(path).should be_false
|
||||
File.exist?(path).should be_false
|
||||
|
||||
expect {
|
||||
module_manager.add_module_path(path)
|
||||
}.to raise_error(ArgumentError, "The path supplied does not exist")
|
||||
end
|
||||
expect {
|
||||
module_manager.add_module_path(path)
|
||||
}.to raise_error(ArgumentError, "The path supplied does not exist")
|
||||
end
|
||||
|
||||
it 'should add the path to #module_paths if the File exists' do
|
||||
Tempfile.open(archive_basename) do |temporary_file|
|
||||
path = temporary_file.path
|
||||
it 'should add the path to #module_paths if the File exists' do
|
||||
Tempfile.open(archive_basename) do |temporary_file|
|
||||
path = temporary_file.path
|
||||
|
||||
File.exist?(path).should be_true
|
||||
File.exist?(path).should be_true
|
||||
|
||||
module_manager.add_module_path(path)
|
||||
module_manager.add_module_path(path)
|
||||
|
||||
module_paths.should include(path)
|
||||
end
|
||||
end
|
||||
end
|
||||
module_paths.should include(path)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with directory' do
|
||||
it 'should add path to #module_paths' do
|
||||
Dir.mktmpdir do |path|
|
||||
module_manager.add_module_path(path)
|
||||
context 'with directory' do
|
||||
it 'should add path to #module_paths' do
|
||||
Dir.mktmpdir do |path|
|
||||
module_manager.add_module_path(path)
|
||||
|
||||
module_paths.should include(path)
|
||||
end
|
||||
end
|
||||
module_paths.should include(path)
|
||||
end
|
||||
end
|
||||
|
||||
context 'containing Fastlib archives' do
|
||||
it 'should add each Fastlib archive to #module_paths' do
|
||||
Dir.mktmpdir do |directory|
|
||||
Tempfile.open(archive_basename, directory) do |file|
|
||||
module_manager.add_module_path(directory)
|
||||
context 'containing Fastlib archives' do
|
||||
it 'should add each Fastlib archive to #module_paths' do
|
||||
Dir.mktmpdir do |directory|
|
||||
Tempfile.open(archive_basename, directory) do |file|
|
||||
module_manager.add_module_path(directory)
|
||||
|
||||
module_paths.should include(directory)
|
||||
module_paths.should include(file.path)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
module_paths.should include(directory)
|
||||
module_paths.should include(file.path)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with other file' do
|
||||
it 'should raise ArgumentError' do
|
||||
Tempfile.open(basename_prefix) do |file|
|
||||
expect {
|
||||
subject.add_module_path(file.path)
|
||||
}.to raise_error(ArgumentError, 'The path supplied is not a valid directory.')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
context 'with other file' do
|
||||
it 'should raise ArgumentError' do
|
||||
Tempfile.open(basename_prefix) do |file|
|
||||
expect {
|
||||
subject.add_module_path(file.path)
|
||||
}.to raise_error(ArgumentError, 'The path supplied is not a valid directory.')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user