Class: Msf::DataStore
- Inherits:
-
Hash
- Object
- Hash
- Msf::DataStore
- Defined in:
- lib/msf/core/data_store.rb
Overview
The data store is just a bitbucket that holds keyed values. It is used by various classes to hold option values and other state information.
Direct Known Subclasses
Instance Attribute Summary collapse
-
#aliases ⇒ Object
Returns the value of attribute aliases.
-
#imported ⇒ Object
Returns the value of attribute imported.
-
#imported_by ⇒ Object
Returns the value of attribute imported_by.
-
#options ⇒ Object
Returns the value of attribute options.
Instance Method Summary collapse
-
#[](k) ⇒ Object
Case-insensitive wrapper around hash lookup.
-
#[]=(k, v) ⇒ Object
Clears the imported flag for the supplied key since it’s being set directly.
-
#clear ⇒ Object
Completely clear all values in the hash.
-
#clear_non_user_defined ⇒ Object
Remove all imported options from the data store.
-
#copy ⇒ Object
Return a deep copy of this datastore.
-
#delete(k) ⇒ Object
Case-insensitive wrapper around delete.
-
#each(&block) ⇒ Object
Overrides the builtin ‘each’ operator to avoid the following exception on Ruby 1.9.2+ “can’t add a new key into hash during iteration”.
-
#find_key_case(k) ⇒ Object
Case-insensitive key lookup.
-
#from_file(path, name = 'global') ⇒ Object
Imports datastore values from the specified file path using the supplied name.
-
#import_option(key, val, imported = true, imported_by = nil, option = nil) ⇒ Object
TODO: Doesn’t normalize data in the same vein as: github.com/rapid7/metasploit-framework/pull/6644.
-
#import_options(options, imported_by = nil, overwrite = false) ⇒ Object
This method is a helper method that imports the default value for all of the supplied options.
-
#import_options_from_hash(option_hash, imported = true, imported_by = nil) ⇒ Object
Imports options from a hash and stores them in the datastore.
-
#import_options_from_s(option_str, delim = nil) ⇒ Object
Imports option values from a whitespace separated string in VAR=VAL format.
-
#initialize ⇒ DataStore
constructor
Initializes the data store’s internal state.
-
#merge(other) ⇒ Object
Override merge to ensure we merge the aliases and imported hashes.
-
#merge!(other) ⇒ Object
Override merge! so that we merge the aliases and imported hashes.
-
#store(k, v) ⇒ Object
Case-insensitive wrapper around store.
-
#to_external_message_h ⇒ Object
Hack on a hack for the external modules.
-
#to_file(path, name = 'global') ⇒ Object
Persists the contents of the data store to a file.
-
#to_h ⇒ Object
Override Hash’s to_h method so we can include the original case of each key (failing to do this breaks a number of places in framework and pro that use serialized datastores).
-
#to_s(delim = ' ') ⇒ Object
Serializes the options in the datastore to a string.
-
#update_value(k, v) ⇒ Object
Updates a value in the datastore with the specified name, k, to the specified value, v.
-
#user_defined ⇒ Object
Returns a hash of user-defined datastore values.
Constructor Details
#initialize ⇒ DataStore
Initializes the data store’s internal state.
15 16 17 18 19 20 |
# File 'lib/msf/core/data_store.rb', line 15 def initialize() @options = Hash.new @aliases = Hash.new @imported = Hash.new @imported_by = Hash.new end |
Instance Attribute Details
#aliases ⇒ Object
Returns the value of attribute aliases.
23 24 25 |
# File 'lib/msf/core/data_store.rb', line 23 def aliases @aliases end |
#imported ⇒ Object
Returns the value of attribute imported.
24 25 26 |
# File 'lib/msf/core/data_store.rb', line 24 def imported @imported end |
#imported_by ⇒ Object
Returns the value of attribute imported_by.
25 26 27 |
# File 'lib/msf/core/data_store.rb', line 25 def imported_by @imported_by end |
#options ⇒ Object
Returns the value of attribute options.
22 23 24 |
# File 'lib/msf/core/data_store.rb', line 22 def @options end |
Instance Method Details
#[](k) ⇒ Object
Case-insensitive wrapper around hash lookup
52 53 54 |
# File 'lib/msf/core/data_store.rb', line 52 def [](k) super(find_key_case(k)) end |
#[]=(k, v) ⇒ Object
Clears the imported flag for the supplied key since it’s being set directly.
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
# File 'lib/msf/core/data_store.rb', line 31 def []=(k, v) k = find_key_case(k) @imported[k] = false @imported_by[k] = nil opt = @options[k] unless opt.nil? if opt.validate_on_assignment? unless opt.valid?(v, check_empty: false) raise Msf::OptionValidateError.new(["Value '#{v}' is not valid for option '#{k}'"]) end v = opt.normalize(v) end end super(k,v) end |
#clear ⇒ Object
Completely clear all values in the hash
297 298 299 300 |
# File 'lib/msf/core/data_store.rb', line 297 def clear self.keys.each {|k| self.delete(k) } self end |
#clear_non_user_defined ⇒ Object
Remove all imported options from the data store.
283 284 285 286 287 288 289 290 291 292 |
# File 'lib/msf/core/data_store.rb', line 283 def clear_non_user_defined @imported.delete_if { |k, v| if (v and @imported_by[k] != 'self') self.delete(k) @imported_by.delete(k) end v } end |
#copy ⇒ Object
Return a deep copy of this datastore.
240 241 242 243 244 245 246 247 |
# File 'lib/msf/core/data_store.rb', line 240 def copy ds = self.class.new self.keys.each do |k| ds.import_option(k, self[k].kind_of?(String) ? self[k].dup : self[k], @imported[k], @imported_by[k]) end ds.aliases = self.aliases.dup ds end |
#delete(k) ⇒ Object
Case-insensitive wrapper around delete
66 67 68 69 |
# File 'lib/msf/core/data_store.rb', line 66 def delete(k) @aliases.delete_if { |_, v| v.casecmp(k) == 0 } super(find_key_case(k)) end |
#each(&block) ⇒ Object
Overrides the builtin ‘each’ operator to avoid the following exception on Ruby 1.9.2+
"can't add a new key into hash during iteration"
306 307 308 309 310 311 312 |
# File 'lib/msf/core/data_store.rb', line 306 def each(&block) list = [] self.keys.sort.each do |sidx| list << [sidx, self[sidx]] end list.each(&block) end |
#find_key_case(k) ⇒ Object
Case-insensitive key lookup
317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 |
# File 'lib/msf/core/data_store.rb', line 317 def find_key_case(k) # Scan each alias looking for a key search_k = k.downcase if self.aliases.has_key?(search_k) search_k = self.aliases[search_k] end # Scan each key looking for a match self.each_key do |rk| if rk.casecmp(search_k) == 0 return rk end end # Fall through to the non-existent value return k end |
#from_file(path, name = 'global') ⇒ Object
Imports datastore values from the specified file path using the supplied name
225 226 227 228 229 230 231 232 233 234 235 |
# File 'lib/msf/core/data_store.rb', line 225 def from_file(path, name = 'global') begin ini = Rex::Parser::Ini.from_file(path) rescue return end if (ini.group?(name)) (ini[name], false) end end |
#import_option(key, val, imported = true, imported_by = nil, option = nil) ⇒ Object
TODO: Doesn’t normalize data in the same vein as: github.com/rapid7/metasploit-framework/pull/6644
145 146 147 148 149 150 151 152 153 154 155 156 |
# File 'lib/msf/core/data_store.rb', line 145 def import_option(key, val, imported = true, imported_by = nil, option = nil) self.store(key, val) if option option.aliases.each do |a| @aliases[a.downcase] = key.downcase end end @options[key] = option @imported[key] = imported @imported_by[key] = imported_by end |
#import_options(options, imported_by = nil, overwrite = false) ⇒ Object
This method is a helper method that imports the default value for all of the supplied options
85 86 87 88 89 90 91 |
# File 'lib/msf/core/data_store.rb', line 85 def (, imported_by = nil, overwrite = false) .each_option do |name, opt| if self[name].nil? || overwrite import_option(name, opt.default, true, imported_by, opt) end end end |
#import_options_from_hash(option_hash, imported = true, imported_by = nil) ⇒ Object
Imports options from a hash and stores them in the datastore.
137 138 139 140 141 |
# File 'lib/msf/core/data_store.rb', line 137 def (option_hash, imported = true, imported_by = nil) option_hash.each_pair { |key, val| import_option(key, val, imported, imported_by) } end |
#import_options_from_s(option_str, delim = nil) ⇒ Object
Imports option values from a whitespace separated string in VAR=VAL format.
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 |
# File 'lib/msf/core/data_store.rb', line 97 def (option_str, delim = nil) hash = {} # Figure out the delimeter, default to space. if (delim.nil?) delim = /\s/ if (option_str.split('=').length <= 2 or option_str.index(',') != nil) delim = ',' end end # Split on the delimeter option_str.split(delim).each { |opt| var, val = opt.split('=') next if (var =~ /^\s+$/) # Invalid parse? Raise an exception and let those bastards know. if (var == nil or val == nil) var = "unknown" if (!var) raise Rex::ArgumentParseError, "Invalid option specified: #{var}", caller end # Remove trailing whitespaces from the value val.gsub!(/\s+$/, '') # Store the value hash[var] = val } (hash) end |
#merge(other) ⇒ Object
Override merge to ensure we merge the aliases and imported hashes
265 266 267 268 |
# File 'lib/msf/core/data_store.rb', line 265 def merge(other) ds = self.copy ds.merge!(other) end |
#merge!(other) ⇒ Object
Override merge! so that we merge the aliases and imported hashes
252 253 254 255 256 257 258 259 260 |
# File 'lib/msf/core/data_store.rb', line 252 def merge!(other) if other.is_a? DataStore self.aliases.merge!(other.aliases) self.imported.merge!(other.imported) self.imported_by.merge!(other.imported_by) end # call super last so that we return a reference to ourselves super end |
#store(k, v) ⇒ Object
Case-insensitive wrapper around store
59 60 61 |
# File 'lib/msf/core/data_store.rb', line 59 def store(k,v) super(find_key_case(k), v) end |
#to_external_message_h ⇒ Object
Hack on a hack for the external modules
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 |
# File 'lib/msf/core/data_store.rb', line 183 def datastore_hash = {} array_nester = ->(arr) do if arr.first.is_a? Array arr.map &array_nester else arr.map { |item| item.to_s.dup.force_encoding('UTF-8') } end end self.keys.each do |k| # TODO arbitrary depth if self[k].is_a? Array datastore_hash[k.to_s.dup.force_encoding('UTF-8')] = array_nester.call(self[k]) else datastore_hash[k.to_s.dup.force_encoding('UTF-8')] = self[k].to_s.dup.force_encoding('UTF-8') end end datastore_hash end |
#to_file(path, name = 'global') ⇒ Object
Persists the contents of the data store to a file
208 209 210 211 212 213 214 215 216 217 218 219 |
# File 'lib/msf/core/data_store.rb', line 208 def to_file(path, name = 'global') ini = Rex::Parser::Ini.new(path) ini.add_group(name) # Save all user-defined options to the file. user_defined.each_pair { |k, v| ini[name][k] = v } ini.to_file(path) end |
#to_h ⇒ Object
Override Hash’s to_h method so we can include the original case of each key (failing to do this breaks a number of places in framework and pro that use serialized datastores)
174 175 176 177 178 179 180 |
# File 'lib/msf/core/data_store.rb', line 174 def to_h datastore_hash = {} self.keys.each do |k| datastore_hash[k.to_s] = self[k].to_s end datastore_hash end |
#to_s(delim = ' ') ⇒ Object
Serializes the options in the datastore to a string.
161 162 163 164 165 166 167 168 169 |
# File 'lib/msf/core/data_store.rb', line 161 def to_s(delim = ' ') str = '' keys.sort.each { |key| str << "#{key}=#{self[key]}" + ((str.length) ? delim : '') } return str end |
#update_value(k, v) ⇒ Object
Updates a value in the datastore with the specified name, k, to the specified value, v. This update does not alter the imported status of the value.
77 78 79 |
# File 'lib/msf/core/data_store.rb', line 77 def update_value(k, v) self.store(k, v) end |
#user_defined ⇒ Object
Returns a hash of user-defined datastore values. The returned hash does not include default option values.
274 275 276 277 278 |
# File 'lib/msf/core/data_store.rb', line 274 def user_defined reject { |k, v| @imported[k] == true } end |