Source code for stoq.plugins.decorator

#!/usr/bin/env python3
#   Copyright 2014-2018 PUNCH Cyber Analytics Group
#
#   Licensed under the Apache License, Version 2.0 (the "License");
#   you may not use this file except in compliance with the License.
#   You may obtain a copy of the License at
#
#       http://www.apache.org/licenses/LICENSE-2.0
#
#   Unless required by applicable law or agreed to in writing, software
#   distributed under the License is distributed on an "AS IS" BASIS,
#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#   See the License for the specific language governing permissions and
#   limitations under the License.

"""
    .. _decorator:

    Overview
    ========

    Decorator plugins are the last plugins run just before saving results. This
    plugin class allows for the analysis of all results from each plugin, the
    original payload, and any extracted payloads. Multiple decorator plugins can
    be loaded, but each plugin is only passed the results once. Decorator plugins
    are extremely useful when post-processing is required of the collective
    results from the entire stoQ workflow.

    Decorator plugins can be defined multiple ways. In these examples, we will use
    the ``test_decorator`` decorator plugin.

    From ``stoq.cfg``::

        [core]
        decorators = test_decorator

    .. note:: Multiple plugins can be defined separated by a comma.

    From the command line::

        $ stoq run -D yara [...]

    .. note:: Multiple plugins can be defined by simply adding the plugin name

    Or, when instantiating the ``Stoq()`` class::

        >>> import stoq
        >>> decorators = ['test_decorator']
        >>> s = Stoq(decorators=decorators, [...])


    Writing a plugin
    ================

    A `decorator` plugin must be a subclass of the ``DecoratorPlugin`` class. Results
    from a decorator are appended to the final ``StoqResponse`` object.

    As with any plugin, a :ref:`configuration file <pluginconfig>` must also exist
    and be properly configured.

    Example
    -------

    ::

        from typing import Dict, Optional

        from stoq.plugins import DecoratorPlugin
        from stoq.helpers import StoqConfigParser
        from stoq.data_classes import StoqResponse, DecoratorResponse


        class ExampleDecorator(DecoratorPlugin):
            def __init__(self, config: StoqConfigParser) -> None:
                super().__init__(config)
                self.msg = config.get('options', 'msg', fallback='do_more msg')

            async def decorate(self, response: StoqResponse) -> Optional[DecoratorResponse]:
                do_more = False
                if 'yara' in response.results[0].plugins_run:
                    do_more = True
                dr = DecoratorResponse({'do_more': do_more, 'msg': self.msg})
                return dr

    API
    ===

"""

from typing import Optional
from abc import abstractmethod, ABC

from stoq.data_classes import StoqResponse, DecoratorResponse
from stoq.plugins import BasePlugin


[docs]class DecoratorPlugin(BasePlugin, ABC):
[docs] @abstractmethod async def decorate(self, response: StoqResponse) -> Optional[DecoratorResponse]: pass