From 53f98cd8158d39a01781c77401e3f9ea80503fce Mon Sep 17 00:00:00 2001 From: Robert Habermann Date: Fri, 12 May 2017 20:26:52 +0200 Subject: [PATCH] merge --- viper/common/abstracts.py | 63 +++++++++++++++++++++++++++++++++++++++ viper/core/plugins.py | 42 +++++++++++++++++--------- viper/core/ui/commands.py | 29 ++++++++++++++++-- viper/modules/exif.py | 3 ++ viper/modules/misp.py | 2 ++ 5 files changed, 123 insertions(+), 16 deletions(-) diff --git a/viper/common/abstracts.py b/viper/common/abstracts.py index 145371d5a..5d8d82dbf 100644 --- a/viper/common/abstracts.py +++ b/viper/common/abstracts.py @@ -2,11 +2,19 @@ # This file is part of Viper - https://github.com/viper-framework/viper # See the file 'LICENSE' for copying permission. +import sys import argparse +from distutils.spawn import find_executable +import pkg_resources + +import logging + import viper.common.out as out from viper.core.config import console_output from viper.common.exceptions import ArgumentErrorCallback +log = logging.getLogger('viper') + class ArgumentParser(argparse.ArgumentParser): def print_usage(self, file=None): @@ -31,9 +39,64 @@ class Module(object): authors = [] output = [] + min_python_version = (2, 7) + dependency_list_python = [] + dependency_list_system = [] + def __init__(self): self.parser = ArgumentParser(prog=self.cmd, description=self.description) + def check(self): + min_python_version = self._check_min_python_version() + dep_python = self._check_dependencies_python() + dep_system = self._check_dependencies_system() + if min_python_version and dep_python and dep_system: + return True + else: + return False + + def _check_min_python_version(self): + if sys.version_info >= self.min_python_version: + log.debug("{}: Python Version ok".format(self.__class__.__name__)) + return True + else: + log.warning("{}: Python Version NOT ok".format(self.__class__.__name__)) + return False + + def _check_dependencies_python(self): + if not self.dependency_list_python: + return True + + missing = [] + + for item in self.dependency_list_python: + try: + pkg_resources.require(item) + except pkg_resources.DistributionNotFound as err: + log.debug("{}: Missing Python dependency: {}".format(self.__class__.__name__, err)) + missing.append(item) + except pkg_resources.VersionConflict as err: + log.debug("{}: Python dependency wrong version: {}".format(self.__class__.__name__, err)) + missing.append(item) + + if missing: + log.warning("{}: Missing/Failed Python dependencies: {}".format(self.__class__.__name__, missing)) + return False + + return True + + def _check_dependencies_system(self): + if not self.dependency_list_system: + return True + + missing = [item for item in self.dependency_list_system if not find_executable(item)] + + if missing: + log.warning("{}: Missing System dependencies: {}".format(self.__class__.__name__, missing)) + return False + else: + return True + def set_commandline(self, command): self.command_line = command diff --git a/viper/core/plugins.py b/viper/core/plugins.py index 1a71f9f17..306f69f76 100644 --- a/viper/core/plugins.py +++ b/viper/core/plugins.py @@ -4,6 +4,7 @@ import pkgutil import inspect +import logging import importlib from viper.common.abstracts import Module @@ -11,12 +12,15 @@ from viper.common.abstracts import get_argparse_subparser_actions from viper.common.out import print_warning +log = logging.getLogger('viper') + def load_modules(): # Import modules package. import viper.modules as modules - plugins = dict() + working_plugins = dict() + failed_plugins = dict() # Walk recursively through all modules and packages. for loader, module_name, ispkg in pkgutil.walk_packages(modules.__path__, modules.__name__ + '.'): @@ -32,16 +36,26 @@ def load_modules(): # Walk through all members of currently imported modules. for member_name, member_object in inspect.getmembers(module): - # Check if current member is a class. - if inspect.isclass(member_object): - # Yield the class if it's a subclass of Module. - if issubclass(member_object, Module) and member_object is not Module: - plugins[member_object.cmd] = dict(obj=member_object, - description=member_object.description, - parser_args=get_argparse_parser_actions(member_object().parser), - subparser_args=get_argparse_subparser_actions(member_object().parser)) - - return plugins - - -__modules__ = load_modules() + if not inspect.isclass(member_object): + continue + # Yield the class if it's a subclass of Module. + if issubclass(member_object, Module) and member_object is not Module: + # run dependency check on each module and only add to working list if successful + if member_object().check(): + log.debug("Module: {} - dependency check ok".format(member_name)) + working_plugins[member_object.cmd] = dict(obj=member_object, + description=member_object.description, + parser_args=get_argparse_parser_actions(member_object().parser), + subparser_args=get_argparse_subparser_actions(member_object().parser)) + else: + log.warning("Module: {} - failed dependency check".format(member_name)) + print_warning("Module: {} - failed dependency check".format(member_name)) + failed_plugins[member_object.cmd] = dict(obj=member_object, + description=member_object.description, + parser_args=get_argparse_parser_actions(member_object().parser), + subparser_args=get_argparse_subparser_actions(member_object().parser)) + + return working_plugins, failed_plugins + + +__modules__, __failed_modules__ = load_modules() diff --git a/viper/core/ui/commands.py b/viper/core/ui/commands.py index 4218de70e..e897a6f0d 100644 --- a/viper/core/ui/commands.py +++ b/viper/core/ui/commands.py @@ -30,7 +30,7 @@ from viper.common.version import __version__ from viper.core.session import __sessions__ from viper.core.project import __project__ -from viper.core.plugins import __modules__ +from viper.core.plugins import __modules__, __failed_modules__ from viper.core.database import Database from viper.core.storage import store_sample, get_sample_path from viper.core.config import Config, console_output @@ -107,9 +107,13 @@ class About(Command): cmd = "about" description = "Show information about this Viper instance" + def __init__(self): + super(About, self).__init__() + self.parser.add_argument('-m', '--modules', action='store_true', help="Show info about modules") + def run(self, *args): try: - self.parser.parse_args(args) + args = self.parser.parse_args(args) except: return @@ -128,6 +132,27 @@ def run(self, *args): self.log('table', dict(header=['Configuration', ''], rows=rows)) + if args.modules: + rows = list() + for key, value in __modules__.items(): + min_python_version_str = ".".join([str(x) for x in value['obj'].min_python_version]) + dependency_python = ",".join(value['obj'].dependency_list_python) + dependency_system = ",".join(value['obj'].dependency_list_system) + + rows.append([key, dependency_system, min_python_version_str, dependency_python]) + + self.log('table', dict(header=['Active Modules', 'System dependencies', 'Min Python Version', 'Python requirements'], rows=rows)) + + rows = list() + for key, value in __failed_modules__.items(): + min_python_version_str = ".".join([str(x) for x in value['obj'].min_python_version]) + dependency_python = ",".join(value['obj'].dependency_list_python) + dependency_system = ",".join(value['obj'].dependency_list_system) + + rows.append([key, dependency_system, min_python_version_str, dependency_python]) + + self.log('table', dict(header=['Failed Modules', 'System dependencies', 'Min Python Version', 'Python requirements'], rows=rows)) + class Analysis(Command): ## diff --git a/viper/modules/exif.py b/viper/modules/exif.py index c45091160..776b33bdf 100644 --- a/viper/modules/exif.py +++ b/viper/modules/exif.py @@ -18,6 +18,9 @@ class Exif(Module): description = 'Extract Exif MetaData' authors = ['Kevin Breen'] + dependency_list_python = ["exiftool"] + dependency_list_system = ["exif"] + def __init__(self): super(Exif, self).__init__() diff --git a/viper/modules/misp.py b/viper/modules/misp.py index 73506ba44..601bfa2fc 100644 --- a/viper/modules/misp.py +++ b/viper/modules/misp.py @@ -48,6 +48,8 @@ class MISP(Module): description = 'Upload and query IOCs to/from a MISP instance' authors = ['Raphaƫl Vinot'] + dependency_list_python = ["pymisp", "pytaxonomies", "requests"] + def __init__(self): super(MISP, self).__init__() self.cur_path = __project__.get_path()