From 7cb0330d040ea77b00e0289cebc8785e81475bb0 Mon Sep 17 00:00:00 2001 From: Mike Auty Date: Sat, 10 Feb 2018 22:41:39 +0000 Subject: [PATCH] Fix and correctly type ListRequirements. --- volatility/cli/__init__.py | 2 +- .../framework/configuration/requirements.py | 41 ++++++++----------- volatility/framework/interfaces/automagic.py | 7 +--- .../framework/interfaces/configuration.py | 4 +- 4 files changed, 24 insertions(+), 30 deletions(-) diff --git a/volatility/cli/__init__.py b/volatility/cli/__init__.py index 55de75816..5017aa2cd 100644 --- a/volatility/cli/__init__.py +++ b/volatility/cli/__init__.py @@ -236,7 +236,7 @@ class CommandLine(object): # we expect the plugin to fail validation instead else: additional["nargs"] = requirement.max_elements - additional["type"] = requirement.element_type.instance_type + additional["type"] = requirement.element_type elif isinstance(requirement, volatility.framework.configuration.requirements.ChoiceRequirement): additional["type"] = str additional["choices"] = requirement.choices diff --git a/volatility/framework/configuration/requirements.py b/volatility/framework/configuration/requirements.py index 7ce7f793d..7a250b12a 100644 --- a/volatility/framework/configuration/requirements.py +++ b/volatility/framework/configuration/requirements.py @@ -63,44 +63,40 @@ class ListRequirement(interfaces_configuration.RequirementInterface): """ def __init__(self, - element_type: interfaces_configuration.InstanceRequirement, - max_elements: int, - min_elements: int, *args, **kwargs) -> None: + element_type: typing.Type[interfaces_configuration.SimpleTypes] = str, + max_elements: typing.Optional[int] = 0, + min_elements: typing.Optional[int] = None, *args, **kwargs) -> None: """Constructs the object :param element_type: The (requirement) type of each element within the list - :type element_type: interfaces_configuration.InstanceRequirement :param max_elements; The maximum number of acceptable elements this list can contain - :type max_elements: int :param min_elements: The minimum number of acceptable elements this list can contain - :type min_elements: int """ super().__init__(*args, **kwargs) - if not isinstance(element_type, interfaces_configuration.InstanceRequirement): - raise TypeError("ListRequirements can only contain simple InstanceRequirements") - self.element_type = element_type - self.min_elements = min_elements # type: int - self.max_elements = max_elements # type: int + if not issubclass(element_type, interfaces_configuration.BasicTypes): + raise TypeError("ListRequirements can only be populated with simple InstanceRequirements") + self.element_type = element_type # type: typing.Type + self.min_elements = min_elements or 0 # type: int + self.max_elements = max_elements # type: typing.Optional[int] def unsatisfied(self, context: interfaces.context.ContextInterface, config_path: str) -> typing.List[str]: """Check the types on each of the returned values and their number and then call the element type's check for each one""" value = self.config_value(context, config_path) + if value is None: + raise ValueError("No value stored in the configuration") if not isinstance(value, list): # TODO: Check this is the correct response for an error - raise ValueError("") - if not (self.min_elements <= len(value) <= self.max_elements): - vollog.log(constants.LOGLEVEL_V, "TypeError - List option provided more or less elements than allowed.") + raise ValueError("Unexpected config value found: {}".format(repr(value))) + if not (self.min_elements <= len(value)): + vollog.log(constants.LOGLEVEL_V, "TypeError - Too few values provided to list option.") return [interfaces_configuration.path_join(config_path, self.name)] - if not all([self._check_type(element, self.element_type.instance_type) for element in value]): + if self.max_elements and not (len(value) < self.max_elements): + vollog.log(constants.LOGLEVEL_V, "TypeError - Too many values provided to list option.") + return [interfaces_configuration.path_join(config_path, self.name)] + if not all([self._check_type(element, self.element_type) for element in value]): vollog.log(constants.LOGLEVEL_V, "TypeError - At least one element in the list is not of the correct type.") return [interfaces_configuration.path_join(config_path, self.name)] - result = [] - for element in value: - if isinstance(element, str): - subresult = self.element_type.unsatisfied(context, element) - for subvalue in subresult: - result.append(subvalue) - return result + return [] class ChoiceRequirement(interfaces_configuration.RequirementInterface): @@ -110,7 +106,6 @@ class ChoiceRequirement(interfaces_configuration.RequirementInterface): """Constructs the object :param choices: A list of possible string options that can be chosen from - :type choices: list of str """ super().__init__(*args, **kwargs) if not isinstance(choices, list) or any([not isinstance(choice, str) for choice in choices]): diff --git a/volatility/framework/interfaces/automagic.py b/volatility/framework/interfaces/automagic.py index 02437a2b2..3d06f3627 100644 --- a/volatility/framework/interfaces/automagic.py +++ b/volatility/framework/interfaces/automagic.py @@ -63,16 +63,13 @@ class AutomagicInterface(interfaces_configuration.ConfigurableInterface, metacla typing.Tuple[RequirementInterfaceType, ...]], shortcut: bool = True) \ -> typing.List[typing.Tuple[str, str, interfaces_configuration.ConstructableRequirementInterface]]: - """Determines if there is actually an unfulfilled symbol requirement waiting + """Determines if there is actually an unfulfilled requirement waiting - This ensures we do not carry out an expensive search when there is no requirement for a particular symbol table. + This ensures we do not carry out an expensive search when there is no requirement for a particular requirement :param context: Context on which to operate - :type context: ~volatility.framework.interfaces.context.ContextInterface :param config_path: Configuration path of the top-level requirement - :type config_path: str :param requirement: Top-level requirement whose subrequirements will all be searched - :type requirement: ~volatility.framework.interfaces.configuration.RequirementInterface :return: A list of tuples containing the config_path, sub_config_path and requirement identifying the SymbolRequirements """ sub_config_path = interfaces_configuration.path_join(config_path, requirement_root.name) diff --git a/volatility/framework/interfaces/configuration.py b/volatility/framework/interfaces/configuration.py index 8f9268c8c..0ddf11d00 100644 --- a/volatility/framework/interfaces/configuration.py +++ b/volatility/framework/interfaces/configuration.py @@ -27,7 +27,9 @@ CONFIG_SEPARATOR = "." vollog = logging.getLogger(__name__) -ConfigSimpleType = typing.Union[str, int, float, bool, typing.List[typing.Union[str, int, float, bool]]] +BasicTypes = (int, bool, bytes, str) +SimpleTypes = typing.Union[int, bool, bytes, str] +ConfigSimpleType = typing.Union[SimpleTypes, typing.List[SimpleTypes]] def path_join(*args) -> str: