From fcda9febe728ebd1c850385e0d5f9d0c3c487ab2 Mon Sep 17 00:00:00 2001 From: Mike Auty Date: Mon, 6 Apr 2015 18:34:13 -0500 Subject: [PATCH] Convert configuration options over to requirements. --- volatility/framework/config.py | 72 ++++++---------------- volatility/framework/interfaces/config.py | 39 ++++++------ volatility/framework/interfaces/plugins.py | 13 ++-- 3 files changed, 42 insertions(+), 82 deletions(-) diff --git a/volatility/framework/config.py b/volatility/framework/config.py index 6bd79c747..ccba64a26 100644 --- a/volatility/framework/config.py +++ b/volatility/framework/config.py @@ -5,81 +5,45 @@ Created on 7 May 2013 """ import re -from volatility.framework.interfaces.config import GenericRequirement, ConfigurationInterface +from volatility.framework.interfaces.config import GenericRequirement class BooleanRequirement(GenericRequirement): - def __init__(self, *args, **kwargs): - GenericRequirement.__init__(*args, **kwargs) + def check_value(self, value, context): + if not isinstance(self.value, bool): + raise TypeError(self.name + " requirement only accepts a boolean type") - def set_value(self, value): - self._value = bool(value) - - -class AddressSpaceRequirement(GenericRequirement): +class TranslationLayerRequirement(GenericRequirement): """Class maintaining the limitations on what sort of address spaces are acceptable""" # TODO: derive acceptable OSes from the address_space information # TODO: derive acceptable arches from the available layers - def __init__(self, layer_name, astype, os, architectures, *args, **kwargs): - GenericRequirement.__init__(self, *args, **kwargs) - self.layer_name = layer_name - self.astype = astype - self.os = os + def __init__(self, name, layer_type, os_type, architectures, *args, **kwargs): + GenericRequirement.__init__(self, name, *args, **kwargs) + self.layer_type = layer_type + self.os = os_type self.arches = architectures + def check_value(self, value, context): + """Validate that the value is a valid layer name and that the layer adheres to the requirements""" class ListRequirement(GenericRequirement): def __init__(self, min_elements, max_elements, element_type, *args, **kwargs): GenericRequirement.__init__(self, *args, **kwargs) - self.element_type = any([self._type_check(element_type, BooleanRequirement)]) + if isinstance(element_type, ListRequirement): + raise TypeError("ListRequirements cannot contain ListRequirements") + self.element_type = self._type_check(element_type, GenericRequirement) self.min_elements = min_elements self.max_elements = max_elements - def set_value(self, value): + def check_value(self, value, context): self._type_check(value, list) - all([self._type_check(element, self.element_type) for element in value]) + if not all([self._type_check(element, self.element_type) for element in value]): + raise TypeError("At least one element in the list is not of the correct type.") if not (self.min_elements <= len(value) <= self.max_elements): raise TypeError("List option provided more or less elements than allowed.") - self._value = value + [self.element_type.check_value(element, context) for element in value] # TODO: OptionTypes such as choice, list and so on - -class Group(ConfigurationInterface): - """Class to handle configuration groups, contains options""" - - def __init__(self, name = None): - self.__setattr__('_mapping', [], True) - self.__setattr__('_name', name, True) - if False: - # Code here for IDEs that attempt to figure out what's going on with all the magic we're doing - self._mapping = None - ConfigurationInterface.__init__(self, name) - - @property - def keys(self): - return self._mapping - - def __setattr__(self, key, value, force = False): - """Type checks values, and only allows those whose name matches their key""" - if not force: - if key == 'name': - raise KeyError("Name is a reserved attribute of Configuration items.") - - self._type_check(value, ConfigurationInterface) - if not re.match('^[A-Za-z][A-Za-z0-9_]*$', value.name): - raise KeyError("Configuration item names must only be lowercase letters.") - if key != value.name: - raise KeyError("Key and value.name must match") - self._mapping.append(key) - return super(Group, self).__setattr__(key, value) - - -if __name__ == '__main__': - root = Group(name = 'volatility') - root.core = Group(name = 'core') - import pdb - - pdb.set_trace() diff --git a/volatility/framework/interfaces/config.py b/volatility/framework/interfaces/config.py index 223084392..d380c51dc 100644 --- a/volatility/framework/interfaces/config.py +++ b/volatility/framework/interfaces/config.py @@ -6,27 +6,26 @@ from volatility.framework import validity __author__ = 'mike' -class ConfigurationInterface(validity.ValidityRoutines): - """Allows the Configuration components to be composable""" +class GenericRequirement(validity.ValidityRoutines, metaclass = ABCMeta): + """Class to handle a single specific configuration option""" - def __init__(self, name = None): + def __init__(self, name, description = None, default = None, optional = False): + """Creates a new option""" + validity.ValidityRoutines.__init__(self) + self._default = default self._type_check(name, str) self._name = name + self._description = description + self.value = None + self._optional = optional @property def name(self): return self._name - -class GenericRequirement(ConfigurationInterface, ABCMeta): - """Class to handle a single specific configuration option""" - - def __init__(self, name, description = None, default = None): - """Creates a new option""" - ConfigurationInterface.__init__(self, name) - self._default = default - self._description = description - self._value = None + @property + def optional(self): + return self._optional @property def name(self): @@ -38,12 +37,12 @@ class GenericRequirement(ConfigurationInterface, ABCMeta): """A short description of what the Option is designed to affect or achieve.""" return self._description - @property - def value(self): - """Returns the value of the option, or not if it has not yet been set""" - return self._value - @abstractmethod - def set_value(self, value): - """Populates the value doing typing checking/casting in the process""" + def check_value(self, value, context): + """Validates the value against a context + + Returns True if the value is valid + Throws exceptions if the valid is invalid""" pass + + diff --git a/volatility/framework/interfaces/plugins.py b/volatility/framework/interfaces/plugins.py index 6391b2e22..e01774b98 100644 --- a/volatility/framework/interfaces/plugins.py +++ b/volatility/framework/interfaces/plugins.py @@ -33,15 +33,12 @@ class PluginInterface(validity.ValidityRoutines, metaclass = ABCMeta): return self._context @abstractmethod - def establish_context(self): - """Alters the context to ensure the plugin can run. + def requirements(self): + """Returns a ConfigGroup object to contain the required options""" + pass - This function constructs the necessary symbol spaces that the plugin will need. - """ - - @abstractmethod - def plugin_options(self, config_group = None): - """Modifies the passed in ConfigGroup object to contain the required options""" + def check_requirements(self): + pass @abstractmethod def __call__(self, context):