Contents

🛠️ OPSE Part 3: Create your own plugin

Introduction

In this article, we’ll explain to you how to write your own plugin to extand and automate the OSINT process.

By following this guide, developer’s plugins will be automatically added to the OPSE core.

This article is part of a three-part series on the OPSE project. In this series of articles we will present different part of the project:

  1. Presentation of the tool w/ installation, usage and an example;
  2. A technical presentation of the tool, how it is thinked and coded;
  3. A guide to develop your own OPSE plugin !

Context

During our fourth year in engeneering school, we led a project on the OSINT theme. We asked ourselves how we could obtain as much personnal informations as possible on someone with few data at the beginning.

We started to imagine an automatic tool that, with few input data such as firstname and lastname, would be able to find many connections of this person on the internet. But we wanted it to be an help for anyone else in the future, so they can reuse it and modify it.

Our objectives were simple:

  • automatic;
  • fast;
  • modular;
  • open-source.

This project is now open-source and available on Github: https://github.com/OPSE-Developers/OPSE-Framework

discord logo You want to contribute on the OPSE project ? Join the Discord server by clicking on the logo !

⚙️ Write your own plugin

OPSE-core: Tool class

Each module is represented by a subclass of Tool. A module is a process started by OPSE during execution. If an error occurs in the process, it will be caught and will not affect the other modules.

The development of a module can be done in the execute() method which will be launched at the start of the process.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# ExampleTool.py
class ExampleTool(Tool):
    """
    Class that describes an ExampleTool.
    """
    
    def __init__(self):
        super().__init__()
    
    def execute(self):
        # Your code goes here.

To work, the module require some informations. First, it is possible to define a default configuration in the get_config() method. By default, configuration is:

1
2
3
4
{
    'active': False,
    'deprecated': False
}

To give the user the opportunity to change some parameters of a plugin, you just need to add those parameters in the get_config() method.

1
2
3
4
5
6
7
# ExampleTool.py
@staticmethod
def get_config() -> Dict[str, Any]:
    """Function that returns tool configuration as a dictionary."""
    return {
        'example': True
    }

Then, it is necessary to define types of data processed in I/O by the module. This can be done in get_lst_input_data_types() & get_lst_output_data_types() method. Without defining types of data, the module will not be executed.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
# ExampleTool.py
@staticmethod
def get_lst_input_data_types() -> Dict[str, bool]:
    """
    Function that returns the list of data types which can be used to
    run this Tool.
    """
    return {
        DataTypeInput.USERNAME: True, # Required data
        DataTypeInput.EMAIL: False, # Optional data
    }

@staticmethod
def get_lst_output_data_types() -> List[str]:
    """
    Function that returns the list of data types which can be received
    by using this Tool.
    """
    return [
        DataTypeOutput.ACCOUNT,
    ]

Get input data

It is possible to get the profile responsible of the execution of the module with the get_default_profile() method. When default profile is gathered, we have access to required data (data that we have defined in the get_lst_input_data_types()) through getters of the Profile class.

1
2
3
4
# ExampleTool.py
def execute(self):
    default_profile = self.get_default_profile()
    username = default_profile.get_username()

Return profiles

In order for the OPSE tool to process founded data correctly, it is necessary to store data in one or more profiles. These profiles are children of the default profile, so we need to clone the default profile and then add our data to the clones.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# ExampleTool.py
def execute(self):
    default_profile = self.get_default_profile()
    username = default_profile.get_username()

    # Your code goes here.
    # Example: Get the account of the username on example.com.
    example_account = get_example_account() # ← You developed this.

    profile: Profile = default_profile.clone()
    profile.set_lst_accounts([example_account])
    self.append_profile(profile)

Once this is done, the module is ready to be connected.

⚙️ Integrate your plugin to the OPSE core

To connect a module to OPSE core, you will need to place the module in the /core/tools/ directory.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
|-- ...
|-- config.yml
\-- tools
  |-- Example
  |   |-- ...
  |   |-- __init__.py
  |   \-- ExampleTool.py
  |-- __init__.py
  |-- .gitignore
  \-- Tool.py

Once installed, it is necessary to launch OPSE one time to generate the default configuration. The configuration is generated at config.yml.

⚠️ You should review the configuration to configure each module.

1
2
3
4
5
6
7
8
9
# config.yml
Opse:
  config:
  ...
  tools:
    exampletool:
      active: true
      deprecated: false
...

Other entry are automatically generated by OPSE.

📖 The final words

In this series of three articles we presented to you our tool OPSE.

First, we explained to you how it works by doing a simple research. Then, we went deeper in the OPSE core. We presented how the tool was built, the modularity of the project and how we manage plugins. Finally, we explained, on this article, how developer can create their own plugins to be added to the OPSE core and be a part of the project.

We currently work on plugins development, and we are open to any contributions that can improve the core or idea of new plugins that we can add to the project.

📚 Here are the links to other articles about the project:

🛠️ OPSE Part 1: A search engine for people

🛠️ OPSE Part 2: Developing an OSINT framework in Python

🛠️ OPSE Part 3: Create your own plugin