Files
metasploit-gs/lib/msf/core/modules/metadata/cache.rb
T
2017-11-15 16:38:01 -06:00

125 lines
3.2 KiB
Ruby

require 'singleton'
require 'msf/events'
require 'rex/ui/text/output/stdio'
require 'msf/core/constants'
require 'msf/core/modules/metadata'
require 'msf/core/modules/metadata/obj'
require 'msf/core/modules/metadata/search'
require 'msf/core/modules/metadata/store'
#
# Core service class that provides storage of module metadata as well as operations on the metadata.
# Note that operations on this metadata are included as separate modules.
#
module Msf
module Modules
module Metadata
class Cache
include Singleton
include Msf::Modules::Metadata::Search
include Msf::Modules::Metadata::Store
#
# Refreshes cached module metadata as well as updating the store
#
def refresh_metadata_instance(module_instance)
refresh_metadata_instance_internal(module_instance)
update_store
end
#
# Returns the module data cache, but first ensures all the metadata is loaded
#
def get_metadata
wait_for_load
@module_metadata_cache.values
end
#
# Checks for modules loaded that are not a part of the cache and updates the underlying store
# if there are changes.
#
def refresh_metadata(module_sets)
unchanged_module_references = get_unchanged_module_references
has_changes = false
module_sets.each do |mt|
unchanged_reference_name_set = unchanged_module_references[mt[0]]
mt[1].keys.sort.each do |mn|
next if unchanged_reference_name_set.include? mn
module_instance = mt[1].create(mn)
next if not module_instance
begin
refresh_metadata_instance_internal(module_instance)
has_changes = true
rescue Exception => e
elog("Error updating module details for #{module_instance.fullname}: #{$!.class} #{$!} : #{e.message}")
end
end
end
update_store if has_changes
end
#
# Returns a hash(type->set) which references modules that have not changed.
#
def get_unchanged_module_references
skip_reference_name_set_by_module_type = Hash.new { |hash, module_type|
hash[module_type] = Set.new
}
@module_metadata_cache.each_value do |module_metadata|
unless module_metadata.path and ::File.exist?(module_metadata.path)
next
end
if ::File.mtime(module_metadata.path).to_i != module_metadata.mod_time.to_i
next
end
skip_reference_name_set = skip_reference_name_set_by_module_type[module_metadata.type]
skip_reference_name_set.add(module_metadata.ref_name)
end
return skip_reference_name_set_by_module_type
end
#######
private
#######
def wait_for_load
@load_thread.join unless @store_loaded
end
def refresh_metadata_instance_internal(module_instance)
metadata_obj = Obj.new(module_instance)
@module_metadata_cache[get_cache_key(module_instance)] = metadata_obj
end
def get_cache_key(module_instance)
key = ''
key << (module_instance.type.nil? ? '' : module_instance.type)
key << '_'
key << module_instance.refname
return key
end
def initialize
@module_metadata_cache = {}
@store_loaded = false
@console = Rex::Ui::Text::Output::Stdio.new
@load_thread = Thread.new {
init_store
@store_loaded = true
}
end
end
end
end
end