Add in plugin function capability (and make plugin validation centralized on plugin construction).

This commit is contained in:
Mike Auty
2017-01-04 22:58:54 +00:00
parent b4c36bcd15
commit 3a2cc24e2a
3 changed files with 35 additions and 6 deletions
+4
View File
@@ -10,6 +10,10 @@ class VolatilityException(Exception):
"""Class to allow filtering of all VolatilityExceptions"""
class PluginRequirementException(VolatilityException):
"""Class to allow plugins to indicate that a requirement has not been fulfilled"""
class SymbolError(VolatilityException):
"""Thrown when a symbol lookup has failed"""
+18 -6
View File
@@ -4,11 +4,15 @@ They are called and carry out some algorithms on data stored in layers using obj
"""
# Configuration interfaces must be imported separately, since we're part of interfaces and can't import ourselves
import logging
from abc import ABCMeta, abstractmethod
from volatility.framework import exceptions
from volatility.framework import validity
from volatility.framework.interfaces import configuration as interfaces_configuration
vollog = logging.getLogger(__name__)
#
# Plugins
@@ -32,7 +36,11 @@ class PluginInterface(interfaces_configuration.ConfigurableInterface, validity.V
def __init__(self, context, config_path):
super().__init__(context, config_path)
# self.validate()
# Plugins self validate on construction, it makes it more difficult to work with them, but then
# the validation doesn't need to be repeated over and over again by externals
if not self.validate(context, config_path):
vollog.warning("Plugin failed validation")
raise exceptions.PluginRequirementException("The plugin configuration failed to validate")
@classmethod
def get_requirements(cls):
@@ -40,20 +48,24 @@ class PluginInterface(interfaces_configuration.ConfigurableInterface, validity.V
return []
@classmethod
def validate(self, context, config_path):
def validate(cls, context, config_path):
"""Ensures that the plugin's requirements have been met appropriately"""
result_set = [(config_path + "." + requirement.name, requirement.validate(context, config_path)) for requirement
in self.get_requirements() if not requirement.optional]
in cls.get_requirements() if not requirement.optional]
return all([r for _, r in result_set])
@abstractmethod
def run(self):
"""Executes the functionality of the code
.. note:: This method expects `self.validate` to have been called to ensure all necessary options have been provided
:return: a TreeGrid object that can then be passed to a Renderer.
:rtype: interfaces.renderers.TreeGrid
"""
# TODO: Needs to say what it can/can't handle (validate context)
# TODO: Needs to offer available options'
# TODO: Figure out how to handle global config options
def __call__(self, **kwargs):
"""Method to make a plugin callable. It must still have been instantiated with a context and a config_path"""
for k, v in kwargs:
self.config[k] = v
return self.run()
+13
View File
@@ -0,0 +1,13 @@
from volatility.framework import interfaces
def plugin_function(plugin, context, config_path, **kwargs):
"""Run the plugin as a function"""
if not isinstance(plugin, interfaces.plugins.PluginInterface):
raise TypeError("Plugin must be a PluginInterface derived object")
if not isinstance(context, interfaces.context.ContextInterface):
raise TypeError("Context must be a ContextInterface derived object")
if not isinstance(config_path, str):
raise TypeError("Config_path must a be string")
constructed = plugin(context, config_path)
return constructed(**kwargs)