4.2. Client Plugins

For information on how client plugins are installed, see the Client Plugins wiki page.

Client plugins need to inherit from the ClientPlugin class which provides the basic outline. Client plugins have access to a dictionary for persistent configuration storage through the config attribute. In order for the plugin’s meta-data to be available to the GUI, class attributes are used. This allows information such as the title, description, etc. to be accessed without initializing the class.

4.2.1. Plugin Manager

When the Plugin Manager window is loaded, all available plugins are loaded in order for their information to be retrieved from the class attributes. This is the effective equivalent of importing the module in Python. When the module is enabled, an instance of the Plugin class created allowing it to fulfill its intended purpose.

4.2.1.1. Reloading Plugins

Plugin modules and classes can be “reloaded” to allow changes made to the plugin on disk to take effect. This can be accomplished by right clicking the plugin and selecting the “Reload” option from the manager window. If an enabled plugin is reloaded, it will first be disabled before being re-enabled causing it to lose any state information it may have been storing.

4.2.1.2. Plugin Compatibility

Plugin modules that have requirements can have their compatibility checked by viewing the plugin information pane. This includes a simple yes or no regarding whether all of the plugin’s requirements are met and the plugin is thus compatible. Additional information regarding the specific requirements a particular plugin has can be accessed by clicking the Compatible link which will show each of the requirements, their values and whether or not they are met. This allows users to easily determine why a particular plugin may not be compatible.

4.2.2. Plugin Options

Client plugins have special ClientOption classes available to them for specifying options that the user can set. The king_phisher.client.plugins.ClientOptionMixin.__init__() method offers additional parameters such as display_name to configure the information shown to the end user in the configuration widget.

The following are the different option classes available for client plugins:

4.2.3. Example

The following is a commented example of a basic “Hello World” plugin.

import king_phisher.client.plugins as plugins
import king_phisher.client.gui_utilities as gui_utilities

try:
    # imports that may not be available need to be an exception handler so
    # the plugin module will still load
    import advancedhttpserver
except ImportError:
    # set a variable to whether this package is available or not for later use
    has_ahs = False
else:
    has_ahs = True

# this is the main plugin class, it is necessary to inherit from plugins.ClientPlugin
class Plugin(plugins.ClientPlugin):
    authors = ['Spencer McIntyre']  # the plugins author
    title = 'Hello World!'          # the title of the plugin to be shown to users
    description = """
    A 'hello world' plugin to serve as a basic template and demonstration. This
    plugin will display a message box when King Phisher exits.
    """                             # a description of the plugin to be shown to users
    homepage = 'https://github.com/securestate/king-phisher-plugins'  # an optional home page
    options = [                     # specify options which can be configured through the GUI
        plugins.ClientOptionString(
            'name',                               # the name of the option as it will appear in the configuration
            'The name to which to say goodbye.',  # the description of the option as shown to users
            default='Alice Liddle',               # a default value for the option
            display_name='Your Name'              # a name of the option as shown to users
        ),
        plugins.ClientOptionBoolean(
            'validiction',
            'Whether or not this plugin say good bye.',
            default=True,
            display_name='Say Good Bye'
        ),
        plugins.ClientOptionInteger(
            'some_number',
            'An example number option.',
            default=1337,
            display_name='A Number'
        ),
        plugins.ClientOptionPort(
            'tcp_port',
            'The TCP port to connect to.',
            default=80,
            display_name='Connection Port'
        )
    ]
    req_min_py_version = '3.3.0'         # (optional) specify the required minimum version of python
    req_min_version = '1.4.0'            # (optional) specify the required minimum version of king phisher
    req_packages = {                     # (optional) specify a dictionary of required package names
        'advancedhttpserver': has_ahs    # set from within the exception handler when importing
    }
    req_platforms = ('Linux', 'Windows') # (optional) specify the supported platforms
    version = '1.0'                      # (optional) specify this plugin's version
    # this is the primary plugin entry point which is executed when the plugin is enabled
    def initialize(self):
        print('Hello World!')
        self.signal_connect('exit', self.signal_exit)
        # it is necessary to return True to indicate that the initialization was successful
        # this allows the plugin to check its options and return false to indicate a failure
        return True

    # this is a cleanup method to allow the plugin to close any open resources
    def finalize(self):
        print('Good Bye World!')

    # the plugin connects this handler to the applications 'exit' signal
    def signal_exit(self, app):
        # check the 'validiction' option in the configuration
        if not self.config['validiction']:
            return
        gui_utilities.show_dialog_info(
            "Good bye {0}!".format(self.config['name']),
            app.get_active_window()
        )