4.3. Server Plugins

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

Server plugins need to inherit from the ServerPlugin class which provides the basic outline. Server plugins have access to their respective configurations from the config attribute. This data is loaded from the server’s configuration file and while it can be changed at runtime, the changes will not be kept after the server has stopped.

A plugin that needs to store data persistently can use the storage attribute which acts as a simple key value store and is backed by the database. Values stored in this must be able to be serialized making it impossible to directly store custom objects.

Server plugins can hook functionality by utilizing the signals module. This allows plugins to provide functionality for specific events.

4.3.1. Adding RPC Methods

Server plugins can provide new RPC methods that are available to client plugins and the client’s RPC terminal. This allows server plugins to provide extended functionality for use by these other components.

Registering new RPC methods is as simple as calling the register_rpc() method. This function, like signal handlers, takes a method as an argument for use as a call back. This method is then called when the RPC function is invoked. The return value of this method is then returned to the caller of the RPC function. The method will automatically be passed the current KingPhisherRequestHandler instance as the first argument (after the standard “self” argument for class methods as applicable). Additional arguments after that accepted from the RPC invocation.

The following is an example of two custom RPC methods.

# ... other initialization code
class Plugin(plugins.ServerPlugin):
    # ... other initialization code
    def initialize(self):
         self.register_rpc('add', self.rpc_add)
         self.register_rpc('greet', self.rpc_greet)
         return True

    # this example takes two arguments to be invoked and returns their sum
    # >>> rpc('plugins/example/add', 1, 2)
    # 3
    def rpc_add(self, handler, number_1, number_2):
        return number_1 + number_2

    # this example takes no arguments but accesses the rpc_session to
    # retrieve the current user name
    # >>> rpc('plugins/example/greet')
    # 'Hello steiner'
    def rpc_greet(self, handler):
        rpc_session = handler.rpc_session
        return 'Hello ' + rpc_session.user

4.3.2. Example

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

import king_phisher.plugins as plugin_opts
import king_phisher.server.plugins as plugins
import king_phisher.server.signals as signals

# this is the main plugin class, it is necessary to inherit from plugins.ServerPlugin
class Plugin(plugins.ServerPlugin):
    authors = ['Spencer McIntyre']  # the plugins author
    title = 'Hello World!'
    description = """
    A 'hello world' plugin to serve as a basic template and demonstration.
    """
    homepage = 'https://github.com/securestate/king-phisher-plugins'
    options = [  # specify options which need to be set through the configuration file
        plugin_opts.OptionString(
            'name',               # the options name
            'the name to greet',  # a basic description of the option
            default=None          # a default value can be specified to
        )
    ]
    req_min_version = '1.4.0'     # (optional) specify the required minimum version of king phisher
    version = '1.0'               # (optional) specify this plugin's version
    def initialize(self):
        self.logger.warning('hello ' + self.config['name'] + '!')
        # connect to a signal via it's object in the signals module
        signals.server_initialized.connect(self.on_server_initialized)
        return True

    def on_server_initialized(self, server):
        self.logger.warning('the server has been initialized')