Full Code of yakuza8/peniot for AI

master fd1c644653a7 cached
116 files
418.4 KB
108.8k tokens
756 symbols
1 requests
Download .txt
Showing preview only (452K chars total). Download the full file or copy to clipboard to get everything.
Repository: yakuza8/peniot
Branch: master
Commit: fd1c644653a7
Files: 116
Total size: 418.4 KB

Directory structure:
gitextract_1myw_xe2/

├── .gitignore
├── LICENSE
├── README.md
├── setup.py
└── src/
    ├── Entity/
    │   ├── __init__.py
    │   ├── attack.py
    │   ├── attack_suite.py
    │   ├── input_format.py
    │   └── protocol.py
    ├── GUI/
    │   ├── __init__.py
    │   ├── custom_widgets.py
    │   ├── hard_coded_texts.py
    │   ├── tkinter.py
    │   └── utils.py
    ├── Utils/
    │   ├── CommonUtil/
    │   │   └── __init__.py
    │   ├── ExtendUtil/
    │   │   ├── __init__.py
    │   │   ├── export_attack_suite_template.py
    │   │   ├── export_attack_template.py
    │   │   ├── export_protocol_template.py
    │   │   ├── export_util.py
    │   │   └── import_util.py
    │   ├── FilterUtil/
    │   │   ├── __init__.py
    │   │   └── pyshark_filter_util.py
    │   ├── FuzzerUtil/
    │   │   ├── __init__.py
    │   │   └── radamsa_util.py
    │   ├── RandomUtil/
    │   │   ├── __init__.py
    │   │   └── random_generated_names.py
    │   ├── ReportUtil/
    │   │   ├── __init__.py
    │   │   └── report_generator.py
    │   ├── SnifferUtil/
    │   │   ├── __init__.py
    │   │   └── generic_sniffer.py
    │   └── __init__.py
    ├── __init__.py
    ├── captured_packets/
    │   └── __init__.py
    ├── module_installer.py
    ├── peniot.py
    └── protocols/
        ├── AMQP/
        │   ├── __init__.py
        │   ├── amqp_protocol.py
        │   ├── amqp_scanner.py
        │   ├── attacks/
        │   │   ├── __init__.py
        │   │   ├── amqp_dos_attack.py
        │   │   ├── amqp_fuzzing_attack_suite.py
        │   │   ├── amqp_payload_size_fuzzer.py
        │   │   └── amqp_random_payload_fuzzing.py
        │   └── examples/
        │       ├── __init__.py
        │       ├── receiver_example.py
        │       └── sender_example.py
        ├── BLE/
        │   ├── Adafruit_BLESniffer/
        │   │   ├── .gitignore
        │   │   ├── API Manifest.txt
        │   │   ├── LICENSE.txt
        │   │   ├── README.md
        │   │   ├── SnifferAPI/
        │   │   │   ├── CaptureFiles.py
        │   │   │   ├── Devices.py
        │   │   │   ├── Exceptions.py
        │   │   │   ├── Logger.py
        │   │   │   ├── Notifications.py
        │   │   │   ├── Packet.py
        │   │   │   ├── Sniffer.py
        │   │   │   ├── SnifferCollector.py
        │   │   │   ├── UART.py
        │   │   │   ├── Version.py
        │   │   │   ├── __init__.py
        │   │   │   └── myVersion.py
        │   │   ├── __init__.py
        │   │   ├── documentation.html
        │   │   ├── requirements.txt
        │   │   ├── setup.cfg
        │   │   ├── sniffer.py
        │   │   ├── sniffer_uart_protocol.xlsx
        │   │   └── wireshark_dissector_source/
        │   │       ├── OSX/
        │   │       │   └── readme.md
        │   │       ├── packet-btle.c
        │   │       └── packet-nordic_ble.c
        │   ├── BLETest.py
        │   ├── __init__.py
        │   ├── attacks/
        │   │   ├── __init__.py
        │   │   ├── ble_replay_attack.py
        │   │   └── ble_sniff_attack.py
        │   ├── ble_advertiser.py
        │   ├── ble_device.py
        │   ├── ble_protocol.py
        │   ├── ble_replay_attack.py
        │   ├── ble_sniff.py
        │   └── ble_tools.py
        ├── CoAP/
        │   ├── __init__.py
        │   ├── attacks/
        │   │   ├── __init__.py
        │   │   ├── coap_dos_attack.py
        │   │   ├── coap_fuzzing_attack_suite.py
        │   │   ├── coap_payload_size_fuzzer.py
        │   │   ├── coap_random_payload_fuzzing.py
        │   │   ├── coap_replay_attack.py
        │   │   └── coap_sniff_attack.py
        │   ├── coap_protocol.py
        │   ├── coap_scanner.py
        │   └── examples/
        │       ├── __init__.py
        │       ├── client_example.py
        │       ├── resource_example.py
        │       └── server_example.py
        ├── MQTT/
        │   ├── __init__.py
        │   ├── attacks/
        │   │   ├── __init__.py
        │   │   ├── mqtt_dos_attack.py
        │   │   ├── mqtt_fuzzing_attack_suite.py
        │   │   ├── mqtt_generation_based_fuzzing.py
        │   │   ├── mqtt_payload_size_fuzzer.py
        │   │   ├── mqtt_random_payload_fuzzing.py
        │   │   ├── mqtt_replay_attack.py
        │   │   ├── mqtt_sniff_attack.py
        │   │   └── mqtt_topic_name_fuzzing.py
        │   ├── examples/
        │   │   ├── Demo/
        │   │   │   ├── __init__.py
        │   │   │   ├── demo_publisher.py
        │   │   │   └── demo_subscriber.py
        │   │   ├── __init__.py
        │   │   ├── publisher_example.py
        │   │   └── subscriber_example.py
        │   ├── mqtt_protocol.py
        │   └── mqtt_scanner.py
        └── __init__.py

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# PyInstaller
#  Usually these files are written by a python script from a template
#  before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/
.pytest_cache/

# Translations
*.mo
*.pot

# Django stuff:
*.log
local_settings.py
db.sqlite3

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
target/

# Jupyter Notebook
.ipynb_checkpoints

# IPython
profile_default/
ipython_config.py

# pyenv
.python-version

# celery beat schedule file
celerybeat-schedule

# SageMath parsed files
*.sage.py

# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

# Spyder project settings
.spyderproject
.spyproject

# Rope project settings
.ropeproject

# mkdocs documentation
/site

# IntelliJ
.idea/
/out/
src/logging.conf

================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2018 Berat Cankar, Bigehan Bingöl, Doğukan Çavdaroğlu, Ebru Çelebi

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================
# PENIOT: Penetration Testing Tool for IoT

#### Table of Contents
* [Project Description](#Project-Description)
    * [What is PENIOT?](#What-is-PENIOT)
    * [Why is PENIOT required?](#Why-is-PENIOT-required)
    * [What does PENIOT provide?](#What-does-PENIOT-provide)
* [Build Instructions](#Build-Instructions)
* [Documentation](#Documentation)
* [Testing](#Testing)
* [Contributors](#Contributors)
* [Developer's Note](#Developers-Note)
* [Project Poster](#Project-Poster)

## Project Description

### What is PENIOT?

[PENIOT](https://senior.ceng.metu.edu.tr/2019/peniot/) is a penetration testing tool for Internet of Things (IoT) devices. 
It helps you to test/penetrate your devices by targeting their internet connectivity
with different types of security attacks. In other words, you can expose your device
to both active and passive security attacks. After deciding target device and necessary
information (or parameters) of that device, you can perform active security attacks like
altering/consuming system resources, replaying valid communication units and so on.
Also, you can perform passive security attacks such as breaching of confidentiality of
important information or reaching traffic analysis. Thanks to PENIOT, all those operations
can be semi-automated or even fully automated. In short, PENIOT is a package/framework for
targeting IoT devices with protocol based security attacks.

Also, it gives you a baseline structure for your further injections of new security attacks
or new IoT protocols. One of the most important features of PENIOT is being extensible.
By default, it has several common IoT protocols and numerous security attacks related to
those protocols. But, it can be extended further via exporting basic structure of internally
used components so that you can develop your attacks in harmony with the internal structure
of the PENIOT.

### Why is PENIOT required?

The IoT paradigm has experienced immense growth in the past decade, with billions of devices
connected to the Internet. Most of these devices lack even basic security measures due to
their capacity constraints and designs made without security in mind due to the shortness
of time-to-market. Due to the high connectivity in IoT, attacks that have devastating
effects in extended networks can easily be launched by hackers through vulnerable devices.

Up until now, penetration testing was done manually if it was not ignored at all.
This procedure made testing phase of devices very slow. On the other hand, the firms which
produce IoT devices should always be up to date on testing their devices in terms of
reliability, robustness as well as their provided functionalities since being exposed to
security attacks by malicious people could cause unexpected impacts on end-users.
The main aim of PENIOT is to accelerate the process of security testing. It enables you to
figure out security flaws on your IoT devices by automating the time consuming penetration
testing phase.

### What does PENIOT provide?

First of all, PENIOT provides novelty. It is one of the first examples of penetration testing
tools on IoT field. There are only one or two similar tools which are specialized on IoT,
but they are still on development phase, so not completed yet.

Since the number of IoT devices is increasing drastically, IoT devices become more and more
common in our daily life. Smart homes, smart bicycles, medical sensors, fitness trackers,
smart locks and connected factories are just a few examples of IoT products. Given this,
we felt the need to choose some of the most commonly used IoT protocols to plant into PENIOT
by default. We chose the following protcols as the default IoT protocols included in the
PENIOT. These IoT protocols are tested with various types of security attacks such as DoS,
Fuzzing, Sniffing and Replay attacks. 

Following protocols are currently supported:
* Advanced Message Queuing Protocol ([AMQP](https://www.amqp.org/))
* Bluetooth Low Energy ([BLE](https://www.bluetooth.com/))
* Constraint Application Protocol ([CoAP](https://coap.technology/))
* Message Queuing Telemetry Transport ([MQTT](http://mqtt.org/))

Moreover, it enables you to export internal mainframe of its own implemented protocol and
attacks to implement your own protocols or attacks. Also, you can extend already existing
protocols with your newly implemented attacks. And lastly, it provides you an easy to use,
user friendly graphical user interface. 

## Build Instructions
Firstly, you need to have Python's **setuptools** module installed in your machine. Also,
you need to install **python-tk** and **[bluepy](https://github.com/IanHarvey/bluepy)**
before installation and build.

In short, you need the followings before running installation script.
* setuptools
* python-tk
* bluepy

> Note that it is suggested to have a separate virtual environment particularly created
> for Peniot since the dependent libraries are pretty old and can cause some trouble to
> install them among your existing external libraries

You can build project in your local by executing following codes.
```shell
$ git clone git@github.com:yakuza8/peniot.git
$ cd peniot
$ python setup.py install
```
Even if we try to provide you up-to-date installation script, there can be some missing parts in
it since the project cannot be maintained so long. Please inform us if there is any problem
with installation.

**Important Note**: You need to have [Radamsa](https://gitlab.com/akihe/radamsa) installed
in your machine in order for generating fuzzing payloads in fuzzing attacks.  

## Execution

You can run Peniot via command line or your favorite IDE after setting up a virtual environment and 
installing the necessary libraries described above.

```shell
$ python src/peniot.py
```

After running this command, you should see an user interface appeared. Then you can explore the tool
by yourself.

## Documentation
You can find *Design Overview Document* and *Final Design Document* under the **resources/documents** folder.
Several diagrams are attached under the **resources/diagrams** folder. Here is the simplest
representation of how PENIOT is separated modules and how it is designed.

<p align="center">
<img src="/resources/diagrams/peniot_structure_component_diagram.png">
</p>

## Testing
Most of the attacks have their own sample integration tests under their attack scripts. In
order to run those tests, you need to have a running program for the target protocol. We try to
provide you with example programs for each protocol where one can find server/client scripts
under each protocol's **examples** directory. 

## Contributors
This project is contributed by the following project members:
- Berat Cankar
- Bilgehan Bingöl
- Doğukan Çavdaroğlu
- Ebru Çelebi

and is supervised by **Pelin Angın**.

## Developer's Note
Firstly, let me thank you for visiting our project site. We tried to provide you how one can
penetrate and hack IoT devices over the protocols they use thanks to end-to-end security attacks.
Our main purpose is to hack those devices with generic security attacks. One can simply find
specific attacks for any protocol, but as I said ours was to provide generic and extendable
penetration framework. 

Secondly, PENIOT is developed with **Python2.7**. And our code maybe had gone into *legacy state*.
But nevertheless, we wanted to share it to public so that anyone could get insight and
inspiration to develop their own penetration tools, that is what makes us happy if it could happen.

Thirdly, we also will try to port our tool into **Python3** if we can spare necessary time for that.
When it happens, we will inform it from this page as well. Thanks for your attention.

Developer: @yakuza8 (Berat Cankar)

## Project Poster
<p align="center">
<img src="/resources/peniot_vectorized.svg">
</p>


================================================
FILE: setup.py
================================================
from os import path
from setuptools import setup, find_packages
import sys

sys.path.insert(0, "src")

with open(path.join(".", "README.md")) as f:
    long_description = f.read()

setup(
    name="Peniot",
    version="1.0",
    description="Penetration Testing Tool for IoT devices",
    long_description=long_description,
    author="Berat Cankar,Bilgehan Bingol,Ebru Celebi,Dogukan Cavdaroglu",
    url="https://senior.ceng.metu.edu.tr/2019/peniot/",
    platform="Unix",
    packages=find_packages(),
    include_package_data=True,
    install_requires=[
        "Cython",
        "paho-mqtt",
        "scapy",
        "pyshark-legacy",
        "coapthon",
        "fpdf",
        "pygame==1.9.4",
        "pika",
        "pexpect",
        "enum",
    ],
    classifiers=["Programming Language :: Python :: 2.7.9"],
)


================================================
FILE: src/Entity/__init__.py
================================================
"""
    This package contains the following entities:

    1) Protocol
    2) Attack Suite
    3) Attack
    4) Input Format

    In this module, we have the backend entities to represent and structure our code
    And these entities have the following relations in between: (Connection endpoints represent cardinality of entity)

    - Protocol      1----------*    Attack Suite
    - Attack suite  1----------*    Attack
    - Attack        1----------*    Input format
"""

================================================
FILE: src/Entity/attack.py
================================================
import logging

from GUI import hard_coded_texts as hct


class Attack(object):
    name = None
    inputs = []
    default_parameters = []

    def __init__(self, name, inputs, default_parameters, definition, logger=None):
        self.name = name
        self.inputs = inputs
        self.default_parameters = default_parameters
        self.definition = definition
        if logger is None:
            self.logger = logging.getLogger(hct.get_logger_name())
        else:
            self.logger = logging.getLogger("Default logger")

        # Load default parameters into input format values
        self.load_default_parameters()

    def get_attack_name(self):
        return self.name

    def set_attack_name(self, name):
        self.name = name
        return self

    def get_inputs(self):
        return self.inputs

    def set_inputs(self, inputs):
        self.inputs = inputs
        return self

    def insert_input(self, _input):
        if self.inputs is not None:
            self.inputs.append(_input)

    def get_default_parameters(self):
        return self.default_parameters

    def set_default_parameters(self, default_parameters):
        self.default_parameters = default_parameters
        return self

    def insert_default_parameters(self, _default_parameter):
        if self.default_parameters is not None:
            self.default_parameters.append(_default_parameter)

    def get_definition(self):
        return self.definition

    def set_definition(self, definition):
        self.definition = definition

    def set_input_value(self, input_name):
        for _input in self.inputs:
            if _input.get_name() == input_name:
                setattr(self, _input.get_name(), _input.get_value())

    def run(self):
        # Set all the input values of the class, then show begins
        for _input in self.inputs:
            setattr(self, _input.get_name(), _input.get_value())
        # Will be filled by inherited class

    def stop_attack(self):
        pass  # Will be filled by attacks

    def load_default_parameters(self):
        for _input_index, _input in enumerate(self.inputs):
            _input.set_value(self.default_parameters[_input_index])


================================================
FILE: src/Entity/attack_suite.py
================================================
class AttackSuite(object):

    name = None
    attacks = []

    def __init__(self, name, attacks):
        self.name = name
        self.attacks = attacks

    def get_attack_suite_name(self):
        return self.name

    def set_attack_suite_name(self, name):
        self.name = name
        return self

    def get_attacks(self):
        return self.attacks

    def set_attacks(self, attacks):
        self.attacks = attacks
        return self

    def insert_attack(self, attack):
        if self.attacks is not None:
            self.attacks.append(attack)

    def run(self):
        for attack in self.attacks:
            attack.run()


================================================
FILE: src/Entity/input_format.py
================================================
class InputFormat(object):

    def __init__(self, label_name, name, value, _type, default_value=None, mandatory=False, secret=False,
                 from_captured_packets=False):
        self.label_name = label_name
        self.name = name
        self.value = value
        self.type = _type
        self.mandatory = mandatory
        self.default_value = default_value
        self.secret = secret
        self.from_captured_packets = from_captured_packets

    def get_label_name(self):
        return self.label_name

    def set_label_name(self, label_name):
        self.label_name = label_name
        return self

    def get_name(self):
        return self.name

    def set_name(self, name):
        self.name = name
        return self

    def get_value(self):
        return self.value

    def set_value(self, value):
        self.value = value
        return self

    def get_type(self):
        return self.type

    def set_type(self, _type):
        self.type = _type
        return self

    def set_mandatory(self, mandadory):
        self.mandatory = mandadory
        return self

    def is_mandatory(self):
        return self.mandatory

    def set_default_value(self, default_value):
        self.default_value = default_value
        return self

    def get_default_value(self):
        return self.default_value

    def is_secret(self):
        return self.secret

    def set_secret(self, secret):
        self.secret = secret
        return self

    def is_from_captured_packets(self):
        return self.from_captured_packets

    def set_from_captured_packets(self, from_captured_packets):
        self.from_captured_packets = from_captured_packets
        return self


================================================
FILE: src/Entity/protocol.py
================================================
class Protocol(object):

    name = None
    attack_suites = []

    def __init__(self, name, attack_suites, definition):
        self.name = name
        self.attack_suites = attack_suites
        self.definition = definition

    def get_protocol_name(self):
        return self.name

    def set_protocol_name(self, name):
        self.name = name
        return self

    def get_attack_suites(self):
        return self.attack_suites

    def set_attack_suites(self, attack_suites):
        self.attack_suites = attack_suites
        return self

    def get_definition(self):
        return self.definition

    def set_definition(self, new_def):
        self.definition = new_def
        return self

    def insert_attack_suite(self, attack_suite):
        if self.attack_suites is not None:
            self.attack_suites.append(attack_suite)


================================================
FILE: src/GUI/__init__.py
================================================
"""
    This package includes graphical user interface of PENIOT
"""

================================================
FILE: src/GUI/custom_widgets.py
================================================
from Tkinter import *
from hard_coded_texts import get_project_name


class Header(Frame):
    """
    Generic header template class which is used for construction of different screens
    """

    def __init__(self, parent_window):
        Frame.__init__(self, parent_window)
        # Configure the window
        self.configure(background="white")
        # Create the header
        header = Label(self, text=get_project_name(), width=55, font=("Arial", 20), height=5)
        header.grid()
        header.configure(background="white")


class CustomButton(Button):
    """
    Generic button template to use them throughout the screens
    """

    def __init__(self, parent_window, text, _function, row, columnspan=None, sticky=None, column=None, height=2,
                 foreground="black"):
        Button.__init__(self, parent_window, command=_function, text=text, font=("Arial", 15), borderwidth=0,
                        height=height, highlightthickness=0, background="white", foreground=foreground)
        self.grid(row=row, columnspan=columnspan, sticky=sticky, column=column)


class CustomLabel(Label):
    """
    Generic label template to use them throughout the screens
    """

    def __init__(self, parent_window, text, row, column, rowspan=None, columnspan=None, sticky=None):
        Label.__init__(self, parent_window, text=text, font=("Arial", 15))
        self.grid(row=row, column=column, rowspan=rowspan, columnspan=columnspan, sticky=sticky)


class CustomRadiobutton(Radiobutton):
    """
    Generic radio button template to use them throughout the screens
    """

    def __init__(self, parent_window, text, row, column, sticky, variable, value):
        Radiobutton.__init__(self, parent_window, text=text, font=("Arial", 13), variable=variable, value=value)
        self.grid(row=row, column=column, sticky=sticky)


================================================
FILE: src/GUI/hard_coded_texts.py
================================================
"""
       This file contains some methods which return hard-coded texts and constant texts
"""


# Window title, size and background color
project_title = "Peniot"
window_size = "800x650"
window_background_color = "white"
mandatory_fields_background_color = "red"

# Button labels
start_testing_label = "Start Testing"
extend_peniot_label = "Extend Peniot"
view_captured_packets = "View Captured Packets"
help_label = "Help"
back_to_menu_label = "Back to menu"
about_us_label = "About us"
footer_label = "2018-2019 CENG Term Project"
go_to_input_page = "Go to input page"
back_to_attack_selection_page = "Back to attacks selection"
back_to_attack_suite_page = "Back to the attack suite page"
back_to_attack_details = "Back to attacks details"
perform_attack = "Perform the attack"
load_default_parameters = "Load default parameters"
stop_attack_go_back = "Stop the attack and go back"
generate_report = "Generate report"

# Settings for logger
logging_format = "%(asctime)s:%(levelname)s:%(name)s:%(message)s"
logger_name = "Attack Reporting Page"

# Color for the console
console_background_color = "black"
console_foreground_color = "white"


def get_project_name():
    return "Peniot:Penetration testing tool for Internet of Things"


def get_about_us():
    return "The developers of PENIOT project are the following : \n" \
           "    Berat Cankar\n" \
           "    Bilgehan Bingol\n" \
           "    Dogukan Cavdaroglu\n" \
           "    Ebru Celebi\n" \
           "The supervisor of the project is :\n" \
           "    Asst. Prof. Dr. Pelin Angin "


def get_help():
    return "PENIOT enables users to test their IoT devices.For now,it supports the \n" \
           "following protocols:\n" \
           "    * MQTT\n" \
           "    * CoAP\n" \
           "    * BLE\n" \
           "    * AMQP\n" \
           "For each protocol, there is at least one attack.After selecting protocol\n" \
           "and attacks, you just need to provide some information about your\n" \
           "device or network.PENIOT will handle the rest while you are resting.\n" \
           "At the end, it will provide a report which states the results of the performed attack.\n"


def get_extension_help():
    return "Extension utility which enables you to export internal structure of entities\n" \
           "(Attack, AttackSuite and Protocol) or import your implemented entities into\n" \
           "Peniot so that you can simulate/execute your own implementations."


def get_logger_name():
    """
    Returns the logger name we will use for reporting the attack results
    """
    return logger_name


================================================
FILE: src/GUI/tkinter.py
================================================
import logging
import tkFileDialog
import ttk
from threading import Timer

from custom_widgets import *
from hard_coded_texts import *
from utils import *
from Entity.attack import Attack
from Entity.attack_suite import AttackSuite
from Utils import CommonUtil
from Utils.ExtendUtil.export_util import ExportUtil, ExportOptions
from Utils.ExtendUtil.import_util import ImportUtil, ImportOptions
from Utils.ReportUtil.report_generator import GenerateReport

root = None


class HomePage(Frame):
    """
    This is the first page which users see when they start the application.
    It simply contains a menu with the following options:
        - Start Testing
        - Help
        - About us
    """

    def __init__(self, parent_window):
        Frame.__init__(self, parent_window)
        # Configure the window
        self.configure(background=window_background_color)
        # Create the header
        Header(self).grid(row=0)
        # Start testing button
        CustomButton(self, start_testing_label, lambda: change_frame(self, ProtocolsPage(root)), 1)
        # Extension button
        CustomButton(self, extend_peniot_label, lambda: change_frame(self, ExtensionPage(root)), 2)
        # View captured packets button
        CustomButton(self, view_captured_packets, lambda: change_frame(self, ViewCapturedPackets(root)), 3)
        # Help button
        CustomButton(self, help_label, lambda: change_frame(self, Help(root)), 4)
        # About us button
        CustomButton(self, about_us_label, lambda: change_frame(self, AboutUs(root)), 5)
        # Footer
        footer = Label(self, text=footer_label, width=55, font=("Arial", 20), height=5)
        footer.grid(row=6)
        footer.configure(background=window_background_color)
        # Make it visible
        self.grid()


class AboutUs(Frame):
    """
    This page displays information about the developers of the project.
    """

    def __init__(self, parent_window):
        Frame.__init__(self, parent_window)
        # Configure the window
        self.configure(background=window_background_color)
        # Create the header
        Header(self).grid(row=0)
        # Information about us
        info_about_us = Label(self, text=get_about_us(), width=55, anchor=W, justify=LEFT, font=("Arial", 15),
                              height=10)
        info_about_us.grid(row=1)
        info_about_us.configure(background=window_background_color)
        # Back to menu button
        CustomButton(self, back_to_menu_label, lambda: change_frame(self, HomePage(root)), 2)
        # Make it visible
        self.grid()


class Help(Frame):
    """
    This page displays information about the tool.
    """

    def __init__(self, parent_window):
        Frame.__init__(self, parent_window)
        # Configure the window
        self.configure(background=window_background_color)
        # Create the header
        Header(self).grid(row=0)
        # Information about us
        info_about_us = Label(self, text=get_help(), width=70, anchor=W, justify=LEFT, font=("Arial", 15), height=10)
        info_about_us.grid(row=1)
        info_about_us.configure(background=window_background_color)
        # Back to menu button
        CustomButton(self, back_to_menu_label, lambda: change_frame(self, HomePage(root)), 2)
        # Make it visible
        self.grid()


class ViewCapturedPackets(Frame):
    """
    This page enables users to download captured packets.
    """
    CAPTURED_PACKET_PATH = os.path.dirname(os.path.abspath(__file__))[:-4] + "/captured_packets/"

    def __init__(self, parent_window):
        Frame.__init__(self, parent_window)
        # Generate content
        self.generate_content()
        # Make it visible
        self.grid()

    def generate_content(self):
        """
        This method is used to generate rows representing the files
        """
        # Destroy the existing widgets
        for widget in self.winfo_children():
            widget.destroy()
        # Configure the window
        self.configure(background=window_background_color)
        # Create the header
        Header(self).grid(row=0, columnspan=4)
        # Row index
        row_index = 1
        # Get the file names
        file_names = get_captured_packet_files()
        for file_name in file_names:
            # Remove .txt part
            file_name_without_extension = file_name[:-4]
            info = file_name_without_extension.split("_")
            # Protocol name
            protocol_name = Label(self, text=info[0])
            protocol_name.grid(row=row_index, column=0)
            protocol_name.configure(background=window_background_color)
            # Date
            date = Label(self, text=info[1] + " " + info[2])
            date.grid(row=row_index, column=1)
            date.configure(background=window_background_color)
            # Download button
            CustomButton(self, "Download", lambda file_name=file_name: self.download_file(file_name), row_index, None,
                         None, 2)
            # Delete button
            print file_name
            CustomButton(self, "Delete", lambda file_name=file_name: self.delete_captured_packets_file(file_name),
                         row_index, None,
                         None, 3)
            # Increment row index
            row_index = row_index + 1
        # Back to menu button
        CustomButton(self, back_to_menu_label, lambda: change_frame(self, HomePage(root)), row_index, 3)
        self.grid()

    def delete_captured_packets_file(self, file_name):
        """ 
        This method is used to delete a captured packets file
        """
        os.remove(self.CAPTURED_PACKET_PATH + file_name)
        # Generate content
        self.generate_content()

    def download_file(self, file_name):
        """
        This methods is used to export the selected packets file.
        """
        # Get the directory
        directory_name = tkFileDialog.askdirectory(initialdir=os.getcwd(), title="Select directory to download packets")

        try:
            # Read the file
            packets_file = os.open(os.path.dirname(os.path.abspath(__file__))[:-4] + "/captured_packets/" + file_name,
                                   os.O_RDONLY)
            # Open a file
            new_file = os.open(directory_name + "/" + file_name, os.O_RDWR | os.O_CREAT)
            # Copy the file content
            while True:
                data = os.read(packets_file, 2048)
                if not data:
                    break
                os.write(new_file, data)
            # Close the files
            os.close(packets_file)
            os.close(new_file)
            # Create pop-up
            pop_up_window(root, None, "Downloaded successfully")
        except Exception as e:
            if len(directory_name) == 0:
                return
            else:
                pop_up_window(root, None, "Download operation is failed because of\n{0}".format(e), justify=CENTER)


class ProtocolsPage(Frame):
    """
    This page displays the possible options for protocols.
    """

    def __init__(self, parent_window):
        Frame.__init__(self, parent_window)
        # Configure the window
        self.configure(background=window_background_color)
        # Create the header
        Header(self).grid(row=0, columnspan=2)
        # Get protocols
        protocols = get_protocols()
        # Current row index
        row_index = 1
        # Create a button for each protocols
        for protocol in protocols:
            # Create the button for the protocol
            CustomButton(self, protocol["protocol"].get_protocol_name(),
                         lambda selected_protocol=protocol: change_frame(self, AttacksPage(root,
                                                                                           selected_protocol)),
                         row_index, None, E, 0)

            CustomButton(self, "?",
                         lambda selected_protocol=protocol: pop_up_window(root,
                                                                          selected_protocol[
                                                                              "protocol"].get_protocol_name(),
                                                                          selected_protocol[
                                                                              "protocol"].get_definition()),
                         row_index, None, W, 1)
            # Increment the row index
            row_index = row_index + 1
        # Back to menu button
        CustomButton(self, back_to_menu_label, lambda: change_frame(self, HomePage(root)), row_index, 2)
        # Make it visible
        self.grid()


class ExtensionPage(Frame):
    """
    This page displays the extension options and help button that explains how to extend for PENIOT.
    """

    def __init__(self, parent_window):
        Frame.__init__(self, parent_window)
        # Configure the window
        self.configure(background=window_background_color)
        # Create the header
        Header(self).grid(row=0, columnspan=2)
        # Current row index
        row_index = 1

        # Export button
        CustomButton(self, "Export", lambda: change_frame(self, ExportPage(root)), row_index, None, E, 0)
        row_index = row_index + 1

        # Import button
        CustomButton(self, "Import", lambda: change_frame(self, ImportPage(root)), row_index, None, E, 0)
        row_index = row_index + 1

        # Help button
        CustomButton(self, help_label, lambda: change_frame(self, ExtensionHelp(root)), row_index, 2)
        row_index = row_index + 1

        # Back to menu button
        CustomButton(self, back_to_menu_label, lambda: change_frame(self, HomePage(root)), row_index, 2)

        # Make it visible
        self.grid()


class ImportPage(Frame):
    """
    These pages make the user select import or export options
    """

    def __init__(self, parent_window):
        Frame.__init__(self, parent_window)
        self.file_path = ""
        self.option = ImportOptions.ATTACK_OR_ATTACK_SUITE
        # Configure the window
        self.configure(background=window_background_color)
        # Create the header
        Header(self).grid(row=0, columnspan=4)

        row_index = 1

        CustomLabel(self, text="Option:", row=row_index, column=0, sticky=E)
        option_combo_box = ttk.Combobox(self, values=["Protocol", "Attack or Attack Suite"], font=("Arial", 15))
        option_combo_box.grid(row=row_index, column=1, sticky=W + E, columnspan=2)
        option_combo_box.bind("<<ComboboxSelected>>",
                              lambda x: combobox_element_changed(option_combo_box, protocol_name_label,
                                                                 self.protocol_name_combo_box))
        option_combo_box.current(1)
        row_index = row_index + 1

        protocol_name_label = CustomLabel(self, text="Protocol Name:", row=row_index, column=0, sticky=E)
        self.protocol_name_combo_box = ttk.Combobox(self, font=("Arial", 15))
        self.protocol_name_combo_box.grid(row=row_index, column=1, sticky=W + E, columnspan=2)
        self.protocol_name_combo_box.bind("<<ComboboxSelected>>",
                                          lambda x: combobox_protocol_name_changed(self.protocol_name_combo_box))
        row_index = row_index + 1

        # Names of available protocols
        self.protocol_names = []
        # Get protocol names
        self.get_protocol_names()

        self.selected_protocol = self.protocol_names[0]

        CustomLabel(self, text="File Path:", row=row_index, column=0, sticky=E)
        file_path_entry = Entry(self, font=("Arial", 15))
        file_path_entry.grid(row=row_index, column=1, sticky=W + E, columnspan=2)

        CustomButton(self, "Select File", lambda: get_file_path(file_path_entry), row_index, None, W, 3, height=1)
        row_index = row_index + 1

        CustomButton(self, "Import",
                     lambda: self.import_button_click(file_path_entry.get(), self.option, self.selected_protocol),
                     row_index, None, W, 3)

        CustomButton(self, back_to_menu_label, lambda: change_frame(self, ExtensionPage(root)), row_index, None, E, 0)

        for col in range(5):
            self.columnconfigure(col, weight=1)
        for row in range(8):
            self.rowconfigure(row, weight=1)

        self.grid()

        def get_file_path(entry):
            self.file_path = tkFileDialog.askopenfilename()
            entry.delete(0, END)
            entry.insert(0, self.file_path)

        def combobox_element_changed(combo, label, combobox):
            if combo.get() == "Protocol":
                label.grid_forget()
                combobox.grid_forget()
                self.option = ImportOptions.PROTOCOL
            else:
                label.grid(row=2, column=0, sticky=E)
                combobox.grid(row=2, column=1, sticky=W + E, columnspan=2)
                self.option = ImportOptions.ATTACK_OR_ATTACK_SUITE

        def combobox_protocol_name_changed(combo):
            self.selected_protocol = combo.get()

    def import_button_click(self, file_path, option, selected_protocol):
        try:
            if not os.path.isfile(file_path):
                pop_up_window(root, None, "Please select a valid file.")
                return
            ImportUtil.import_action(file_path, option, selected_protocol)
            # Update the protocol list since the user may import a new protocol
            self.get_protocol_names()
            pop_up_window(root, None, "Files are imported successfully")

        except Exception as e:
            pop_up_window(root, None, "Import operation is failed because of\n{0}".format(e), justify=CENTER)

    def get_protocol_names(self):
        protocols = get_protocols()
        self.protocol_names = []
        for protocol in protocols:
            self.protocol_names.append(protocol["protocol"].get_protocol_name())
        self.protocol_name_combo_box['values'] = self.protocol_names


class ExportPage(Frame):
    def __init__(self, parent_window):
        Frame.__init__(self, parent_window)
        # Configure the window
        self.configure(background=window_background_color)
        # Create the header
        Header(self).grid(row=0, columnspan=4)

        s = ttk.Style()
        s.configure(".", font=("Arial", 15))

        tab_control = ttk.Notebook(self)
        attack_tab = TabFrame(tab_control, ExportOptions.ATTACK)
        tab_control.add(attack_tab, text="Attack")

        attacksuite_tab = TabFrame(tab_control, ExportOptions.ATTACK_SUITE)
        tab_control.add(attacksuite_tab, text="Attack Suite")

        protocol_tab = TabFrame(tab_control, ExportOptions.PROTOCOL)
        tab_control.add(protocol_tab, text="Protocol")

        tab_control.grid(row=1, column=0, columnspan=4, rowspan=3, sticky=W + E + S + N)
        CustomButton(self, back_to_menu_label, lambda: change_frame(self, ExtensionPage(root)), 7, None, E, 1)
        self.grid()


class TabFrame(Frame):
    def __init__(self, parent_window, option):
        Frame.__init__(self, parent_window)
        # Configure the window
        self.configure(background=window_background_color)
        self.file_path = None
        row = 0
        CustomLabel(self, text="Protocol Name:", row=row, column=1, sticky=E)
        protocol_name_entry = Entry(self, font=("Arial", 15))
        protocol_name_entry.grid(row=row, column=2, sticky=W + E, columnspan=2)
        row = row + 1

        attack_name_entry = Entry(self, font=("Arial", 15))
        if option == ExportOptions.ATTACK:
            CustomLabel(self, text="Attack Name:", row=row, column=1, sticky=E)
            attack_name_entry.grid(row=row, column=2, sticky=W + E, columnspan=2)
            row = row + 1

        attack_suite_name_entry = Entry(self, font=("Arial", 15))
        if option == ExportOptions.ATTACK_SUITE:
            CustomLabel(self, text="Attack Suite Name:", row=row, column=1, sticky=E)
            attack_suite_name_entry.grid(row=row, column=2, sticky=W + E, columnspan=2)
            row = row + 1

        CustomLabel(self, text="File Path:", row=row, column=1, sticky=E)
        file_path_entry = Entry(self, font=("Arial", 15))
        file_path_entry.grid(row=row, column=2, sticky=W + E, columnspan=2)

        CustomButton(self, "Select File Path", lambda: get_file_path(file_path_entry), row, None, W, 4, height=1)
        row = row + 1

        CustomLabel(self, text="File Name:", row=row, column=1, sticky=E)
        file_name_entry = Entry(self, font=("Arial", 15))
        file_name_entry.grid(row=row, column=2, sticky=W + E, columnspan=2)
        row = row + 1

        rad_var = IntVar()
        for export_index, export_option in enumerate(ExportUtil.get_export_texts_and_values()):
            export_value = export_option.get("value")
            if export_index == 0:
                rad_var.set(export_value)
            CustomRadiobutton(self, text=export_option.get("text"), row=row, column=2, sticky=W + S, variable=rad_var,
                              value=export_value)
            row = row + 1

        CustomButton(self, "Export",
                     lambda: export_button_click(protocol_name=protocol_name_entry.get(),
                                                 attack_name=attack_name_entry.get(),
                                                 attack_suite_name=attack_suite_name_entry.get(),
                                                 file_path=file_path_entry.get(),
                                                 file_name=file_name_entry.get(), extension=rad_var.get(),
                                                 option=option),
                     row, None, W, 4)

        for col in range(5):
            self.columnconfigure(col, weight=1)
        for row in range(8):
            self.rowconfigure(row, weight=1)

        self.grid()

        def get_file_path(entry):
            self.file_path = tkFileDialog.askdirectory()
            entry.delete(0, END)
            entry.insert(0, self.file_path)

        def export_button_click(protocol_name, attack_name, attack_suite_name, file_path, file_name, extension, option):
            try:
                if not os.path.exists(file_path):
                    pop_up_window(root, None, "Please enter a valid file path.")
                    return
                ExportUtil.export_action(protocol_name=protocol_name,
                                         attack_name=attack_name,
                                         attack_suite_name=attack_suite_name,
                                         file_path=file_path,
                                         file_name=file_name, extension=extension,
                                         option=option)
                pop_up_window(root, None, "Files are exported successfully.")
            except Exception as e:
                pop_up_window(root, None, "Export operation is failed because of\n{0}".format(e), justify=CENTER)


class ExtensionHelp(Frame):
    """
    This page gives detailed information on how to extend PENIOT.
    """

    def __init__(self, parent_window):
        Frame.__init__(self, parent_window)
        # Configure the window
        self.configure(background=window_background_color)
        # Create the header
        Header(self).grid(row=0)
        # information about us
        extension_info = Label(self, text=get_extension_help(), width=70, justify=CENTER, font=("Arial", 15), height=10)
        extension_info.grid(row=1)
        extension_info.configure(background=window_background_color)
        # Back to menu button
        CustomButton(self, back_to_menu_label, lambda: change_frame(self, ExtensionPage(root)), 2)
        # Make it visible
        self.grid()


class AttacksPage(Frame):
    """
    This page displays the possible attacks for the selected protocol.
    """

    def __init__(self, parent_window, protocol):
        Frame.__init__(self, parent_window)
        # Configure the window
        self.configure(background=window_background_color)
        # Set the selected protocol
        self.protocol = protocol
        # Create the header
        Header(self).grid(row=0)
        # Get protocol's attack suites
        attacks_suites = get_attacks(protocol["package_name"])
        # current row index
        row_index = 1
        # Create a button for each attack
        for attack_suite in attacks_suites:
            if isinstance(attack_suite, Attack):
                # Create the button for the attack
                CustomButton(self, attack_suite.get_attack_name(),
                             lambda selected_attack=attack_suite: change_frame(self,
                                                                               AttackDetailsPage(root,
                                                                                                 self.protocol,
                                                                                                 selected_attack,
                                                                                                 None)),
                             row_index)
                # Increment the row index
                row_index = row_index + 1
            elif isinstance(attack_suite, AttackSuite):
                # Create the button for the attack suite
                CustomButton(self, attack_suite.get_attack_suite_name(),
                             lambda selected_attack_suite=attack_suite: change_frame(self,
                                                                                     AttackSuiteDetailsPage(root,
                                                                                                            self.protocol,
                                                                                                            selected_attack_suite)),
                             row_index)
                # Increment the row index
                row_index = row_index + 1
        if not is_default_protocol(self.protocol["protocol"].get_protocol_name()):
            # Back to attack selection page button
            CustomButton(self, "Delete Protocol", lambda: self.delete_protocol(), row_index, foreground="red")
        row_index = row_index + 1
        # Back to menu button
        CustomButton(self, back_to_menu_label, lambda: change_frame(self, ProtocolsPage(root)), row_index)
        # Make it visible
        self.grid()

    def delete_protocol(self):
        is_successful = delete_protocol(self.protocol["protocol"].get_protocol_name())
        if is_successful:
            change_frame(self, ProtocolsPage(root))


class AttackSuiteDetailsPage(Frame):
    """
        This page displays the details of the selected attack suite.
    """

    def __init__(self, parent_window, protocol, attack_suite):
        Frame.__init__(self, parent_window)
        # Configure the window
        self.configure(background=window_background_color)
        # Set the selected protocol
        self.protocol = protocol
        # Set the selected attack suite
        self.attack_suite = attack_suite
        # Create the header
        Header(self).grid(row=0, columnspan=2)
        # row index
        row_index = 1
        # Create buttons for attacks
        for attack_in_suite in attack_suite.get_attacks():
            # Create the button for the attack
            CustomButton(self, attack_in_suite.get_attack_name(),
                         lambda selected_attack=attack_in_suite: change_frame(self,
                                                                              AttackDetailsPage(root, self.protocol,
                                                                                                selected_attack,
                                                                                                attack_suite)),
                         row_index, 2)
            # Increment row index
            row_index = row_index + 1
        # Back to attack selection page button
        CustomButton(self, back_to_attack_selection_page, lambda: change_frame(self, AttacksPage(root, self.protocol)),
                     row_index, 2)
        # Make it visible
        self.grid()


class AttackDetailsPage(Frame):
    """
        This page displays the details of the selected attack.
    """

    def __init__(self, parent_window, protocol, attack, attack_suite):
        Frame.__init__(self, parent_window)
        # Configure the window
        self.configure(background=window_background_color)
        # Set the selected protocol
        self.protocol = protocol
        # Set the attack suite
        self.attack_suite = attack_suite
        # Set the selected attack
        self.attack = attack
        # Create the header
        Header(self).grid(row=0, columnspan=2)
        # Definition of the attack
        attack_definition = Label(self, text=self.attack.get_definition(), width=70, justify=CENTER,
                                  font=("Arial", 15),
                                  height=10)
        attack_definition.grid(row=1)
        attack_definition.configure(background=window_background_color)
        # Back to the previous page
        if self.attack_suite is None:
            # Back to attack selection page button
            CustomButton(self, back_to_attack_selection_page,
                         lambda: change_frame(self, AttacksPage(root, self.protocol)),
                         2, None, W)
        else:
            # Back to attack suite details page button
            CustomButton(self, back_to_attack_suite_page,
                         lambda: change_frame(self, AttackSuiteDetailsPage(root, self.protocol, attack_suite)),
                         2, None, W)
        if not is_default_protocol(self.protocol["protocol"].get_protocol_name()):
            # Delete attack button
            CustomButton(self, "Delete Attack", lambda: self.delete_attack(), 2, foreground="red")
        # Go to input page button
        CustomButton(self, go_to_input_page,
                     lambda: change_frame(self, InputsPage(root, self.protocol, self.attack, self.attack_suite)),
                     2, None, E)
        # Make it visible
        self.grid()

    def delete_attack(self):
        is_successful = delete_attack(self.attack.get_attack_name())
        if is_successful:
            # Back to the previous page
            if self.attack_suite is None:
                # Back to attack selection page button
                change_frame(self, AttacksPage(root, self.protocol))
            else:
                # Back to attack suite details page button
                change_frame(self, AttackSuiteDetailsPage(root, self.protocol, self.attack_suite))


class InputsPage(Frame):
    """
        This page is used to get inputs from the user.
    """

    def __init__(self, parent_window, protocol, attack, attack_suite):
        Frame.__init__(self, parent_window)
        # Configure the window
        self.configure(background=window_background_color)
        # Set the selected protocol
        self.protocol = protocol
        # Set the attack suite
        self.attack_suite = attack_suite
        # Set the selected attack
        self.attack = attack
        # file path if necessary
        self.file_path = ""
        # Create the header
        Header(self).grid(row=0, columnspan=3)
        # Inputs of the attack
        row_index = 1
        # Get inputs
        self.inputs = self.attack.get_inputs()
        # Create an empty list for input values
        self.input_values = []
        # For each input, create a Label-Entity pair
        for _input in self.inputs:
            label = Label(self, text=_input.get_label_name())
            label.grid(row=row_index)
            label.configure(background=window_background_color)

            # Create a StringVar for the input
            string_var = StringVar(value=str(_input.get_value()))
            # Add it to the list
            self.input_values.append(string_var)
            # Create an entry for the input
            if _input.is_secret():
                # Bind it to the string var
                entry = Entry(self, show="*", textvariable=string_var)
            else:
                # Bind it to the string var
                entry = Entry(self, textvariable=string_var)
            entry.grid(row=row_index, column=1)
            if _input.is_mandatory():
                entry.configure(background=mandatory_fields_background_color)
            else:
                entry.configure(background=window_background_color)
            if _input.is_from_captured_packets():
                CustomButton(self, "Select File", lambda: self.get_file_path(entry), row_index, None, W, 2,
                             height=1)
            # Increment the row index
            row_index = row_index + 1

        # Back to attack details page button
        CustomButton(self, back_to_attack_details,
                     lambda: change_frame(self,
                                          AttackDetailsPage(root, self.protocol, self.attack, self.attack_suite)),
                     row_index, None,
                     None, 0)
        # Perform the attack page button
        CustomButton(self, perform_attack, lambda: self.navigate_to_attack_reporting_page(), row_index, None,
                     None, 1)

        # Set default parameters of the current protocol
        row_index += 1
        CustomButton(self, load_default_parameters, lambda: (
            self.attack.load_default_parameters(),
            self.load_default_parameters_to_variables()
        ), row_index, 2, None, None)
        # Make it visible
        self.grid()

    def get_file_path(self, entry):
        path_to_captured_packets = os.path.dirname(os.path.abspath(__file__)) + "/../captured_packets"
        self.file_path = tkFileDialog.askopenfilename(initialdir=path_to_captured_packets,
                                                      filetypes=[("pcap-files", "BLE*.pcap")])
        entry.delete(0, END)
        entry.insert(0, self.file_path)

    def set_input_values(self):
        """
        This function sets the values of the inputs using the self.input_values field.
        """
        for i in range(0, len(self.inputs)):
            # Get the input from the user
            value = self.input_values[i].get()
            # If this is a mandatory field, but user did not provide any value for it,
            # Then simply create a pop-up explaining the situation
            if self.inputs[i].is_mandatory() and value.strip() is "":
                pop_up_window(root, "Input Validation",
                              "Please, be sure that you provide valid values for the mandatory fields.")
                # input validation failed
                return False
            # If the user provide a value for the input, use it
            # Otherwise, use the default one
            if value is not "":
                # convert string to the expected type
                try:
                    value = InputsPage._check_value_type(self.inputs[i], value)
                except Exception:
                    return False
            else:
                value = self.inputs[i].get_default_value()
            # Set the value
            self.inputs[i].set_value(value)
        return True

    def navigate_to_attack_reporting_page(self):
        """
        This function is called when we want to start testing
        """
        # Set the input values
        is_valid = self.set_input_values()
        # If we have valid inputs, then continue with the attack
        if is_valid:
            # Change page to the attack reporting page
            change_frame(self, AttackReportingPage(root, self.protocol, self.attack, self.attack_suite))
        else:
            pop_up_window(root, "Input Validation",
                          "Please, be sure that you provide valid values for input fields.")

    def load_default_parameters_to_variables(self):
        for _input_index, _input in enumerate(self.inputs):
            self.input_values[_input_index].set(str(_input.get_value()))

    @staticmethod
    def _check_value_type(_input, _value):
        try:
            if _input.type == bool:
                return CommonUtil.get_boolean_value(_value)
            else:
                return _input.type(_value)
        except TypeError as _:
            raise _


class AttackReportingPage(Frame):
    """
    This page is used to show the results of the attack.
    """

    def __init__(self, parent_window, protocol, attack, attack_suite):
        Frame.__init__(self, parent_window)
        # Configure the window
        self.configure(background=window_background_color)
        # Set the selected protocol
        self.protocol = protocol
        # Set the attack suite
        self.attack_suite = attack_suite
        # Set the selected attack
        self.attack = attack
        # Create the header
        Header(self).grid(row=0, columnspan=2)
        # Create the console
        self.console = Text(self)
        self.console.grid(row=1, columnspan=2, sticky="nsew")
        self.console.configure(background=console_background_color, foreground=console_foreground_color, wrap='word')
        # Change the default output stream
        sys.stdout = self
        # Change the default input stream
        sys.stdin = self

        # Create a stream handler
        stream_handler = logging.StreamHandler(self)
        stream_handler.setLevel(logging.INFO)
        # Create a formatter
        formatter = logging.Formatter(logging_format)
        stream_handler.setFormatter(formatter)
        # Create a logger
        self.logger = logging.getLogger(logger_name)
        self.logger.addHandler(stream_handler)
        # Start the testing after 1 seconds. Create a Timer object so we can stop execution later
        self.timer = Timer(1.0, self.perform_attack)
        self.timer.start()

        # Stop the attack and back to menu button
        CustomButton(self, stop_attack_go_back, lambda: self.attack_stopper(), 2, 1, None, 0)
        CustomButton(self, generate_report, lambda: self.report_generator(), 2, 1, None, 1)
        # Make it visible
        self.grid()

    # Override write function
    def write(self, text):
        self.console.insert(END, str(text))
        # Change the state of the console to Disabled so that nobody can write
        # Update the tasks so that the user can see the logs
        self.update_idletasks()

    # Override readline function
    def readline(self):
        return_value = None
        while return_value is None:
            # Get the return value
            return_value = self.get_number()
            # continue until we have a valid return value
            if return_value is None:
                continue
            return return_value

    # Used to get user selection for BLE sniffing attack
    def get_number(self):
        return_value = None
        text = self.console.get(1.0, END)[::-1].encode("ascii")

        if text[0] == '\n' and text[1] == '\n':
            for i in text:
                if i == ">":
                    break
                elif str.isdigit(i):
                    if return_value is None:
                        return_value = ""
                    return_value = i + return_value
        return return_value

    def perform_attack(self):
        # Start message
        self.logger.info("Performing the attack")
        # Run the attack
        self.attack.run()
        # Exit message
        self.logger.info("Attack is performed successfully")

    # Define the attack stopper function to end attacks
    def attack_stopper(self):
        # Remove handlers
        self.attack.stop_attack()  # Call the underlying attack's own stopper
        for handler in self.logger.handlers:
            handler.close()
            self.logger.removeHandler(handler)
        # There will be some more changes here to close open pipes and so on.
        # Then, change the frame and go back
        change_frame(self, InputsPage(root, self.protocol, self.attack, self.attack_suite))

    def report_generator(self):
        directory = tkFileDialog.askdirectory()
        try:
            if type(directory) == str and len(directory) > 0:
                directory = directory if directory.endswith('/') else directory + '/'
                GenerateReport.generate_pdf_from_text(
                    self.protocol['protocol'].get_protocol_name(),
                    self.attack.get_attack_name(),
                    self.console.get("1.0", END),
                    directory
                )
                pop_up_window(root, None, 'Report is successfully generated.', justify=CENTER)
        except Exception as e:
            pop_up_window(root, None, 'Report cannot be generated properly.\nPlease check given directory path.',
                          justify=CENTER)


def run():
    # Create the root window
    root = create_root()
    # Create HomePage and make it the current window
    HomePage(root).tkraise()
    root.mainloop()


================================================
FILE: src/GUI/utils.py
================================================
# This file contains methods which are used in the GUI.
import importlib
import inspect
import os
import pkgutil
import shutil

from Tkinter import *
from hard_coded_texts import project_title, window_size, window_background_color
from Utils.ExtendUtil.import_util import ImportUtil

# list of default protocols
DEFAULT_PROTOCOLS = ["MQTT", "CoAP", "AMQP", "BLE"]


def is_default_protocol(protocol_name):
    """
    Check whether the given protocol is default or not
    """
    if DEFAULT_PROTOCOLS.__contains__(protocol_name):
        return True
    return False


def delete_protocol(protocol_name):
    """
    Deletes the given protocol
    """
    path_to_protocol = os.path.dirname(os.path.abspath(__file__)) + "/../protocols/" + protocol_name
    shutil.rmtree(path_to_protocol)
    return True


def delete_attack(attack_name):
    """
    Deletes the given attack
    """
    # Get the protocol name
    protocol_name = attack_name[:attack_name.index(" ")]
    # Get the attack real name
    # Remove protocol name
    attack_name = attack_name[attack_name.index(" ") + 1:]
    # Remove 'Attack' label at the end
    attack_name = attack_name[:attack_name.index(" ")]

    # Delete the attack
    path_to_attack = os.path.dirname(
        os.path.abspath(__file__)) + "/../protocols/" + protocol_name + "/attacks/" + attack_name
    shutil.rmtree(path_to_attack)
    return True


def pop_up_window(root, protocol_name, definition, justify=LEFT):
    """
    A pop up message generator.
    """
    popup = Toplevel(root)
    # Prevent pop-up from resizing
    popup.resizable(False, False)
    popup.wm_title(protocol_name)
    label = Label(popup, text=definition, anchor=W, font=("Arial", 10), justify=justify, wraplength=800)
    # A pop-up with protocol name on top and definition below
    label.pack(side="top", fill="both", pady=10)
    button1 = Button(popup, text="OK", command=popup.destroy)
    button1.pack(expand=True, fill=BOTH)
    # Prohibits any other window to accept events
    popup.grab_set()
    # Center the window
    center_widget(popup)
    popup.mainloop()


def get_protocols():
    """
    it simply searches for the subclasses of Protocol class and returns the all protocols
    """
    # Available protocols
    protocols = []
    # Base package to start searching for protocols
    packages = ["src.protocols"]
    # Continue to search until no package is available
    while len(packages) > 0:
        # Get the package
        package = packages.pop()
        # Get the package module
        package_module = importlib.import_module(package)
        prefix = package_module.__name__ + "."
        for finder, name, ispkg in pkgutil.iter_modules(package_module.__path__, prefix):
            # If it is a package, add it to the package list
            if ispkg:
                packages.append(name)
            else:
                # For some modules, we may have errors, skip those errors for now
                try:
                    mod = importlib.import_module(name)
                except ImportError:
                    continue
                for tname, klass in inspect.getmembers(mod):
                    if inspect.isclass(klass):
                        # If the class inherits from Protocol class, simply add it to the protocol list
                        if "Protocol" in [c.__name__ for c in inspect.getmro(klass)[1:]]:
                            protocols.append({"package_name": package, "protocol": klass()})
    return protocols


def get_attacks(package_name):
    """
    it simply searches for the subclasses of Attack class in the given package and returns the attacks
    """
    # Available attack names
    attack_names = []
    # Available attack suites
    attack_suites = []
    # Available attacks
    attacks = []
    # Base package to start searching for protocols
    packages = [package_name + ".attacks"]
    # Continue to search until no package is available
    while len(packages) > 0:
        # Get the package
        package = packages.pop()
        package_module = importlib.import_module(package)
        prefix = package_module.__name__ + "."
        for finder, name, ispkg in pkgutil.iter_modules(package_module.__path__, prefix):
            # If it is a package, add it to the package list
            if ispkg:
                packages.append(name)
            else:
                try:
                    mod = importlib.import_module(name)
                except ImportError:
                    continue
                for tname, klass in inspect.getmembers(mod):
                    if inspect.isclass(klass):
                        # If the class inherits from Attack class, simply add it to the attack list
                        if "Attack" in [c.__name__ for c in inspect.getmro(klass)[1:]]:
                            attack = klass()
                            # check whether we have this attack in the list or not
                            if not attack_names.__contains__(attack.get_attack_name()):
                                attacks.append(attack)
                                attack_names.append(attack.get_attack_name())
                        # If the class inherits from AttackSuite class, simply add it to the Attack suite list
                        if "AttackSuite" in [c.__name__ for c in inspect.getmro(klass)[1:]]:
                            attack_suite = klass()
                            attack_suites.append(attack_suite)
    # Remove attack names included in the attack suites
    for attack_suite in attack_suites:
        for attack in attack_suite.get_attacks():
            if attack_names.__contains__(attack.get_attack_name()):
                attack_names.remove(attack.get_attack_name())
    # Final list of available attacks
    available_attacks = []
    # Retrieve attack whose name is included in the attack name list
    for attack in attacks:
        for attack_name in attack_names:
            if attack.get_attack_name() == attack_name:
                available_attacks.append(attack)
                break
    # Add attack suites to the available attacks
    for attack_suite in attack_suites:
        available_attacks.append(attack_suite)
    return available_attacks


def get_captured_packet_files():
    """
    Retrieves the files containing saved captured packets
    """
    # Names of the files
    file_names = []
    # Search files in the src.captured_packets package
    path_to_package = os.path.dirname(os.path.abspath(__file__))[:-4] + "/captured_packets"
    for root, dirs, files in os.walk(path_to_package):
        for filename in files:
            # Only get .txt files
            if filename.endswith(".pcap") or filename.endswith(".txt"):
                file_names.append(filename)
    return file_names


def change_frame(old_frame, new_frame):
    """
    This function is used to change the frame.
    Firstly, we have to delete the old frame. Then, we start to use new one.
    """
    # Destroy old frame
    old_frame.grid_forget()
    old_frame.destroy()
    # New frame
    new_frame.tkraise()


def create_root():
    """
    It creates the root window.
    """
    # Create the root window
    root = Tk()
    # Root window related settings
    root.title(project_title)
    root.geometry(window_size)
    root.configure(background=window_background_color)
    root.resizable(False, False)
    # Center the window
    center_widget(root)

    startup_calls()
    root.protocol("WM_DELETE_WINDOW", lambda: shutdown_calls(root))

    return root


def center_widget(window):
    """
    Used to center the given window on the screen
    """
    # Render the window to get correct width and height
    window.update()
    # Make window invisible so that we will have a smooth transition from upper left side to center
    window.withdraw()
    # Get window size settings
    width_of_window = window.winfo_width()
    height_of_window = window.winfo_height()
    # Get screen size settings
    screen_width = window.winfo_screenwidth()
    screen_height = window.winfo_screenheight()
    # Calculate the x and y coordinates
    x_coordinate = (screen_width / 2) - (width_of_window / 2)
    y_coordinate = (screen_height / 2) - (height_of_window / 2)
    # Set the geometry
    window.geometry("%dx%d+%d+%d" % (width_of_window, height_of_window, x_coordinate, y_coordinate))
    # Make the window visible
    window.deiconify()


def startup_calls():
    """
    Initialize program dependent modules to make program prepared for all operations
    """
    ImportUtil.startup()


def shutdown_calls(root):
    """
    Register method callback to call necessary ending operations
    """
    ImportUtil.shutdown()
    root.destroy()


================================================
FILE: src/Utils/CommonUtil/__init__.py
================================================
"""
    Common Utilities
    It contains necessary functionalities used commonly in project.
"""

import datetime


def get_current_datetime_for_filename_format():
    return datetime.datetime.now().strftime("%Y-%m-%d_%H:%M:%S")


def get_current_datetime_for_report_format():
    return datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")


def get_boolean_value(bool_str):
    bool_str = str(bool_str)
    true_list = ["1", "true", "yes", "t", "y"]
    if bool_str.lower() in true_list:
        return True
    false_list = ["0", "false", "no", "f", "n"]
    if bool_str.lower() in false_list:
        return False
    raise TypeError("Invalid input for bool type!")



================================================
FILE: src/Utils/ExtendUtil/__init__.py
================================================
"""
    Extendability Utilities
    It contains necessary functionality used for importing and exporting scripts.
"""

================================================
FILE: src/Utils/ExtendUtil/export_attack_suite_template.py
================================================
#################################################################################
#                               IMPORTANT WARNING                               #
# This file is prepared to be guidance for you while implementing your protocol #
# attack or attack suite. You can extend PENIOT with your implementations by    #
# filling necessary fields properly, then you can perform what you have created.#
# To achieve this successfully, fill the following code segment carefully and   #
# keep compulsory code fields without changing their signatures so that PENIOT  #
# could extend itself with your code and work properly.                         #
#################################################################################

# Do not change any of the import statements, we will provide their contents to you
# Moreover, you do not need to export any other file than your attack suite
from Entity.attack_suite import AttackSuite


class _ATTACK_SUITE_COMBINED_NAME(AttackSuite):

    def __init__(self):
        attacks = [
            # List the wanted attack here to package them in a single entity
        ]

        # Auto generated attack suite name, you can change attack name to be displayed in graphical user interface
        attack_suite_name = "_ATTACK_SUITE_NAME"

        AttackSuite.__init__(self, attack_suite_name, attacks)


================================================
FILE: src/Utils/ExtendUtil/export_attack_template.py
================================================
#################################################################################
#                               IMPORTANT WARNING                               #
# This file is prepared to be guidance for you while implementing your protocol #
# attack or attack suite. You can extend PENIOT with your implementations by    #
# filling necessary fields properly, then you can perform what you have created.#
# To achieve this successfully, fill the following code segment carefully and   #
# keep compulsory code fields without changing their signatures so that PENIOT  #
# could extend itself with your code and work properly.                         #
#################################################################################

# Do not change any of the import statements, we will provide their contents to you
# Moreover, you do not need to export any other file than your attack
import logging

from Entity.attack import Attack


class _ATTACK_COMBINED_NAME(Attack):

    """
    Input Fields
    ** Important Note **: Each input must appear in the following lines of code for example, you can have following
    configuration in attack input list

    * For input format class, you need to fill following fields:
        1) Label of input to be displayed in GUI
        2) Name of member variable in this class, they need to match with following declarations
        3) If exist, default value. You may set it "" or None
        4) Type of input value to check/cast
    inputs = [
        InputFormat("Port Number", "port", self.port, int),
        InputFormat("Timeout", "timeout", self.timeout, float)
        ...
    ]

    * Then your attack class must have following member variables (Values are used for exemplifying)
    port = 8080
    timeout = 0.01
    ...
    """

    """
        Miscellaneous Members
        You can much more of them here to internally use
    """
    logger = None

    def __init__(self):
        inputs = [
            # You need to decide inputs to be taken from graphical user interface to conduct attack
        ]

        # Auto generated attack name, you can change attack name to be displayed in graphical user interface
        attack_name = "_ATTACK_NAME"
        # Auto generated attack description, you can change or add description for the new attack,
        # you can browse it from ? button nearby attacks in attack menu
        description = "_ATTACK_NAME Description"

        Attack.__init__(self, attack_name, inputs, description)

        # Simple logger and registration
        logging.basicConfig(level=logging.DEBUG, format="%(asctime)s:%(levelname)s:%(name)s:%(message)s")
        self.logger = logging.getLogger("_ATTACK_NAME")

    def pre_attack_init(self):
        # You can preliminary processes here such as client initialization, sniffing of packets or similar processes
        pass

    def run(self):
        # DO NOT REMOVE!
        # Necessary to initiate obtained input values
        super(_ATTACK_COMBINED_NAME, self).run()

        # Optional field if the attack needs preliminary procedure to be done
        self.pre_attack_init()

        # Implement attack here
        # The code segment below this line will be executed when you click Run Attack button
        """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
        "                    ||| Attack Content HERE |||                   "
        "                    vvv                     vvv                   "
        """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
        pass


================================================
FILE: src/Utils/ExtendUtil/export_protocol_template.py
================================================
#################################################################################
#                               IMPORTANT WARNING                               #
# This file is prepared to be guidance for you while implementing your protocol #
# attack or attack suite. You can extend PENIOT with your implementations by    #
# filling necessary fields properly, then you can perform what you have created.#
# To achieve this successfully, fill the following code segment carefully and   #
# keep compulsory code fields without changing their signatures so that PENIOT  #
# could extend itself with your code and work properly.                         #
#################################################################################

# Do not change any of the import statements, we will provide their contents to you
# Moreover, you do not need to export any other file than your protocol
from Entity.protocol import Protocol

"""
Note: You need to put your attack implementations to the attack directory that you
can find in root path of created archive. Do not forget this since we are parsing
that directory to import attack dynamically.
"""

class _PROTOCOL_NAME(Protocol):

    def __init__(self):
        # Auto generated name with respect to your protocol name input
        # If you want, you can change it, it will be showed in protocol menu
        protocol_name = "_PROTOCOL_NAME"

        # You should write definition of exported protocol
        # In case of writing, you can view protocol definition
        # by clicking question-mark-icon button while selecting target protocol
        protocol_definition = "_PROTOCOL_NAME Definition"

        # You need to add your attacks to this list in order to view and instantiate them while performing your attacks
        attack_suites = [
            # Add attacks or attack suites
        ]

        # Call parent constructor with following parameters
        # 1) Attack name to be displayed in GUI
        # 2) Attacks or attack suites to perform regression and penetration
        # 3) Protocol definition to be displayed in GUI
        Protocol.__init__(self, protocol_name, attack_suites, protocol_definition)



================================================
FILE: src/Utils/ExtendUtil/export_util.py
================================================
from enum import Enum
from Utils.RandomUtil import random_generated_names as random_util

import logging
import os
import re
import tarfile
import zipfile


logging.basicConfig(level=logging.DEBUG, format="%(asctime)s:%(levelname)s:%(name)s : %(message)s")
logger = logging.getLogger("Util - Export")


class ExportTypes(Enum):
    """
    Enumeration types for export modes
    """
    ZIP = 0
    TAR_GZ = 1


class ExportOptions(Enum):
    """
    Enumeration types for export options such as Protocol, Attack or Attack Suite
    """
    PROTOCOL = 0
    ATTACK = 1
    ATTACK_SUITE = 2


# noinspection PyBroadException
class ExportUtil(object):
    # Base path
    BASE_PATH = os.path.dirname(os.path.abspath(__file__))

    # Export Protocol Constants
    EXPORT_PROTOCOL_TEMPLATE_NAME = BASE_PATH + "/export_protocol_template.py"
    EXPORT_PROTOCOL_NAME_REGEX = "_PROTOCOL_NAME"

    # Export Attack Constants
    EXPORT_ATTACK_TEMPLATE_NAME = BASE_PATH + "/export_attack_template.py"
    EXPORT_ATTACK_NAME_REGEX = "_ATTACK_NAME"
    EXPORT_COMBINED_ATTACK_NAME_REGEX = "_ATTACK_COMBINED_NAME"

    # Export Attack Suite Constants
    EXPORT_ATTACK_SUITE_TEMPLATE_NAME = BASE_PATH + "/export_attack_suite_template.py"
    EXPORT_ATTACK_SUITE_NAME_REGEX = "_ATTACK_SUITE_NAME"
    EXPORT_COMBINED_ATTACK_SUITE_NAME_REGEX = "_ATTACK_SUITE_COMBINED_NAME"

    @staticmethod
    def get_export_texts_and_values():
        return [
            {"text": ".zip", "value": ExportTypes.ZIP},
            {"text": ".tar.gz", "value": ExportTypes.TAR_GZ}
        ]

    @staticmethod
    def export_function_factory(export_type):
        """
        Export function factory to decide method of archive
        :type export_type: ExportTypes
        :return: Corresponding export function
        """
        if export_type == ExportTypes.TAR_GZ:
            return ExportUtil.export_files_with_tar
        else:
            return ExportUtil.export_files_with_zip

    @staticmethod
    def export_files_with_zip(output_name, list_of_files, output_path="./"):
        if not output_name.endswith(".zip"):
            output_name = output_name + ".zip"
        zf = zipfile.ZipFile(output_path + output_name, mode='w')
        for _file in list_of_files:
            try:
                logger.info("File {0} is added to {1}".format(_file, output_name))
                if len(_file) == 2:
                    # Create file
                    zf.write(_file[0], _file[1])
                else:
                    # Create directory
                    zf.writestr(zipfile.ZipInfo(_file[0]), '')
            except RuntimeError as _:
                logger.error("Error has occurred while compressing file {0}".format(_file[0]))
        zf.close()

    @staticmethod
    def export_files_with_tar(output_name, list_of_files, output_path="./"):
        if not output_name.endswith(".tar.gz"):
            output_name = output_name + ".tar.gz"
        tar = tarfile.open(output_path + output_name, "w:gz")
        for _file in list_of_files:
            try:
                logger.info("File {0} is added to {1}".format(_file, output_name))
                if len(_file) == 2:
                    # Create file
                    tar.add(_file[0], _file[1])
                else:
                    # Create directory
                    t = tarfile.TarInfo(_file[0])
                    t.type = tarfile.DIRTYPE
                    tar.addfile(t)
            except RuntimeError as _:
                logger.error("Error has occurred while compressing file {0}".format(_file[0]))
        tar.close()

    @staticmethod
    def export_protocol(protocol_name, export_path, export_type, output_name):
        temporary_file_name = None
        try:
            logger.info("Exporting protocol is started.")

            # Check whether output name has any possible naming
            if len(output_name.split(".")[0].strip()) == 0:
                output_name = protocol_name

            temporary_file_name = ExportUtil._create_temporary_file_and_replace_regex(
                template_name=ExportUtil.EXPORT_PROTOCOL_TEMPLATE_NAME,
                regex_list=[
                    (ExportUtil.EXPORT_PROTOCOL_NAME_REGEX, protocol_name)
                ]
            )

            # Decide function and export with respect to corresponding archive
            export_func = ExportUtil.export_function_factory(export_type)
            export_func(
                output_name,
                [  # [0] represents actual file path and [1] represents the name of file in compressed file
                    (ExportUtil.BASE_PATH + "/../../Entity/protocol.py", "protocol.py"),
                    (temporary_file_name, protocol_name + "_protocol.py"),
                    (temporary_file_name, "__init__.py"),
                    ("attacks/__init__.py",)
                ],
                export_path
            )

            logger.info("Exporting protocol is finished.")
        except Exception as _:
            logger.error("Error has occurred while exporting protocol.")
        finally:
            if temporary_file_name is not None:
                # Remove temporary file
                os.remove(temporary_file_name)

    @staticmethod
    def export_attack(protocol_name, attack_name, export_path, export_type, output_name):
        temporary_file_name = None
        try:
            logger.info("Exporting attack is started.")

            # Check whether output name has any possible naming
            if len(output_name.split(".")[0].strip()) == 0:
                output_name = protocol_name + "_" + attack_name

            temporary_file_name = ExportUtil._create_temporary_file_and_replace_regex(
                template_name=ExportUtil.EXPORT_ATTACK_TEMPLATE_NAME,
                regex_list=[
                    (ExportUtil.EXPORT_ATTACK_NAME_REGEX, protocol_name + " " + attack_name + " Attack"),
                    (ExportUtil.EXPORT_COMBINED_ATTACK_NAME_REGEX, protocol_name + attack_name + "Attack")
                ]
            )

            # Decide function and export with respect to corresponding archive
            export_func = ExportUtil.export_function_factory(export_type)
            export_func(
                output_name,
                [  # [0] represents actual file path and [1] represents the name of file in compressed file
                    (ExportUtil.BASE_PATH + "/../../Entity/attack.py", "attack.py"),
                    (ExportUtil.BASE_PATH + "/../../Entity/input_format.py", "input_format.py"),
                    (temporary_file_name, protocol_name + "_" + attack_name + "_attack.py"),
                    (temporary_file_name, "__init__.py",)
                ],
                export_path
            )

            logger.info("Exporting attack is finished.")
        except Exception as _:
            logger.error("Error has occurred while exporting attack.")
        finally:
            if temporary_file_name is not None:
                # Remove temporary file
                os.remove(temporary_file_name)

    @staticmethod
    def export_attack_suite(protocol_name, attack_suite_name, export_path, export_type, output_name):
        temporary_file_name = None
        try:
            logger.info("Exporting attack suite is started.")

            # Check whether output name has any possible naming
            if len(output_name.split(".")[0].strip()) == 0:
                output_name = protocol_name + "_" + attack_suite_name + "_suite"

            temporary_file_name = ExportUtil._create_temporary_file_and_replace_regex(
                template_name=ExportUtil.EXPORT_ATTACK_SUITE_TEMPLATE_NAME,
                regex_list=[
                    (ExportUtil.EXPORT_ATTACK_SUITE_NAME_REGEX, protocol_name + " "
                     + attack_suite_name + " Attack Suite"),
                    (ExportUtil.EXPORT_COMBINED_ATTACK_SUITE_NAME_REGEX, protocol_name
                     + attack_suite_name + "AttackSuite")
                ]
            )

            # Decide function and export with respect to corresponding archive
            export_func = ExportUtil.export_function_factory(export_type)
            export_func(
                output_name,
                [  # [0] represents actual file path and [1] represents the name of file in compressed file
                    (ExportUtil.BASE_PATH + "/../../Entity/attack_suite.py", "attack_suite.py"),
                    (temporary_file_name, protocol_name + "_" + attack_suite_name + "_attack_suite.py"),
                    (temporary_file_name, "__init__.py",)
                ],
                export_path
            )

            logger.info("Exporting attack suite is finished.")
        except Exception as _:
            logger.error("Error has occurred while exporting attack.")
        finally:
            if temporary_file_name is not None:
                # Remove temporary file
                os.remove(temporary_file_name)

    @staticmethod
    def _create_temporary_file_and_replace_regex(template_name=None, regex_list=None):
        if regex_list is None:
            regex_list = []

        # Read template
        with open(template_name, "r") as export_template_file:
            content = export_template_file.read()

        temporary_file_name = random_util.get_random_file_name()
        content_replaced = \
            ExportUtil._replace_regex(content, regex_list)

        # Write template to temporary file
        with open(temporary_file_name, "w") as temporary_file:
            temporary_file.write(content_replaced)

        return temporary_file_name

    @staticmethod
    def _replace_regex(content, substitution_list_as_tuples):
        for pair in substitution_list_as_tuples:
            content = re.sub(pair[0], pair[1], content)
        return content

    @staticmethod
    def export_action(protocol_name, attack_name, attack_suite_name, file_path, file_name, extension, option):
        file_path = file_path if file_path.endswith("/") else file_path + "/"
        if option == ExportOptions.PROTOCOL:
            ExportUtil.export_protocol(protocol_name, file_path, extension, file_name)
        elif option == ExportOptions.ATTACK:
            ExportUtil.export_attack(protocol_name, attack_name, file_path, extension, file_name)
        elif option == ExportOptions.ATTACK_SUITE:
            ExportUtil.export_attack_suite(protocol_name, attack_suite_name, file_path, extension, file_name)
        else:
            raise ValueError("Unknown export option!")


if __name__ == '__main__':
    ExportUtil.export_protocol("KNX", "./", ExportTypes.ZIP, "hey")


================================================
FILE: src/Utils/ExtendUtil/import_util.py
================================================
from enum import Enum
from os import listdir
from os.path import isfile, join

import logging
import os
import shutil
import tarfile
import zipfile

logging.basicConfig(level=logging.DEBUG, format="%(asctime)s:%(levelname)s:%(name)s : %(message)s")
logger = logging.getLogger("Util - Import")


class ImportOptions(Enum):
    """
    Enumeration types for import options such as Protocol, Attack_OR_Attack Suite
    If user chooses PROTOCOL, then s/he can directly import without selecting any other input
    Otherwise, we need to provide currently loaded protocols to select to which one we will import
    """
    PROTOCOL = 0
    ATTACK_OR_ATTACK_SUITE = 1


class ImportUtil(object):
    # Path related variables
    BASE_PATH_OF_TEMP = os.path.dirname(os.path.abspath(__file__))
    PROTOCOLS_DIR_NAME = "../../protocols/tmp"
    TEMP_FULL_PATH = BASE_PATH_OF_TEMP + "/" + PROTOCOLS_DIR_NAME
    TEMP_DIR_NAME = ".tmp"

    # Get entities
    ENTITY_PATH = BASE_PATH_OF_TEMP + "/../../Entity/"
    ENTITIES = [_ for _ in listdir(ENTITY_PATH) if
                isfile(join(ENTITY_PATH, _)) and not _.startswith("__") and not _.endswith(".pyc")]

    @staticmethod
    def startup():
        """
        Startup function that will be called program starting point in order to create necessary containers
        Currently creates the followings:
            * Temporary directory imported files
        """
        try:
            if os.path.isdir(ImportUtil.TEMP_FULL_PATH):
                shutil.rmtree(ImportUtil.TEMP_FULL_PATH)
            os.mkdir(ImportUtil.TEMP_FULL_PATH)
            # make this directory a package
            os.open(ImportUtil.TEMP_FULL_PATH + "/__init__.py", os.O_CREAT)
        except OSError:
            logger.error("Creation of the directory {0} failed.".format(ImportUtil.TEMP_DIR_NAME))
        else:
            logger.info("Creation of the directory {0} successfully done.".format(ImportUtil.TEMP_DIR_NAME))
        pass

    @staticmethod
    def shutdown():
        """
        Shutdown function that will be exit stage of program in order to clean everything that are already created
        """
        try:
            if os.path.isdir(ImportUtil.TEMP_FULL_PATH):
                shutil.rmtree(ImportUtil.TEMP_FULL_PATH)
        except OSError:
            logger.error("Deletion of the directory {0} failed.".format(ImportUtil.TEMP_DIR_NAME))
        else:
            logger.info("Deletion of the directory {0} successfully done.".format(ImportUtil.TEMP_DIR_NAME))
        pass

    @staticmethod
    def trigger_import(input_path, protocol_name=None):
        try:
            import_action = ImportUtil.import_function_factory(input_path)
            dir_name, file_name = os.path.split(input_path)

            # If the protocol name is provided, it means that we are importing a attack/attack suite
            # Therefore, put the imported files to corresponding attacks directory
            if protocol_name is not None:
                full_path_to_out_dir = ImportUtil.TEMP_FULL_PATH + "/" + protocol_name + "/attacks/" + \
                                       file_name.split(".", 1)[0]
            else:
                full_path_to_out_dir = ImportUtil.TEMP_FULL_PATH + "/" + file_name.split(".", 1)[0]

            try:
                os.mkdir(full_path_to_out_dir)
            except OSError:
                logger.error("Creation of the directory {0} failed.".format(full_path_to_out_dir))
            else:
                logger.info("Creation of the directory {0} successfully done.".format(full_path_to_out_dir))

            import_action(input_path, full_path_to_out_dir)

        except RuntimeError as _:
            logger.error(_.message)

    @staticmethod
    def import_function_factory(input_path):
        options = [
            (zipfile.is_zipfile, ImportUtil.import_zip),
            (tarfile.is_tarfile, ImportUtil.import_tar)
        ]
        for option in options:
            try:
                if option[0](input_path):
                    return option[1]
                else:
                    continue
            except Exception:
                pass
        raise RuntimeError("Unknown import extension!")

    @staticmethod
    def import_zip(input_path, full_out_dir_path):
        zf = zipfile.ZipFile(input_path, mode='r')
        namelist = zf.namelist()
        for _file in namelist:
            if ImportUtil._do_not_import_names(_file):
                continue
            try:
                zf.extract(_file, full_out_dir_path)
            except RuntimeError as _:
                logger.error("Error has occurred while extracting file {0}".format(_file))
        zf.close()

    @staticmethod
    def import_tar(input_path, full_out_dir_path):
        tar = tarfile.open(input_path)
        namelist = tar.getnames()
        for _file in namelist:
            if ImportUtil._do_not_import_names(_file):
                continue
            try:
                tar.extract(_file, full_out_dir_path)
            except RuntimeError as _:
                logger.error("Error has occurred while extracting file {0}".format(_file))
        tar.close()

    @staticmethod
    def import_protocol(file_path):
        ImportUtil.trigger_import(file_path)
        # Take actions with respect to importing of protocol

    @staticmethod
    def import_attack_or_attack_suite(file_path, protocol_name):
        ImportUtil.trigger_import(file_path, protocol_name)
        # Take actions with respect to importing of attack or attack suite

    @staticmethod
    def _is_file_name(name):
        """
        :param name: File name or directory name
        :return: Whether name represents file or not
        """
        return not name.endswith("/")

    @staticmethod
    def _do_not_import_names(name):
        return name in ImportUtil.ENTITIES

    @staticmethod
    def import_action(file_path, option, protocol_name=None):
        if option == ImportOptions.PROTOCOL:
            ImportUtil.import_protocol(file_path)
        elif option == ImportOptions.ATTACK_OR_ATTACK_SUITE:
            if protocol_name is None or protocol_name is "":
                raise ValueError("You need to provide protocol name to bind attack to that protocol!")
            ImportUtil.import_attack_or_attack_suite(file_path, protocol_name)
        else:
            raise ValueError("Unknown export option!")


if __name__ == '__main__':
    ImportUtil.startup()


================================================
FILE: src/Utils/FilterUtil/__init__.py
================================================
"""
    Filtering Utilities
    It contains necessary functionalities used for filtering packets in several attacks

    1) PyShark Filterer (used with Generic Sniffer)
"""

================================================
FILE: src/Utils/FilterUtil/pyshark_filter_util.py
================================================
import logging

logging.basicConfig(level=logging.DEBUG, format="%(asctime)s:%(levelname)s:%(name)s : %(message)s")
logger = logging.getLogger("Util - PyShark Filter")


class PySharkFilter:
    """
    Container class for internally represented pyshark filter
    where filter has layer_name, field_nane and value to be checked while filter
    """
    def __init__(self, layer_name, field_name, value):
        self.layer_name = layer_name
        self.field_name = field_name
        self.value = value

    def set_layer_name(self, layer_name):
        self.layer_name = layer_name
        return self

    def get_layer_name(self):
        return self.layer_name

    def set_field_name(self, field_name):
        self.field_name = field_name
        return self

    def get_field_name(self):
        return self.field_name

    def set_value(self, value):
        self.value = value
        return self

    def get_value(self):
        return self.value

    def apply_filter_to_packet(self, packet):
        """
        Apply filter to packet, if exists check value equality otherwise return False
        :param packet: Packet to be filtered
        :return: Whether packet is the same value with filter value
        """
        try:
            return packet[self.layer_name].get_field_value(self.field_name).main_field.raw_value == unicode(self.value)
        except KeyError:
            logger.error("Given layer name or field name is not defined in packet!")
            return False



================================================
FILE: src/Utils/FuzzerUtil/__init__.py
================================================
"""
    Fuzzer Utilities
    It contains necessary functionalities used for fuzzing attacks

    1) Radamsa Random Fuzzing Payload Generator
"""

================================================
FILE: src/Utils/FuzzerUtil/radamsa_util.py
================================================
import logging
import subprocess

logging.basicConfig(level=logging.DEBUG, format="%(asctime)s:%(levelname)s:%(name)s:%(message)s")
logger = logging.getLogger("Util - Radamsa")

ASCII_DECODE_LIMIT = 128


def radamsa_malformed_input_generator(input_string, output_count=1):
    """
    Return test case output from given input string
    :param output_count: Number of returned output strings
    :param input_string: Any type of variable can be input
    :return: Radamsa generated output string for fuzzing
    """
    # Create subprocess for both echo and radamsa
    echo_process = subprocess.Popen(["echo", input_string], stdout=subprocess.PIPE)
    radamsa_process = subprocess.Popen(["radamsa", "-n", str(output_count)],
                                       stdin=echo_process.stdout, stdout=subprocess.PIPE)
    echo_process.stdout.close()
    # Get values
    output_string, error_message = radamsa_process.communicate()

    if error_message is None:
        if output_count > 1:
            # If it are more than one, then split it
            return output_string.split("\n")
        else:
            return output_string
    else:
        logger.debug(error_message)


def get_ascii_decodable_radamsa_malformed_input(input_string, output_count=1):
    def delete_non_ascii_characters(_string):
        return "".join([_ for _ in _string if ord(_) < ASCII_DECODE_LIMIT])

    returned_strings = radamsa_malformed_input_generator(input_string, output_count)
    _type = type(returned_strings)
    if _type == list:
        return [delete_non_ascii_characters(_returned_string) for _returned_string in returned_strings]
    elif _type == str:
        return delete_non_ascii_characters(returned_strings)
    else:
        logger.error("Non-matched type for output value")


================================================
FILE: src/Utils/RandomUtil/__init__.py
================================================
"""
    Random Utilities
    It contains necessary functionalities that is related to randomized operations.
"""

================================================
FILE: src/Utils/RandomUtil/random_generated_names.py
================================================
import random
import string
import time


def get_random_client_name():
    return 'peniot-cli-' + ''.join(random.choice(string.ascii_uppercase + string.ascii_lowercase + string.digits)
                                   for _ in range(16)) + '-' + str(int(time.time()))


def get_random_file_name():
    return 'peniot_file_' + ''.join(random.choice(string.ascii_uppercase + string.ascii_lowercase + string.digits)
                                    for _ in range(16)) + '-' + str(int(time.time()))


================================================
FILE: src/Utils/ReportUtil/__init__.py
================================================
"""
    Report Generation Utilities
    It contains necessary functionalities used for reporting

    1) Report Generator
"""

================================================
FILE: src/Utils/ReportUtil/report_generator.py
================================================
from fpdf import FPDF

from Utils.CommonUtil import get_current_datetime_for_report_format, get_current_datetime_for_filename_format


class PeniotPDF(FPDF):

    TITLE = 'PENIOT: Penetration Testing Tool for IoT'
    COPYRIGHT = 'Copyright ' + chr(169) + ' 2018 - 2019 PENIOT Group. All Rights Reserved.'

    def header(self):
        self.set_font('Arial', 'B', 16)

        # Add an address
        self.cell(0, 15, self.TITLE, ln=1, align='C')
        # Line break
        self.ln(15)
        self.line(0, 35, self.w, 35)

    def footer(self):
        self.set_y(-10)
        self.set_font('Arial', size=9)
        page = 'Page ' + str(self.page_no())
        self.cell(0, 5, self.COPYRIGHT, 0, 0, 'C', 0)
        self.cell(0, 5, page, 0, 0, 'R')

    def add_title_and_date(self, attack_name):
        self.set_font("Arial", size=14, style='B')
        self.cell(0, 5, attack_name + ' Summary', 0, 0, 'L')
        self.set_font("Arial", size=12)
        self.cell(0, 5, 'Date: ' + get_current_datetime_for_report_format(), 0, 0, 'R')
        self.ln(10)

    def add_attack_logs(self, attack_logs):
        self.set_font("Arial", size=12)
        self.multi_cell(0, 5, txt=attack_logs)


class GenerateReport(object):

    @staticmethod
    def generate_pdf_from_text(protocol_name, attack_name, attack_logs, directory):
        pdf = PeniotPDF()
        pdf.add_page()

        pdf.add_title_and_date(attack_name)
        pdf.add_attack_logs(attack_logs)

        output_name = ('_'.join((protocol_name + ' ' + attack_name).split())).lower()
        pdf.output(directory + output_name + '_' + get_current_datetime_for_filename_format())


if __name__ == '__main__':
    txt = """
    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras quis lacus varius, tempus odio vitae, tempor enim. Cras ut nibh justo. Ut diam ipsum, interdum commodo orci non, ultrices dictum magna. Curabitur tortor lacus, finibus et mattis nec, malesuada nec nibh. Morbi nec sem a leo tincidunt viverra quis eget leo. Aliquam erat volutpat. In tempor auctor tincidunt. Aliquam lectus dui, semper vel justo a, molestie tristique magna. Mauris nec vulputate sapien, blandit convallis felis. In a orci vel urna vehicula faucibus quis et mi. Duis lacus magna, malesuada eu mattis vestibulum, interdum vitae lectus. Lorem ipsum dolor sit amet, consectetur adipiscing elit.

    Suspendisse a lectus id nibh semper hendrerit non eget nisi. Maecenas massa magna, euismod ac dui et, tristique porta metus. Maecenas sed massa eget leo commodo sagittis iaculis ac nisi. Suspendisse ullamcorper, purus quis faucibus venenatis, metus mauris faucibus turpis, ac posuere magna velit non est. Ut ac odio vitae ante ultricies aliquam. Quisque sapien sem, condimentum at erat nec, luctus facilisis nisl. Sed maximus velit ac pellentesque sagittis. Donec ac sagittis leo, et laoreet sem. Vivamus egestas lectus non bibendum accumsan. Sed tempus risus id odio volutpat, a ullamcorper odio lacinia. In vitae velit nulla. Praesent a venenatis diam, a vestibulum tortor.
    
    Duis tincidunt efficitur faucibus. Praesent eget dui tellus. Vestibulum dapibus aliquam arcu. Donec vulputate sem enim, quis tincidunt diam blandit ut. Curabitur accumsan maximus risus, sed dictum ligula volutpat vitae. Curabitur convallis ac mauris ut consectetur. Quisque tellus arcu, ultrices vel ante quis, aliquet fringilla mauris. Sed ornare eros sed interdum facilisis. Duis dictum augue vel rutrum maximus. Phasellus neque dolor, pretium non risus in, tincidunt feugiat eros. Integer vel odio iaculis, faucibus neque quis, mollis enim. Etiam ac euismod orci. Donec tempor, erat at cursus porta, tortor sem aliquam leo, eget porta erat libero eu enim. Etiam felis elit, consectetur a facilisis id, porta quis nulla. Quisque libero odio, ultrices quis est et, efficitur pellentesque dui.
    
    Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Praesent semper tempus risus, eu condimentum leo interdum sed. Aenean turpis leo, aliquet non ligula venenatis, fermentum maximus velit. Aliquam aliquam posuere libero, quis cursus nisl gravida quis. Proin ac interdum lorem, vitae varius lacus. Maecenas sit amet convallis leo, sit amet tincidunt enim. Suspendisse sit amet risus sit amet libero aliquam mollis. Vestibulum vehicula lacus condimentum, fermentum turpis id, pretium eros. Cras sagittis sem nec porta dictum. Donec a accumsan dolor. Nam dictum eros at leo viverra, ac mattis elit placerat. Mauris ornare pulvinar massa nec rutrum. Nunc nec erat at est lobortis dictum ut in enim. Donec eu est sit amet lacus feugiat blandit. Praesent a sollicitudin ex, blandit fermentum tellus. Nulla vitae viverra ipsum, in pharetra dolor.
    
    Praesent imperdiet nec nisi aliquam dictum. Nunc ultricies sodales porta. Donec consectetur finibus tellus, porttitor sodales sapien pulvinar in. Duis suscipit suscipit felis eu luctus. Nam in dolor aliquam, laoreet elit a, faucibus ligula. Nulla quis nisl imperdiet dolor molestie rhoncus. Fusce neque tortor, blandit at sapien in, egestas fermentum felis. Curabitur auctor ipsum vitae velit vestibulum ultrices.
    
    Pellentesque eget lectus urna. Aenean commodo semper orci sit amet dictum. Curabitur ultrices vitae ipsum in bibendum. Nunc at justo ut augue mollis aliquam. Sed varius, purus at sagittis condimentum, ex velit elementum neque, at malesuada dui arcu nec orci. Nullam viverra, nisi aliquam porta tempor, ex ex bibendum eros, eu viverra urna turpis eu massa. Vestibulum quam lectus, ullamcorper sit amet imperdiet in, tincidunt quis tortor.
    
    Sed non mollis ligula, non imperdiet nunc. Nam elementum augue sit amet risus pulvinar, id dapibus velit laoreet. Sed commodo arcu ut tellus commodo, sed gravida nisl viverra. Sed non sapien lacus. Etiam nec gravida urna, vitae sodales risus. Donec iaculis vel ex aliquam imperdiet. Maecenas condimentum imperdiet porta. Suspendisse potenti. Donec tincidunt vestibulum libero, ac lobortis nisi interdum ac. Curabitur luctus nisl a lorem ultrices pellentesque. Nam eleifend at ex nec pretium. Nullam id purus eget metus facilisis condimentum quis non urna. Quisque et volutpat purus. Pellentesque facilisis molestie orci, a pharetra dolor aliquet sed.
    
    Vestibulum purus mi, dapibus ac rutrum et, convallis at magna. Nunc leo justo, finibus quis molestie vel, accumsan sit amet diam. Quisque vehicula lacus vitae augue imperdiet vulputate. Phasellus vulputate metus vel ex dapibus, nec pretium sapien eleifend. Cras metus erat, vehicula sed mi ut, eleifend finibus dui. Mauris bibendum, velit vel mollis sodales, libero orci congue dui, non dapibus eros lectus malesuada tortor. Ut dignissim dui turpis, ut faucibus velit consectetur nec. Aenean vestibulum turpis pulvinar egestas fringilla. Suspendisse potenti. Etiam dignissim sapien ac velit molestie, ac blandit augue tempor. Pellentesque laoreet tellus a dui dignissim, eget sagittis lacus pharetra. Sed id elit ac lorem tristique cursus. Nunc vel porta augue. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
    
    Donec at dolor eget arcu dignissim mollis at eget erat. Aenean sodales enim id massa vehicula, ac tempus massa dictum. Praesent facilisis id urna vel scelerisque. Etiam pharetra consequat massa eget molestie. Donec ullamcorper ipsum ut orci aliquet placerat. Quisque sit amet magna quis velit tincidunt placerat. Nulla facilisi. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Duis congue est sit amet arcu sollicitudin dapibus. Maecenas tristique venenatis ante, eu elementum leo sollicitudin vel.
    
    Suspendisse at accumsan nulla. Nam blandit auctor purus posuere tempor. Pellentesque molestie pellentesque justo ut condimentum. Aenean non fringilla mi. Nullam elementum nibh orci, eget imperdiet eros elementum hendrerit. Nam vitae volutpat odio. Pellentesque a ligula iaculis odio varius porta at ut ipsum.
    
    Nulla mi augue, malesuada iaculis nibh sed, blandit molestie enim. Donec luctus ipsum sed mollis porta. Nam hendrerit finibus turpis, ac elementum ante mattis vel. Aliquam tincidunt varius tellus sed tempus. Fusce vel tellus sem. Sed suscipit ex in auctor dictum. Duis ullamcorper tortor urna, non ullamcorper justo convallis ac. Nullam at est magna. Nam id erat mattis orci bibendum ultrices et in nisl. Maecenas a fringilla lorem. In facilisis, sapien volutpat posuere consectetur, ligula erat ornare neque, a ornare velit.
    """
    GenerateReport.generate_pdf_from_text('CoAP', 'DoS Attack', txt)


================================================
FILE: src/Utils/SnifferUtil/__init__.py
================================================
"""
    Sniffer Utilities
    It contains necessary functionalities used for sniffers

    1) Generic Sniffer with PyShark
"""

================================================
FILE: src/Utils/SnifferUtil/generic_sniffer.py
================================================
import logging
import os

import pyshark
from Utils.FilterUtil import pyshark_filter_util as pyshark_filter_util

logging.basicConfig(level=logging.DEBUG, format="%(asctime)s:%(levelname)s:%(name)s : %(message)s")
logger = logging.getLogger("Generic Sniffer")

DEFAULT_INTERFACE = "any"
DEFAULT_SNIFF_TIMEOUT = 15.
DEFAULT_SAVE = False
DEFAULT_SAVE_DIR = os.path.dirname(os.path.abspath(__file__)) + "/../../captured_packets/"


def filter_packets_by_filter_list(packets, filter_list):
    """
    :param packets: Packet list
    :param filter_list: Filters with respect to packet field
    :type filter_list: list of pyshark_filter_util.PySharkFilter
    :return: Filtered packets as list
    """

    filtered_packets = [packet for packet in packets
                        if all(single_filter.apply_filter_to_packet(packet) for single_filter in filter_list)]
    return filtered_packets


class GenericSniffer:
    """
    Generic sniffer template class
    The class can listen specific interface by tshark over pyshark
    and filter wanted packets by looking at display filter parameter
    with the given timeout amount
    """

    def __init__(self, timeout=DEFAULT_SNIFF_TIMEOUT, interface=DEFAULT_INTERFACE, use_json=False, include_raw=False,
                 output_pcap_filename=None, output_dir=DEFAULT_SAVE_DIR, display_filter=None):
        self.captured_packets = None

        self.timeout = timeout
        self.interface = interface
        self.use_json = use_json
        self.include_raw = include_raw
        # Default value is None and it is important to have it None since it will not produce file in this case
        if output_pcap_filename is None:
            self.output_pcap_filename = None
        else:
            self.output_pcap_filename = "{0}{1}{2}".format(output_dir, output_pcap_filename,
                                                           ("" if output_pcap_filename.endswith(".pcap") else ".pcap"))

        self.display_filter = display_filter

    def start_live_capture(self):
        """
        Start capture procedure of packets over listener
        :return: None since captured packets are saved internally
        """
        capture = pyshark.LiveCapture(interface=self.interface, use_json=self.use_json, include_raw=self.include_raw,
                                      output_file=self.output_pcap_filename, display_filter=self.display_filter)
        capture.sniff(timeout=self.timeout)
        self.captured_packets = capture._packets
        logger.info("{0} packets are captured.".format(len(self.captured_packets)))
        capture.close()

    def get_captured_packets(self):
        """
        :return: Captured packets as list
        """
        return self.captured_packets

    def filter_packets_by_protocol(self, protocol=None):
        """
        Filtering operation of packets via protocol name
        :param protocol: Protocol name which will be used for filtering packets by looking their layers
        :return: Filtered packet list
        """
        if protocol is None:
            return self.captured_packets
        else:
            return filter(lambda packet: protocol in str(packet.layers), self.captured_packets)


if __name__ == '__main__':
    sniffer = GenericSniffer()
    sniffer.start_live_capture()


================================================
FILE: src/Utils/__init__.py
================================================
"""
    General Utility Module
"""

================================================
FILE: src/__init__.py
================================================


================================================
FILE: src/captured_packets/__init__.py
================================================
"""
    This package contains the all captured packets.
    The files inside this package follows these rules:
        - Name of the file begins with the protocol name which packets belong to.
        - Then, the time at which packets are captured is appended to the file name.
        - The file extension is .pcap.
    Here are some example file names:
        MQTT_2014-09-26_16:34:40.pcap, AMQP_2014-09-26_17:25:40.pcap
"""

================================================
FILE: src/module_installer.py
================================================
print "Checking whether we have necessary dependencies installed..."

try:
    import paho.mqtt

    print "[+] You have paho-mqtt module installed."
except ImportError:
    print "[-] You have to install paho.mqtt module"
    print "\tHint: sudo -H pip install paho-mqtt"

try:
    import bluepy

    print "[+] You have bluepy module installed."
except ImportError:
    print "[-] You have to install bluepy module"
    print "\tHint: sudo -H pip install bluepy"

try:
    import coapthon

    print "[+] You have coapthon module installed."
except ImportError:
    print "[-] You have to install coapthon module"
    print "\tHint: sudo -H pip install coapthon"

try:
    import Cython

    print "[+] You have Cython module installed."
except ImportError:
    print "[-] You have to install Cython module"
    print "\tHint: sudo -H pip install Cython"

try:
    import pygame

    print "[+] You have pygame module installed."
except ImportError:
    print "[-] You have to install pygame module"
    print "\tHint: sudo -H pip install pygame"

try:
    import pika

    print "[+] You have pika module installed."
except ImportError:
    print "[-] You have to install pygame module"
    print "\tHint: sudo -H pip install pika"


================================================
FILE: src/peniot.py
================================================
# Run the program driver of tkinter

if __name__ == '__main__':
    from GUI.tkinter import run
    run()


================================================
FILE: src/protocols/AMQP/__init__.py
================================================
"""
    This package contains the following functionalities:

    1) Example usage of AMQP.
    2) AMQP Scanner
"""


================================================
FILE: src/protocols/AMQP/amqp_protocol.py
================================================
import unittest

from Entity.protocol import Protocol


class AMQP(Protocol):

    def __init__(self):
        amqp_definition = "AMQP stands for Advanced Message Queuing Protocol and it is an open standard application layer protocol.\n\n" \
                          "There are a couple of key parts in AMQP:\n" \
                          "* Broker (Server): An application - implementing the AMQP model - that accepts connections from clients\n" \
                          " for message routing, queuing etc.\n" \
                          "* Message: Content of data transferred / routed including information such as payload and message attributes.\n" \
                          "* Consumer: An application which receives message(s) - put by a producer - from queues.\n" \
                          "* Producer: An application which puts messages to a queue."
        attack_suites = []
        Protocol.__init__(self, "AMQP", attack_suites, amqp_definition)


class TestAMQPProtocol(unittest.TestCase):
    def setUp(self):
        self.amqp = AMQP()

    def tearDown(self):
        pass

    def test_name(self):
        self.assertEqual("AMQP", self.amqp.get_protocol_name())

    def test_attacks(self):
        attack_suites = self.amqp.get_attack_suites()
        self.assertIsNotNone(attack_suites)
        self.assertEquals(len(attack_suites), 0)


if __name__ == '__main__':
    unittest.main()


================================================
FILE: src/protocols/AMQP/amqp_scanner.py
================================================
from Utils.SnifferUtil import generic_sniffer as generic_sniffer

# Capturing via TShark
amqp_layer_filter = "amqp"


class AMQPScanner:
    """
    This class is used to scan for a AMQP device.
    It captures packets from the network and try to find AMQP devices.
    """

    def __init__(self):
        pass

    @staticmethod
    def scan(timeout=generic_sniffer.DEFAULT_SNIFF_TIMEOUT, interface=generic_sniffer.DEFAULT_INTERFACE,
             use_json_and_include_raw=False, output_pcap_filename=None):
        sniffer = generic_sniffer.GenericSniffer(timeout=timeout, interface=interface,
                                                 use_json=use_json_and_include_raw,
                                                 include_raw=use_json_and_include_raw,
                                                 output_pcap_filename=output_pcap_filename,
                                                 display_filter=amqp_layer_filter)
        sniffer.start_live_capture()
        return sniffer.get_captured_packets()


if __name__ == '__main__':
    packets = AMQPScanner().scan()
    for packet in packets:
        print packet


================================================
FILE: src/protocols/AMQP/attacks/__init__.py
================================================
"""
    This is a package that contains attacks to AMQP protocol.
    Currently, it supports the following attacks

        1) Denial of Service Attack
        2) Fuzzing Attack
"""

================================================
FILE: src/protocols/AMQP/attacks/amqp_dos_attack.py
================================================
import logging
import multiprocessing
import signal
import time
import unittest

import pika

from Entity.attack import Attack
from Entity.input_format import InputFormat


class AMQPDoSAttack(Attack):
    """
    AMQP Protocol - DoS Attack Module
    """
    # Input Fields
    host = "localhost"
    queue = "peniot-queue"
    exchange = "peniot-exchange"
    routing_key = "peniot-routing-key"
    body = "peniot-body"
    exchange_type = "direct"
    timeout = 0.01

    # Misc Members
    connection = None
    channel = None
    logger = None
    sent_message_count = 0
    stopped_flag = False

    def __init__(self):
        default_parameters = ["", "", "", "", "", "", 10.0]
        inputs = [
            InputFormat("Host Name", "host", "localhost", str, mandatory=True),
            InputFormat("Queue Name", "queue", "peniot-queue", str, mandatory=True),
            InputFormat("Exchange Name", "exchange", "peniot-exchange", str, mandatory=True),
            InputFormat("Routing Key", "routing_key", "peniot-routing-key", str, mandatory=True),
            InputFormat("Message Body", "body", "peniot-body", str, mandatory=True),
            InputFormat("Exchange Type", "exchange_type", "direct", str, mandatory=True),
            InputFormat("Timeout", "timeout", self.timeout, float)
        ]

        Attack.__init__(self, "AMQP DoS Attack", inputs, default_parameters,
                        "    We send AMQP requests to the client.\n"
                        "    The time difference between those requests\n"
                        "    can be specified.")

        logging.basicConfig(level=logging.DEBUG, format="%(asctime)s:%(levelname)s:%(name)s:%(message)s")

        # Signal handler to exit from function
        signal.signal(signal.SIGINT, self.signal_handler)

    def signal_handler(self, sig, frame):
        self.stop_attack()

    def stop_attack(self):
        self.logger.info("Connection will be closed")
        self.stopped_flag = True
        if self.connection is not None:
            self.connection.close()
        time.sleep(2)  # Sleep two seconds so the user can see the message

    def pre_attack_init(self):
        # Get connection and channel
        self.connection = pika.BlockingConnection(pika.ConnectionParameters(host=self.host))
        self.channel = self.connection.channel()

        # Create exchange
        self.channel.exchange_declare(exchange=self.exchange, exchange_type=self.exchange_type)

        # Define queue to store
        self.channel.queue_declare(queue=self.queue)

    def run(self):
        super(AMQPDoSAttack, self).run()
        self.pre_attack_init()

        # Start client loop for requests
        while self.stopped_flag is True:
            self.sent_message_count += 1
            self.channel.basic_publish(exchange=self.exchange, routing_key=self.routing_key, body=self.body)
            self.logger.info("{0} messages published.".format(str(self.sent_message_count)))
            time.sleep(self.timeout)


class TestMQTTDoSAttack(unittest.TestCase):
    def setUp(self):
        self.amqp_dos_attack = AMQPDoSAttack()

    def tearDown(self):
        pass

    def test_name(self):
        self.assertEqual("AMQP DoS Attack", self.amqp_dos_attack.get_attack_name())

    def test_inputs(self):
        inputs = self.amqp_dos_attack.get_inputs()
        self.assertIsNotNone(inputs)
        self.assertGreater(len(inputs), 0, "Non inserted inputs")
        self.assertEquals(len(inputs), 7)

    def test_non_initialized_inputs(self):
        inputs = self.amqp_dos_attack.get_inputs()
        for _input in inputs:
            value = getattr(self.amqp_dos_attack, _input.get_name())
            self.assertTrue(value is None or type(value) == _input.get_type())

    def test_after_getting_inputs(self):
        example_inputs = ["a.b.c.d", "pen-queue", "pen-exchange", "pen-routing-key", "peniot-payload", "pen-exh-type",
                          13.2]
        for index, _input in enumerate(example_inputs):
            self.amqp_dos_attack.inputs[index].set_value(_input)

        # Previously it should not be set
        self.assertIsNone(self.amqp_dos_attack.connection)

        super(AMQPDoSAttack, self.amqp_dos_attack).run()

        inputs = self.amqp_dos_attack.get_inputs()
        for index, _input in enumerate(inputs):
            value = getattr(self.amqp_dos_attack, _input.get_name())
            self.assertEqual(example_inputs[index], value)

    def test_dos_attack(self):
        def run_attack():
            example_inputs = ["localhost", "peniot-queue", "peniot-exchange", "peniot-routing-key", "peniot-body",
                              "direct", 1]
            for index, _input in enumerate(example_inputs):
                self.amqp_dos_attack.inputs[index].set_value(_input)

            self.amqp_dos_attack.run()

        print "* If server is not initialized this test will not execute properly."
        p = multiprocessing.Process(target=run_attack, name="DoS Attack")
        p.start()
        time.sleep(5)
        if p.is_alive():
            p.terminate()
            p.join()


if __name__ == '__main__':
    unittest.main()


================================================
FILE: src/protocols/AMQP/attacks/amqp_fuzzing_attack_suite.py
================================================
from amqp_payload_size_fuzzer import *
from amqp_random_payload_fuzzing import *
from Entity.attack_suite import AttackSuite


class AMQPFuzzingAttackSuite(AttackSuite):

    def __init__(self):
        attacks = [AMQPRandomPayloadFuzzingAttack(), AMQPPayloadSizeFuzzerAttack()]
        AttackSuite.__init__(self, "AMQP Fuzzing Attack Suite", attacks)


class TestAMQPFuzzingAttackSuite(unittest.TestCase):
    def setUp(self):
        self.amqp_fuzzing_attack_suite = AMQPFuzzingAttackSuite()

    def tearDown(self):
        pass

    def test_name(self):
        self.assertEqual("AMQP Fuzzing Attack Suite", self.amqp_fuzzing_attack_suite.get_attack_suite_name())

    def test_attack_list(self):
        attacks = self.amqp_fuzzing_attack_suite.get_attacks()
        self.assertIsNotNone(attacks)
        self.assertGreater(len(attacks), 0, "Non inserted attacks")
        self.assertEquals(len(attacks), 2)

    def test_attacks(self):
        attacks = self.amqp_fuzzing_attack_suite.get_attacks()
        for attack in attacks:
            p = multiprocessing.Process(target=attack.run, name=attack.get_attack_name())
            p.start()
            time.sleep(5)
            if p.is_alive():
                p.terminate()
                p.join()


if __name__ == '__main__':
    unittest.main()


================================================
FILE: src/protocols/AMQP/attacks/amqp_payload_size_fuzzer.py
================================================
import logging
import multiprocessing
import random
import signal
import time
import unittest

import pika

from Entity.attack import Attack
from Entity.input_format import InputFormat


class AMQPPayloadSizeFuzzerAttack(Attack):
    """
    AMQP Protocol - Payload Size Fuzzer Attack module
    It is created to test any AMQP device as black box test with malformed or semi-malformed inputs
    """
    # Input Fields
    host = "localhost"
    queue = "peniot-queue"
    exchange = "peniot-exchange"
    routing_key = "peniot-routing-key"
    payload = None
    exchange_type = "direct"
    turn = 10

    # Misc Members
    connection = None
    channel = None
    logger = None
    sent_message_count = 0
    max_payload_length = 2 ** 32
    stopped_flag = False

    def __init__(self):
        default_parameters = ["", "", "", "", "", "", 10]
        inputs = [
            InputFormat("Host Name", "host", "localhost", str, mandatory=True),
            InputFormat("Queue Name", "queue", "peniot-queue", str, mandatory=True),
            InputFormat("Exchange Name", "exchange", "peniot-exchange", str, mandatory=True),
            InputFormat("Routing Key", "routing_key", "peniot-routing-key", str, mandatory=True),
            InputFormat("Payload", "payload", "", str, mandatory=True),
            InputFormat("Exchange Type", "exchange_type", "direct", str, mandatory=True),
            InputFormat("Fuzzing Turn", "turn", 10, int)
        ]
        Attack.__init__(self, "AMQP Payload Size Fuzzer Attack", inputs, default_parameters,
                        "    AMQP Payload size fuzzer attack description")

        logging.basicConfig(level=logging.DEBUG, format="%(asctime)s:%(levelname)s:%(name)s:%(message)s")

        # Signal handler to exit from function
        signal.signal(signal.SIGINT, self.signal_handler)

    def signal_handler(self, sig, frame):
        self.stop_attack()

    def stop_attack(self):
        self.logger.info("Connection will be closed")
        self.stopped_flag = True
        if self.connection is not None:
            self.connection.close()
        time.sleep(2)  # Sleep two seconds so the user can see the message

    def pre_attack_init(self):
        try:
            assert self.turn >= 2
        except AssertionError as e:
            raise
        # Get connection and channel
        self.connection = pika.BlockingConnection(pika.ConnectionParameters(host=self.host))
        self.channel = self.connection.channel()

        # Create exchange
        self.channel.exchange_declare(exchange=self.exchange, exchange_type=self.exchange_type)

        # Define queue to store
        self.channel.queue_declare(queue=self.queue)

    def run(self):
        Attack.run(self)
        self.pre_attack_init()

        assert self.turn >= 2
        # Fill the size list as randomly generated
        size_list = [0, self.max_payload_length]
        size_list.extend([random.randint(0, self.max_payload_length) for _ in range(self.turn - 2)])

        fuzzing = 0
        self.logger.info("Size payload fuzzing is started. Please consider it may take some time.")
        for payload_size in size_list:

            if self.stopped_flag is True:
                break
            # Create payload and send it
            random_strings = "".join([chr(_) for _ in range(65, 91)]) + "".join([chr(_) for _ in range(97, 123)])
            random_character = random.choice(random_strings)
            sized_payload = random_character * payload_size
            self.channel.basic_publish(exchange=self.exchange, routing_key=self.routing_key, body=sized_payload)

            # Informative procedures
            self.logger.info("Turn {0} is completed".format(fuzzing + 1))
            self.sent_message_count += 1
            fuzzing += 1
            time.sleep(1)

        if self.stopped_flag is False:
            self.logger.info("Payload size attack is finished.")


class TestCoAPPayloadSizeAttack(unittest.TestCase):
    def setUp(self):
        self.amqp_payload_size_fuzzer = AMQPPayloadSizeFuzzerAttack()

    def tearDown(self):
        pass

    def test_name(self):
        self.assertEqual("AMQP Payload Size Fuzzer Attack", self.amqp_payload_size_fuzzer.get_attack_name())

    def test_inputs(self):
        inputs = self.amqp_payload_size_fuzzer.get_inputs()
        self.assertIsNotNone(inputs)
        self.assertGreater(len(inputs), 0, "Non inserted inputs")
        self.assertEquals(len(inputs), 7)

    def test_non_initialized_inputs(self):
        inputs = self.amqp_payload_size_fuzzer.get_inputs()
        for _input in inputs:
            value = getattr(self.amqp_payload_size_fuzzer, _input.get_name())
            self.assertTrue(value is None or type(value) == _input.get_type())

    def test_after_getting_inputs(self):
        example_inputs = ["localhost", "peniot-queue", "peniot-exchange", "peniot-routing-key", "peniot-body", "direct",
                          5]
        for index, _input in enumerate(example_inputs):
            self.amqp_payload_size_fuzzer.inputs[index].set_value(_input)

        # Previously it should not be set
        self.assertIsNone(self.amqp_payload_size_fuzzer.connection)

        super(AMQPPayloadSizeFuzzerAttack, self.amqp_payload_size_fuzzer).run()

        inputs = self.amqp_payload_size_fuzzer.get_inputs()
        for index, _input in enumerate(inputs):
            value = getattr(self.amqp_payload_size_fuzzer, _input.get_name())
            self.assertEqual(example_inputs[index], value)

    def test_invalid_fuzzing_turn(self):
        example_inputs = ["localhost", "peniot-queue", "peniot-exchange", "peniot-routing-key", "peniot-body", "direct",
                          1]
        for index, _input in enumerate(example_inputs):
            self.amqp_payload_size_fuzzer.inputs[index].set_value(_input)

        super(AMQPPayloadSizeFuzzerAttack, self.amqp_payload_size_fuzzer).run()
        try:
            self.amqp_payload_size_fuzzer.pre_attack_init()
        except AssertionError as e:
            self.assertTrue(True)

    def test_payload_size_fuzzing_attack(self):
        def run_attack():
            example_inputs = ["localhost", "peniot-queue", "peniot-exchange", "peniot-routing-key", "peniot-body",
                              "direct", 3]
            for index, _input in enumerate(example_inputs):
                self.amqp_payload_size_fuzzer.inputs[index].set_value(_input)

            try:
                self.amqp_payload_size_fuzzer.run()
            except Exception as e:
                self.assertTrue(False)

        print "* If server is not initialized this test will not execute properly."
        p = multiprocessing.Process(target=run_attack, name="DoS Attack")
        p.start()
        time.sleep(5)
        if p.is_alive():
            p.terminate()
            p.join()


if __name__ == '__main__':
    unittest.main()


================================================
FILE: src/protocols/AMQP/attacks/amqp_random_payload_fuzzing.py
================================================
import logging
import multiprocessing
import random
import signal
import time
import unittest

import pika

from Entity.attack import Attack
from Entity.input_format import InputFormat
from Utils.FuzzerUtil import radamsa_util as rdm


class AMQPRandomPayloadFuzzingAttack(Attack):
    """
    AMQP Protocol - Random Payload Fuzzing Attack module
    """
    # Input Fields
    host = "localhost"
    queue = "peniot-queue"
    exchange = "peniot-exchange"
    routing_key = "peniot-routing-key"
    payload = None
    exchange_type = "direct"
    turn = 10
    count = 1

    # Misc Members
    connection = None
    channel = None
    logger = None
    sent_message_count = 0
    max_length_of_random_payload = 100
    stopped_flag = False

    def __init__(self):
        default_parameters = ["", "", "", "", "", "", 10, 1]
        inputs = [
            InputFormat("Host Name", "host", "localhost", str, mandatory=True),
            InputFormat("Queue Name", "queue", "peniot-queue", str, mandatory=True),
            InputFormat("Exchange Name", "exchange", "peniot-exchange", str, mandatory=True),
            InputFormat("Routing Key", "routing_key", "peniot-routing-key", str, mandatory=True),
            InputFormat("Payload", "payload", "", str),
            InputFormat("Exchange Type", "exchange_type", "direct", str, mandatory=True),
            InputFormat("Fuzzing Turn", "turn", 10, int),
            InputFormat("Fuzzing Count", "count", 1, int)
        ]

        Attack.__init__(self, "AMQP Random Payload Fuzzing Attack", inputs, default_parameters,
                        "    It creates a random payload and sends \n"
                        "    this payload to the client.")

        logging.basicConfig(level=logging.DEBUG, format="%(asctime)s:%(levelname)s:%(name)s:%(message)s")

        # Signal handler to exit from function
        signal.signal(signal.SIGINT, self.signal_handler)

    def signal_handler(self, sig, frame):
        self.stop_attack()

    def stop_attack(self):
        self.logger.info("Connection will be closed")
        self.stopped_flag = True
        if self.connection is not None:
            self.connection.close()
        time.sleep(2)  # Sleep two seconds so the user can see the message

    def pre_attack_init(self):
        # Get connection and channel
        self.connection = pika.BlockingConnection(pika.ConnectionParameters(host=self.host))
        self.channel = self.connection.channel()

        # Create exchange
        self.channel.exchange_declare(exchange=self.exchange, exchange_type=self.exchange_type)

        # Define queue to store
        self.channel.queue_declare(queue=self.queue)

    def run(self):
        Attack.run(self)
        self.pre_attack_init()

        payload = self.payload
        if payload is None:
            # Create seed with randomly
            length = random.randint(1, self.max_length_of_random_payload)
            payload = "".join([chr(random.randint(1, 127)) for _ in range(length)])

        self.logger.info("Random payload fuzzing is started.")
        for fuzzing in range(self.turn):

            if self.stopped_flag is True:
                break
            while True:
                try:
                    returned_strings = rdm.get_ascii_decodable_radamsa_malformed_input(payload, self.count)
                    if type(returned_strings) == list:
                        fuzzer_messages = [string.decode("utf-8") for string in returned_strings]
                    else:
                        fuzzer_messages = returned_strings.decode("utf-8")
                    break
                except UnicodeDecodeError:
                    continue
            # Check whether result is list or not
            if type(fuzzer_messages) == list:
                for message in fuzzer_messages:
                    self.channel.basic_publish(exchange=self.exchange, routing_key=self.routing_key, body=message)
                    # Increment sent message count
                    self.sent_message_count += 1
            else:
                self.channel.basic_publish(exchange=self.exchange, routing_key=self.routing_key, body=fuzzer_messages)
                # Increment sent message count
                self.sent_message_count += 1
            time.sleep(1)
            self.logger.info("Turn {0} is completed".format(fuzzing + 1))

        if self.stopped_flag is False:
            self.logger.info("Random payload fuzzing is finished.")

        if self.connection is not None:
            self.connection.close()


class TestAMQPRandomPayloadAttack(unittest.TestCase):
    def setUp(self):
        self.amqp_random_payload_fuzzer = AMQPRandomPayloadFuzzingAttack()

    def tearDown(self):
        pass

    def test_name(self):
        self.assertEqual("AMQP Random Payload Fuzzing Attack", self.amqp_random_payload_fuzzer.get_attack_name())

    def test_inputs(self):
        inputs = self.amqp_random_payload_fuzzer.get_inputs()
        self.assertIsNotNone(inputs)
        self.assertGreater(len(inputs), 0, "Non inserted inputs")
        self.assertEquals(len(inputs), 8)

    def test_non_initialized_inputs(self):
        inputs = self.amqp_random_payload_fuzzer.get_inputs()
        for _input in inputs:
            value = getattr(self.amqp_random_payload_fuzzer, _input.get_name())
            self.assertTrue(value is None or type(value) == _input.get_type())

    def test_after_getting_inputs(self):
        example_inputs = ["localhost", "peniot-queue", "peniot-exchange", "peniot-routing-key", "peniot-body", "direct",
                          13, 12]
        for index, _input in enumerate(example_inputs):
            self.amqp_random_payload_fuzzer.inputs[index].set_value(_input)

        # Previously it should not be set
        self.assertIsNone(self.amqp_random_payload_fuzzer.connection)

        super(AMQPRandomPayloadFuzzingAttack, self.amqp_random_payload_fuzzer).run()

        inputs = self.amqp_random_payload_fuzzer.get_inputs()
        for index, _input in enumerate(inputs):
            value = getattr(self.amqp_random_payload_fuzzer, _input.get_name())
            self.assertEqual(example_inputs[index], value)

    def test_invalid_fuzzing_turn(self):
        example_inputs = ["localhost", "peniot-queue", "peniot-exchange", "peniot-routing-key", "peniot-body", "direct",
                          1, 11]
        for index, _input in enumerate(example_inputs):
            self.amqp_random_payload_fuzzer.inputs[index].set_value(_input)

        super(AMQPRandomPayloadFuzzingAttack, self.amqp_random_payload_fuzzer).run()
        try:
            self.amqp_random_payload_fuzzer.pre_attack_init()
        except AssertionError as e:
            self.assertTrue(True)

    def test_random_payload_fuzzing_attack(self):
        def run_attack():
            example_inputs = ["localhost", "peniot-queue", "peniot-exchange", "peniot-routing-key", "peniot-body",
                              "direct", 5, 1]
            for index, _input in enumerate(example_inputs):
                self.amqp_random_payload_fuzzer.inputs[index].set_value(_input)

            try:
                self.amqp_random_payload_fuzzer.run()
            except Exception as e:
                self.assertTrue(False)

        print "* If server is not initialized this test will not execute properly."
        p = multiprocessing.Process(target=run_attack, name=self.amqp_random_payload_fuzzer.get_attack_name())
        p.start()
        time.sleep(15)
        if p.is_alive():
            p.terminate()
            p.join()


if __name__ == '__main__':
    unittest.main()


================================================
FILE: src/protocols/AMQP/examples/__init__.py
================================================
"""
    This package contains the following functionalities:

    1) AMQP Sender Example
    2) AMQP Receiver Example
"""


================================================
FILE: src/protocols/AMQP/examples/receiver_example.py
================================================
import pika

import argparse
import logging
import signal
import sys
import time

DEFAULT_BROKER_HOST = "localhost"
DEFAULT_QUEUE_NAME = "peniot-queue"
DEFAULT_EXCHANGE = "peniot-exchange"
DEFAULT_ROUTING_KEY = "peniot-routing-key"
DEFAULT_BODY = "peniot-body"

logging.basicConfig(level=logging.DEBUG, format="%(asctime)s:%(levelname)s:%(name)s : %(message)s")
logger = logging.getLogger("AMQP Receiver Example")

global_connection = None

"""
    AMQP Example Receiver
"""


def signal_handler(sig, frame):
    global global_connection
    logger.info("Connection will be closed")
    if global_connection is not None:
        global_connection.close()
    sys.exit(0)


def callback(ch, method, properties, body):
    logger.info("Received %r" % body)


def receive_procedure(channel_to_receive, queue_name=DEFAULT_QUEUE_NAME):
    """
    Sending procedure for AMQP protocol
    :param channel_to_receive: Channel means which is created given host name
    :param queue_name: Queue from which consume message
    :return: None
    """
    # Signal handler to exit from function
    signal.signal(signal.SIGINT, signal_handler)

    # Start consuming
    channel_to_receive.basic_consume(callback, queue=queue_name, no_ack=True)
    channel_to_receive.start_consuming()


if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument("-b", "--broker", help="Broker host name or IP address", default=DEFAULT_BROKER_HOST)
    parser.add_argument("-q", "--queue", help="Queue name to subscribe", default=DEFAULT_QUEUE_NAME)
    parser.add_argument("-e", "--exchange", help="Name of exchange", default=DEFAULT_EXCHANGE)
    parser.add_argument("-r", "--routing_key", help="Routing key (endpoint)", default=DEFAULT_ROUTING_KEY)
    parser.add_argument("-c", "--content", help="Content of message body", default=DEFAULT_BODY)
    args = parser.parse_args()

    # Get connection and channel
    connection = pika.BlockingConnection(pika.ConnectionParameters(host=args.broker))
    global_connection = connection
    channel = connection.channel()

    channel.queue_bind(queue=args.queue, exchange=args.exchange, routing_key=args.routing_key)

    # Start sending procedure
    receive_procedure(channel, args.queue)


================================================
FILE: src/protocols/AMQP/examples/sender_example.py
================================================
import pika

import argparse
import logging
import signal
import sys
import time

DEFAULT_BROKER_HOST = "localhost"
DEFAULT_QUEUE_NAME = "peniot-queue"
DEFAULT_EXCHANGE = "peniot-exchange"
DEFAULT_ROUTING_KEY = "peniot-routing-key"
DEFAULT_BODY = "peniot-body"
DEFAULT_EXCHANGE_TYPE = "direct"

logging.basicConfig(level=logging.DEBUG, format="%(asctime)s:%(levelname)s:%(name)s : %(message)s")
logger = logging.getLogger("AMQP Sender Example")

global_connection = None

"""
    AMQP Example Sender
"""


def signal_handler(sig, frame):
    global global_connection
    logger.info("Connection will be closed")
    if global_connection is not None:
        global_connection.close()
    sys.exit(0)


def send_procedure(channel_to_send, exchange=DEFAULT_EXCHANGE, routing_key=DEFAULT_ROUTING_KEY, body=DEFAULT_BODY):
    """
    Sending procedure for AMQP protocol
    :param channel_to_send: Channel means which is created given host name
    :param exchange: Name of exchange
    :param routing_key: Routing key which is similar to endpoint this context
    :param body: Body of messages
    :return: None
    """
    # Signal handler to exit from function
    signal.signal(signal.SIGINT, signal_handler)

    publish_content = 0
    while True:
        channel_to_send.basic_publish(exchange=exchange, routing_key=routing_key, body=body + " " + str(publish_content))
        time.sleep(2)
        publish_content += 1
        logger.info("Message {0} is published".format(publish_content))


if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument("-b", "--broker", help="Broker host name or IP address", default=DEFAULT_BROKER_HOST)
    parser.add_argument("-q", "--queue", help="Queue name to subscribe", default=DEFAULT_QUEUE_NAME)
    parser.add_argument("-e", "--exchange", help="Name of exchange", default=DEFAULT_EXCHANGE)
    parser.add_argument("-r", "--routing_key", help="Routing key (endpoint)", default=DEFAULT_ROUTING_KEY)
    parser.add_argument("-c", "--content", help="Content of message body", default=DEFAULT_BODY)
    parser.add_argument("-x", "--exchange_type", help="Type of exchange", default=DEFAULT_EXCHANGE_TYPE)
    args = parser.parse_args()

    # Get connection and channel
    connection = pika.BlockingConnection(pika.ConnectionParameters(host=args.broker))
    global_connection = connection
    channel = connection.channel()

    # Create exchange
    channel.exchange_declare(exchange=args.exchange, exchange_type=DEFAULT_EXCHANGE_TYPE)

    # Define queue to store
    channel.queue_declare(queue=args.queue)

    # Start sending procedure
    send_procedure(channel, args.exchange, args.routing_key, args.content)


================================================
FILE: src/protocols/BLE/Adafruit_BLESniffer/.gitignore
================================================
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]

*.pcap
logs/


================================================
FILE: src/protocols/BLE/Adafruit_BLESniffer/API Manifest.txt
================================================
API Manifest.txt
documentation.html
example.py
LICENSE.txt
Nordic Semiconductor Sniffer API Guide.pdf
sniffer_uart_protocol.xlsx

wireshark_dissector_source
	packet-btle.c
	packet-nordic_ble.c

SnifferAPI
	CaptureFiles.py
	Devices.py
	Exceptions.py
	Logger.py
	myVersion.py
	Notifications.py
	Packet.py
	Sniffer.py
	SnifferCollector.py
	UART.py
	Version.py
	__init__.py


================================================
FILE: src/protocols/BLE/Adafruit_BLESniffer/LICENSE.txt
================================================
All files in this package is released under the license below, except the 
Wireshark dissector source files packet-nordic_ble.c and packet-btle.c.
The Wireshark dissector source files are released under the 
GNU General Public License as published by the Free Software Foundation; 
either version 2 of the License, or (at your option) any later version.
=

Copyright (c) 2014, Nordic Semiconductor ASA

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
 

================================================
FILE: src/protocols/BLE/Adafruit_BLESniffer/README.md
================================================
# Python API for Bluefruit LE Sniffer 

This repository contains the Python API for Adafruit's Bluefruit LE Sniffer, and our easy to use API wrapper.

It has been tested on the following platforms using Python 2.7:

- OSX 10.10
- Windows 7 x64
- Ubuntu 14.04

## Related Links

Bluefruit LE Sniffer product page: https://www.adafruit.com/product/2269
Bluefruit LE Sniffer Learning Guide: https://learn.adafruit.com/introducing-the-adafruit-bluefruit-le-sniffer/introduction

# Sniffer Python Wrapper

Running sniffer.py in this folder on the Bluefruit LE Friend Sniffer Edition board will cause the device to scan for Bluetooth LE devices in range, and log any data from the selected device to a libpcap file (in `logs/capture.pcap`) that can be opened in Wireshark.

The current example does not enable live streaming of data directly into Wireshark via named pipes since this would require a pre-compiled utility for each platform, but it should be possible to implement this on your platform if required.


## Using sniffer.py

To use sniffer.py, simply specify the serial port where the sniffer can be found (ex. `COM14` on Windows, `/dev/tty.usbmodem1412311` on OS X, `/dev/ttyACM0` or Linux, etc.):

```
python sniffer.py /dev/tty.usbmodem1412311
```

**Note:** You will need to run python with `sudo` on Linux to allow the log file to be created, so `sudo python sniffer.py /dev/ttyACM0`, etc..

This will create a new log file and start scanning for BLE devices, which should result in the following menu:

```
$ python sniffer.py /dev/tty.usbmodem1412311
Logging data to logs/capture.pcap
Connecting to sniffer on /dev/tty.usbmodem1412311
Scanning for BLE devices (5s) ...
Found 2 BLE devices:

  [1] "" (14:99:E2:05:29:CF, RSSI = -85)
  [2] "" (E7:0C:E1:BE:87:66, RSSI = -49)

Select a device to sniff, or '0' to scan again
> 
```

Simply select the device you wish to sniff, and it will start logging traffic from the specified device.

Type **CTRL+C** to stop sniffing and quit the application, closing the libpcap log file.

**NOTE:** You may need to remove the sniffer and re-insert it before starting a new session if you see any unusual error messages running sniffer.py.

## Requirements

This Python script was written and tested on **Python 2.7.6**, and will require that both Python 2.7 and **pySerial** are installed on your system.


================================================
FILE: src/protocols/BLE/Adafruit_BLESniffer/SnifferAPI/CaptureFiles.py
================================================
from __future__ import absolute_import
import time
import os
import logging
from . import Logger

LINKTYPE_BLUETOOTH_LE_LL = 251
LINKTYPE_NORDIC_BLE = 157

MAGIC_NUMBER = 0xa1b2c3d4
VERSION_MAJOR = 2
VERSION_MINOR = 4
THISZONE = 0
SIGFIGS = 0
SNAPLEN = 0xFFFF
NETWORK = LINKTYPE_NORDIC_BLE


globalHeaderString = [
    ((MAGIC_NUMBER >> 0) & 0xFF),
    ((MAGIC_NUMBER >> 8) & 0xFF),
    ((MAGIC_NUMBER >> 16) & 0xFF),
    ((MAGIC_NUMBER >> 24) & 0xFF),
    ((VERSION_MAJOR >> 0) & 0xFF),
    ((VERSION_MAJOR >> 8) & 0xFF),
    ((VERSION_MINOR >> 0) & 0xFF),
    ((VERSION_MINOR >> 8) & 0xFF),
    ((THISZONE >> 0) & 0xFF),
    ((THISZONE >> 8) & 0xFF),
    ((THISZONE >> 16) & 0xFF),
    ((THISZONE >> 24) & 0xFF),
    ((SIGFIGS >> 0) & 0xFF),
    ((SIGFIGS >> 8) & 0xFF),
    ((SIGFIGS >> 16) & 0xFF),
    ((SIGFIGS >> 24) & 0xFF),
    ((SNAPLEN >> 0) & 0xFF),
    ((SNAPLEN >> 8) & 0xFF),
    ((SNAPLEN >> 16) & 0xFF),
    ((SNAPLEN >> 24) & 0xFF),
    ((NETWORK >> 0) & 0xFF),
    ((NETWORK >> 8) & 0xFF),
    ((NETWORK >> 16) & 0xFF),
    ((NETWORK >> 24) & 0xFF)
]

captureFilePath = os.path.join(Logger.logFilePath, "capture.pcap")


class CaptureFileHandler:
    def __init__(self, clear=False):
        self.filename = captureFilePath
        self.backupFilename = self.filename+".1"
        if not os.path.isfile(self.filename):
            self.startNewFile()
        elif os.path.getsize(self.filename) > 20000000:
            self.doRollover()
        if clear:
            # clear file
            self.startNewFile()

    def startNewFile(self):
        with open(self.filename, "wb") as f:
            f.write(bytearray(globalHeaderString))

    def doRollover(self):
        try:
            os.remove(self.backupFilename)
        except:  # noqa: E722
            logging.exception("capture file rollover remove backup failed")
        try:
            os.rename(self.filename, self.backupFilename)
            self.startNewFile()
        except:  # noqa: E722
            logging.exception("capture file rollover failed")

    def readLine(self, lineNum):
        line = ""
        with open(self.filename, "r") as f:
            f.seek(lineNum)
            line = f.readline()
        return line

    def readAll(self):
        text = ""
        with open(self.filename, "r") as f:
            text = f.read()
        return text

    def writeString(self, msgString):
        with open(self.filename, "ab") as f:
            f.write(msgString)

    def writeList(self, msgList):
        self.writeString(bytearray(msgList))

    def writePacketList(self, packetList):
        self.writeList(self.makePacketHeader(len(packetList)) + packetList)

    def writePacket(self, packet):
        self.writePacketList([packet.boardId] + packet.getList())

    def makePacketHeader(self, length):

        timeNow = time.time()

        TS_SEC = int(timeNow)
        TS_USEC = int((timeNow-TS_SEC)*1000000)
        INCL_LENGTH = length
        ORIG_LENGTH = length

        headerString = [
            ((TS_SEC >> 0) & 0xFF),
            ((TS_SEC >> 8) & 0xFF),
            ((TS_SEC >> 16) & 0xFF),
            ((TS_SEC >> 24) & 0xFF),
            ((TS_USEC >> 0) & 0xFF),
            ((TS_USEC >> 8) & 0xFF),
            ((TS_USEC >> 16) & 0xFF),
            ((TS_USEC >> 24) & 0xFF),
            ((INCL_LENGTH >> 0) & 0xFF),
            ((INCL_LENGTH >> 8) & 0xFF),
            ((INCL_LENGTH >> 16) & 0xFF),
            ((INCL_LENGTH >> 24) & 0xFF),
            ((ORIG_LENGTH >> 0) & 0xFF),
            ((ORIG_LENGTH >> 8) & 0xFF),
            ((ORIG_LENGTH >> 16) & 0xFF),
            ((ORIG_LENGTH >> 24) & 0xFF)
        ]
        return headerString


def toList(myString):
    myList = []
    for c in myString:
        myList += [ord(c)]
    return myList


================================================
FILE: src/protocols/BLE/Adafruit_BLESniffer/SnifferAPI/Devices.py
================================================
from __future__ import absolute_import
from . import Notifications
import logging


class DeviceList(Notifications.Notifier):
    def __init__(self, *args, **kwargs):
        Notifications.Notifier.__init__(self, *args, **kwargs)
        logging.info("args: " + str(args))
        logging.info("kwargs: " + str(kwargs))
        self.devices = []

    def __len__(self):
        return len(self.devices)

    def __repr__(self):
        return "Sniffer Device List: "+str(self.asList())

    def clear(self):
        self.devices = []

    def appendOrUpdate(self, newDevice):
        existingDevice = self.find(newDevice)

        # logging.info("appendOrUpdate")

        # Add device to the list of devices being displayed, but only if CRC is OK
        if existingDevice is None:
            self.append(newDevice)
        else:
            updated = False
            if (newDevice.name != "") and (existingDevice.name == ""):
                existingDevice.name = newDevice.name
                updated = True

            if (newDevice.RSSI < (newDevice.RSSI - 5)) or (existingDevice.RSSI > (newDevice.RSSI+2)):  # noqa: E501
                existingDevice.RSSI = newDevice.RSSI
                updated = True

            if updated:
                self.notify("DEVICE_UPDATED", existingDevice)
                # self.updateDeviceDisplay()

    def append(self, device):
        self.devices.append(device)
        self.notify("DEVICE_ADDED", device)

    def find(self, id):
        # logging.info("find type: %s" % str(id.__class__.__name__))
        if type(id) == list:
            for dev in self.devices:
                if dev.address == id:
                    return dev
        elif type(id) == int:
            return self.devices[id]
        elif type(id) == str:
            for dev in self.devices:
                if dev.name in [id, '"'+id+'"']:
                    return dev
        elif id.__class__.__name__ == "Device":
            # logging.info("find Device")
            return self.find(id.address)
        return None

    def remove(self, id):
        if type(id) == list:  # address
            device = self.devices.pop(self.devices.index(self.find(id)))
        elif type(id) == int:
            device = self.devices.pop(id)
        elif type(id) == Device:
            device = self.devices.pop(self.devices.index(self.find(id.address)))
        self.notify("DEVICE_REMOVED", device)
        # self.updateDeviceDisplay()

    # def getSelected(self):
        # for dev in self.devices:
        # if dev.selected:
        # return dev
        # if len(self.devices) ==  1:
        # self.devices[0].selected = True
        # else:
        # return None

    def index(self, device):
        index = 0
        for dev in self.devices:
            if dev.address == device.address:
                return index
            index += 1
        return None

    # def setSelected(self, device):
        # if device in self.devices:
        # for dev in self.devices:
        # dev.selected = False
        # device.selected = True
        # self.notify("DEVICE_SELECTED", device)

    def setFollowed(self, device):
        if device in self.devices:
            for dev in self.devices:
                dev.followed = False
            device.followed = True
        self.notify("DEVICE_FOLLOWED", device)

    # def incrementSelected(self, step = 1):
        # if len(self.devices) > 0:
        # self.setSelected(self.find((self.index(self.getSelected())+step)%len(self.devices)))

    def asList(self):
        return self.devices[:]


class Device:
    def __init__(self, address, name, RSSI, txAdd=1):
        self.address = address
        self.txAdd = txAdd
        self.name = name
        self.RSSI = RSSI
        # self.selected = selected
        self.followed = False

================================================
FILE: src/protocols/BLE/Adafruit_BLESniffer/SnifferAPI/Exceptions.py
================================================
class SnifferTimeout(Exception):
    pass


class UARTPacketError(Exception):
    pass


class InvalidPacketException(Exception):
    pass

# Internal Use


class SnifferWatchDogTimeout(SnifferTimeout):
    pass

# Internal Use


class ExitCodeException(Exception):
    pass


================================================
FILE: src/protocols/BLE/Adafruit_BLESniffer/SnifferAPI/Logger.py
================================================
from __future__ import absolute_import
from __future__ import print_function
import time
import os
import logging
import traceback
import threading
import logging.handlers as logHandlers
from six.moves import range

#################################################################
# This file contains the logger. To log a line, simply write     #
# 'logging.[level]("whatever you want to log")'                    #
# [level] is one of {info, debug, warning, error, critical,        #
#     exception}                                                    #
# See python logging documentation                                #
# As long as Logger.initLogger has been called beforehand, this    #
# will result in the line being appended to the log file        #
#################################################################

try:
    logFilePath = os.path.join(
        os.getenv('appdata'), 'Nordic Semiconductor', 'Sniffer', 'logs')
except AttributeError:
    logFilePath = "logs"

logFileName = os.path.join(logFilePath, 'log.txt')

logHandler = None
logFlusher = None

myMaxBytes = 1000000

# Ensure that the directory we are writing the log file to exists.
# Create our logfile, and write the timestamp in the first line.


def initLogger():
    try:
        # First, make sure that the directory exists
        if not os.path.isdir(logFilePath):
            os.makedirs(logFilePath)

        # If the file does not exist, create it, and save the timestamp
        if not os.path.isfile(logFileName):
            with open(logFileName, "wb") as f:
                f.write('{0}{1}'.format(time.time(), os.linesep).encode())

        global logHandler
        global logFlusher

        logHandler = MyRotatingFileHandler(
            logFileName, mode='a', maxBytes=myMaxBytes, backupCount=3)
        logFormatter = logging.Formatter(
            '%(asctime)s %(levelname)s: %(message)s', datefmt='%d-%b-%Y %H:%M:%S (%z)')
        logHandler.setFormatter(logFormatter)
        logger = logging.getLogger()
        logger.addHandler(logHandler)
        logger.setLevel(logging.INFO)

        logFlusher = LogFlusher(logHandler)
    except:  # noqa: 722
        print("LOGGING FAILED")
        print(traceback.format_exc())
        raise


def shutdownLogger():
    logging.shutdown()

# Clear the log (typically after it has been sent on email)


def clearLog():
    try:
        logHandler.doRollover()
    except:  # noqa: 722
        print("LOGGING FAILED")
        raise


# Returns the timestamp residing on the first line of the logfile.
# Used for checking the time of creation
def getTimestamp():
    try:
        with open(logFileName, "r") as f:
            f.seek(0)
            return f.readline()
    except:  # noqa: 722
        print("LOGGING FAILED")


def addTimestamp():
    try:
        with open(logFileName, "a") as f:
            f.write(str(time.time()) + os.linesep)
    except:  # noqa: 722
        print("LOGGING FAILED")
# Returns the entire content of the logfile. Used when sending emails


def readAll():
    try:
        text = ""
        with open(logFileName, "r") as f:
            text = f.read()
        return text
    except:  # noqa: 722
        print("LOGGING FAILED")


class MyRotatingFileHandler(logHandlers.RotatingFileHandler):
    def doRollover(self):
        try:
            logHandlers.RotatingFileHandler.doRollover(self)
            addTimestamp()
            self.maxBytes = myMaxBytes
        except:  # noqa: 722
            # There have been permissions issues with the log files.
            self.maxBytes += int(myMaxBytes/2)
            # logging.exception("log rollover error")


class LogFlusher(threading.Thread):
    def __init__(self, logHandler):
        threading.Thread.__init__(self)

        self.daemon = True
        self.handler = logHandler
        self.exit = False

        self.start()

    def run(self):
        while not self.exit:
            time.sleep(10)
            self.doFlush()

    def doFlush(self):
        self.handler.flush()
        os.fsync(self.handler.stream.fileno())

    def stop(self):
        self.exit = True


if __name__ == '__main__':
    initLogger()
    for i in range(50):
        logging.info("test log no. "+str(i))
        print("test log no. ", i)


================================================
FILE: src/protocols/BLE/Adafruit_BLESniffer/SnifferAPI/Notifications.py
================================================
from __future__ import absolute_import
import threading


class Notification():
    def __init__(self, key, msg=None):
        if type(key) is not str:
            raise TypeError("Invalid notification key: "+str(key))
        self.key = key
        self.msg = msg

    def __repr__(self):
        return "Notification (key: %s, msg: %s)" % (str(self.key), str(self.msg))


class Notifier():
    def __init__(self, callbacks=[]):
        self.callbacks = {}
        self.callbackLock = threading.RLock()
        # logging.info("callbacks: "+  str(callbacks))
        for callback in callbacks:
            self.subscribe(*callback)

        # logging.info(self.callbacks)

    def subscribe(self, key, callback):
        with self.callbackLock:
            if callback not in self.getCallbacks(key):
                self.getCallbacks(key).append(callback)

    def getCallbacks(self, key):
        with self.callbackLock:
            # logging.info(self.callbacks)
            if key not in self.callbacks:
                self.callbacks[key] = []
            return self.callbacks[key]

    def notify(self, key=None, msg=None, notification=None):
        # logging.info(self.callbacks)
        with self.callbackLock:
            if notification is None:
                notification = Notification(key, msg)

            for callback in self.getCallbacks(notification.key):
                callback(notification)

            for callback in self.getCallbacks("*"):
                callback(notification)

        # logging.info("sending notification: %s" % str(notification))

    def passOnNotification(self, notification):
        self.notify(notification=notification)


================================================
FILE: src/protocols/BLE/Adafruit_BLESniffer/SnifferAPI/Packet.py
================================================
from __future__ import absolute_import
from . import UART, Exceptions, Notifications
import time
import logging
import os
import sys
import serial
from six.moves import range

SLIP_START = 0xAB
SLIP_END = 0xBC
SLIP_ESC = 0xCD
SLIP_ESC_START = SLIP_START+1
SLIP_ESC_END = SLIP_END+1
SLIP_ESC_ESC = SLIP_ESC+1

REQ_FOLLOW = 0x00
RESP_FOLLOW = 0x01
EVENT_DEVICE = 0x02
REQ_SINGLE_PACKET = 0x03
RESP_SINGLE_PACKET = 0x04
EVENT_CONNECT = 0x05
EVENT_PACKET = 0x06
REQ_SCAN_CONT = 0x07
RESP_SCAN_CONT = 0x08
EVENT_DISCONNECT = 0x09
EVENT_ERROR = 0x0A
EVENT_EMPTY_DATA_PACKET = 0x0B
SET_TEMPORARY_KEY = 0x0C
PING_REQ = 0x0D
PING_RESP = 0x0E
TEST_COMMAND_ID = 0x0F
TEST_RESULT_ID = 0x10
UART_TEST_START = 0x11
UART_DUMMY_PACKET = 0x12
SWITCH_BAUD_RATE_REQ = 0x13
SWITCH_BAUD_RATE_RESP = 0x14
UART_OUT_START = 0x15
UART_OUT_STOP = 0x16
SET_ADV_CHANNEL_HOP_SEQ = 0x17
GO_IDLE = 0xFE

ADV_ACCESS_ADDRESS = [0xD6, 0xBE, 0x89, 0x8E]

SYNCWORD_POS = 0
HEADER_LEN_POS = 0
PAYLOAD_LEN_POS = HEADER_LEN_POS+1
PROTOVER_POS = PAYLOAD_LEN_POS+1
PACKETCOUNTER_POS = PROTOVER_POS+1
ID_POS = PACKETCOUNTER_POS+2

BLE_HEADER_LEN_POS = ID_POS+1
FLAGS_POS = BLE_HEADER_LEN_POS+1
CHANNEL_POS = FLAGS_POS+1
RSSI_POS = CHANNEL_POS+1
EVENTCOUNTER_POS = RSSI_POS+1
TIMESTAMP_POS = EVENTCOUNTER_POS+2
BLEPACKET_POS = TIMESTAMP_POS+4
TXADD_POS = BLEPACKET_POS + 4
TXADD_MSK = 0x40
PAYLOAD_POS = BLE_HEADER_LEN_POS

HEADER_LENGTH = 6
BLE_HEADER_LENGTH = 10
PROTOVER = 1

ADV_TYPE_ADV_IND = 0x0
ADV_TYPE_ADV_DIRECT_IND = 0x1
ADV_TYPE_ADV_NONCONN_IND = 0x2
ADV_TYPE_ADV_DISCOVER_IND = 0x6
ADV_TYPE_SCAN_REQ = 0x3
ADV_TYPE_SCAN_RSP = 0x4
ADV_TYPE_CONNECT_REQ = 0x5

VALID_ADV_CHANS = [37, 38, 39]


class PacketReader(Notifications.Notifier):
    def __init__(self, portnum=None, callbacks=[]):
        Notifications.Notifier.__init__(self, callbacks)
        self.portnum = portnum
        self.exit = False
        try:
            self.uart = UART.Uart(portnum)
        except serial.SerialException as e:
            logging.exception("Error opening UART.")
            self.uart = UART.Uart()
        self.packetCounter = 0
        self.lastReceivedPacketCounter = 0
        self.lastReceivedPacket = None

        # self.states = {}

    def setup(self):
        self.findSerialPort()
        self.uart.ser.port = self.portnum
        self.uart.ser.open

    def doExit(self):
        self.exit = True
        if self.uart.ser is not None:
            self.uart.ser.close()

    # This function takes a byte list, encode it in SLIP protocol and return the encoded byte list
    def encodeToSLIP(self, byteList):
        tempSLIPBuffer = []
        tempSLIPBuffer.append(SLIP_START)
        for i in byteList:
            if i == SLIP_START:
                tempSLIPBuffer.append(SLIP_ESC)
                tempSLIPBuffer.append(SLIP_ESC_START)
            elif i == SLIP_END:
                tempSLIPBuffer.append(SLIP_ESC)
                tempSLIPBuffer.append(SLIP_ESC_END)
            elif i == SLIP_ESC:
                tempSLIPBuffer.append(SLIP_ESC)
                tempSLIPBuffer.append(SLIP_ESC_ESC)
            else:
                tempSLIPBuffer.append(i)
        tempSLIPBuffer.append(SLIP_END)
        return tempSLIPBuffer

    # This function uses getSerialByte() function to get SLIP encoded bytes from the serial port
    # and return a decoded byte list
    # Based on https://github.com/mehdix/pyslip/
    def decodeFromSLIP(self, timeout=None):
        dataBuffer = []
        startOfPacket = False
        endOfPacket = False

        while not startOfPacket:
            startOfPacket = (self.getSerialByte(timeout) == SLIP_START)

        while not endOfPacket:
            serialByte = self.getSerialByte(timeout)
            if serialByte == SLIP_END:
                endOfPacket = True
            elif serialByte == SLIP_ESC:
                serialByte = self.getSerialByte()
                if serialByte == SLIP_ESC_START:
                    dataBuffer.append(SLIP_START)
                elif serialByte == SLIP_ESC_END:
                    dataBuffer.append(SLIP_END)
                elif serialByte == SLIP_ESC_ESC:
                    dataBuffer.append(SLIP_ESC)
                else:
                    raise Exceptions.UARTPacketError(
                        "Unexpected character after SLIP_ESC: %d." % serialByte)
            else:
                dataBuffer.append(serialByte)
        return dataBuffer

    # This function read byte chuncks from the serial port and return one byte at a time
    # Based on https://github.com/mehdix/pyslip/
    def getSerialByte(self, timeout=None):
        serialByte = self.uart.readByte(timeout)
        if len(serialByte) != 1:
            raise Exceptions.SnifferTimeout("Packet read timed out.")
        return ord(serialByte)

    def handlePacketHistory(self, packet):
        # Reads and validates packet counter
        if self.lastReceivedPacket and (
            packet.packetCounter != (self.lastReceivedPacket.packetCounter+1)) and (
                self.lastReceivedPacket.packetCounter != 0):
            logging.info("gap in packets, between {} and {}. packet before: {}, packet after: {}"
                         .format(
                             self.lastReceivedPacket.packetCounter,
                             str(packet.packetCounter),
                             str(self.lastReceivedPacket.packetList),
                             str(packet.packetList)
                         ))
        self.lastReceivedPacket = packet

    def getPacket(self, timeout=None):
        packetList = []
        try:
            packetList = self.decodeFromSLIP(timeout)
        except Exceptions.UARTPacketError:
            logging.exception("")
            return None
        else:
            packet = Packet(packetList)
            if packet.valid:
                self.handlePacketHistory(packet)
            return packet

    def useByteQueue(self, useByteQueue=True):
        self.uart.useByteQueue = useByteQueue

    def getByteQueue(self):
        return self.uart.byteQueue

    def sendPacket(self, id, payload, timeout=None):
        packetList = [HEADER_LENGTH] + [len(payload)] + [PROTOVER] + \
            toLittleEndian(self.packetCounter, 2) + [id] + payload
        pkt = self.encodeToSLIP(packetList)
        self.packetCounter += 1
        self.uart.writeList(pkt, timeout)

    def sendScan(self, timeout=None):
        self.sendPacket(REQ_SCAN_CONT, [], timeout)

    def sendFollow(self, addr, txAdd=1, followOnlyAdvertisements=False, timeout=None):
        # TxAdd is a single byte (0 or 1) so we just append it to the address.
        # addr.append(txAdd)
        self.sendPacket(REQ_FOLLOW, addr+[followOnlyAdvertisements], timeout)

    def sendPingReq(self, timeout=1):
        self.sendPacket(PING_REQ, [], timeout)

    def sendTK(self, TK, timeout=None):
        if (len(TK) < 16):
            TK = [0] * (16-len(TK)) + TK
        else:
            TK = TK[:16]
        self.sendPacket(SET_TEMPORARY_KEY, TK, timeout)

        logging.info("Sent key value to sniffer: "+str(TK))
        self.notify("TK_SENT", {"TK": TK})
        return TK

    def sendSwitchBaudRate(self, newBaudRate, timeout=None):
        self.sendPacket(SWITCH_BAUD_RATE_REQ, toLittleEndian(newBaudRate, 4), timeout)

    def switchBaudRate(self, newBaudRate):
        self.uart.switchBaudRate(newBaudRate)

    def sendHopSequence(self, hopSequence):
        for chan in hopSequence:
            if chan not in VALID_ADV_CHANS:
                raise Exceptions.InvalidAdvChannel("%s is not an adv channel" % str(chan))
        payload = [len(hopSequence)] + hopSequence + [37]*(3-len(hopSequence))
        self.sendPacket(SET_ADV_CHANNEL_HOP_SEQ, payload)
        self.notify("NEW_ADV_HOP_SEQ", {"hopSequence": hopSequence})

    def sendGoIdle(self, timeout=None):
        self.sendPacket(GO_IDLE, [], timeout)

    def findSerialPort(self):
        foundPort = False
        iPort = 0  # To avoid COM1 (iPort=0).
        nTicks = 0

        trials = 10
        # comports = self.findSeggerComPorts().keys()

        if self.portnum is not None:
            self.notify("INFO_PRESET")
        else:
            self.notify("INFO_NO_PRESET")

        readTimeout = 1
        iPort = self.portnum if self.portnum is not None else 1
        while not foundPort and not self.exit:

            try:
                self.uart.ser.port = iPort
                try:
                    self.uart.ser.open()
                except:
                    pass
                self.sendPingReq()
                startTime = time.time()
                continueLoop = True
                packetCounter = 0
                while continueLoop and (time.time() < (startTime+1)):
                    packet = self.getPacket(timeout=readTimeout)

                    if packet is None:
                        continueLoop = False
                        raise Exception("None packet")
                    elif packet.id == 0x0E:
                        continueLoop = False
                        fwversion = packet.version
                        self.portnum = self.uart.ser.portstr
                        self.notify("COMPORT_FOUND", {"comPort": self.portnum})
                        self.fwversion = fwversion
                        return
                    else:
                        packetCounter += 1

                if continueLoop:
                    raise Exception("No packet with correct id. Received " +
                                    str(packetCounter)+" packets.")

            except Exception as e:
                if "The system cannot find the file specified." not in str(e):
                    # logging.exception("Error on COM"+str(iPort+1)+": "+str(e))
                    logging.info("Error on port " + str(iPort) + ". file: " +
                                 os.path.basename(sys.exc_info()[2].tb_frame.f_code.co_filename) +
                                 ", line " + str(sys.exc_info()[2].tb_lineno) + ": "+str(e))
                    # logging.exception("error")
                    trials = trials + 1
                    if (trials>9):
                        self.doExit()   #Try to open the port for some time, if can't just exit
                try:
                    if self.uart.ser is not None:
                        self.uart.ser.close()
                except:  # noqa: E722
                    logging.exception("could not close UART")

            if self.portnum is None:
                if type(iPort) != int:
                    iPort = 0
                iPort += 1
                iPort = (iPort % 256)

            if self.portnum is not None or (iPort % 64) == 0:
                nTicks += 1
                self.notify("DEVICE_DISCOVERY_TICK", {"tickNumber": nTicks})
                if readTimeout < 3:
                    readTimeout += 0.1

            # logging.info("iPort: " +str(iPort))
            # logging.info("self.portnum: " +str(self.portnum))

            if self.portnum is not None:
                time.sleep(0.7)
            else:
                time.sleep(0.01)
        return (None, None)


class Packet:

    def __init__(self, packetList):
        try:
            if packetList == []:
                raise Exceptions.InvalidPacketException(
                    "packet list not valid: %s" % str(packetList))
            self.packetList = packetList
            self.readStaticHeader(packetList)
            self.readDynamicHeader(packetList)
            self.readPayload(packetList)

        except Exceptions.InvalidPacketException as e:
            logging.error("Invalid packet: %s" % str(e))
            self.OK = False
            self.valid = False
        except:  # noqa: E722
            logging.exception("packet creation error")
            logging.info("packetList: " + str(packetList))
            self.OK = False
            self.valid = False

    def __repr__(self):
        return "UART packet, type: "+str(self.id)+", PC: "+str(self.packetCounter)

    def readStaticHeader(self, packetList):
        self.headerLength = packetList[HEADER_LEN_POS]
        self.payloadLength = packetList[PAYLOAD_LEN_POS]
        self.protover = packetList[PROTOVER_POS]

    def readDynamicHeader(self, packetList):
        self.header = packetList[0:self.headerLength]
        if self.headerLength == HEADER_LENGTH:
            self.packetCounter = parseLittleEndian(
                packetList[PACKETCOUNTER_POS:PACKETCOUNTER_POS+2])
            self.id = packetList[ID_POS]
        else:
            logging.info("incorrect header length: %d" % self.headerLength)

    def readPayload(self, packetList):
        self.blePacket = None
        self.OK = False

        if not self.validatePacketList(packetList):
            raise Exceptions.InvalidPacketException("packet list not valid: %s" % str(packetList))
        else:
            self.valid = True

        self.payload = packetList[PAYLOAD_POS:PAYLOAD_POS+self.payloadLength]

        if self.id == EVENT_PACKET:
            try:
                self.bleHeaderLength = packetList[BLE_HEADER_LEN_POS]
                if self.bleHeaderLength == BLE_HEADER_LENGTH:
                    self.flags = packetList[FLAGS_POS]
                    self.readFlags()
                    self.channel = packetList[CHANNEL_POS]
                    self.rawRSSI = packetList[RSSI_POS]
                    self.RSSI = -self.rawRSSI
                    self.txAdd = packetList[TXADD_POS] & TXADD_MSK
                    self.eventCounter = parseLittleEndian(
                        packetList[EVENTCOUNTER_POS:EVENTCOUNTER_POS+2])
                    self.timestamp = parseLittleEndian(packetList[TIMESTAMP_POS:TIMESTAMP_POS+2])
                    # self.payload = packetList[13:(4+self.length)]
                    # The hardware adds a padding byte which isn't sent on air.
                    # The following removes it.
                    self.packetList.pop(BLEPACKET_POS+6)
                    self.payloadLength -= 1
                    if packetList[PAYLOAD_LEN_POS] > 0:
                        packetList[PAYLOAD_LEN_POS] -= 1

                if self.OK:
                    try:
                        self.blePacket = BlePacket(packetList[BLEPACKET_POS:])
                    except:  # noqa: E722
                        logging.exception("blePacket error")
            except:  # noqa: E722
                # malformed packet
                logging.exception("packet error")
                self.OK = False
        elif self.id == PING_RESP:
            self.version = parseLittleEndian(self.packetList[PAYLOAD_POS:PAYLOAD_POS+2])
        elif self.id == SWITCH_BAUD_RATE_RESP or self.id == SWITCH_BAUD_RATE_REQ:
            self.baud_rate = parseLittleEndian(packetList[PAYLOAD_POS:PAYLOAD_POS+4])
        elif self.id == TEST_RESULT_ID:
            self.testId = packetList[PAYLOAD_POS]
            self.testLength = packetList[PAYLOAD_POS+1]
            self.testPayload = packetList[PAYLOAD_POS+2:]

    def readFlags(self):
        self.crcOK = not not (self.flags & 1)
        self.direction = not not (self.flags & 2)
        self.encrypted = not not (self.flags & 4)
        self.micOK = not not (self.flags & 8)
        self.OK = self.crcOK and (self.micOK or not self.encrypted)

    def getList(self):
        return self.packetList

    def validatePacketList(self, packetList):
        try:
            if (packetList[PAYLOAD_LEN_POS] + packetList[HEADER_LEN_POS]) == len(packetList):
                return True
            else:
                return False
        except:  # noqa: E722
            logging.exception("Invalid packet: %s" % str(packetList))
            return False


class BlePacket():
    def __init__(self, packetList):
        self.extractAccessAddress(packetList)
        if self.accessAddress == ADV_ACCESS_ADDRESS:
            self.extractAdvType(packetList)
            self.extractAdvAddress(packetList)
            self.extractName(packetList)
        self.extractLength(packetList)
        self.payload = packetList[6:]

    def __repr__(self):
        return "BLE packet, AAddr: "+str(self.accessAddress)

    def extractAccessAddress(self, packetList):
        self.accessAddress = packetList[0:4]

    def extractAdvType(self, packetList):
        self.advType = (packetList[4] & 15)

    def extractAdvAddress(self, packetList):
        addr = None
        if (self.advType == 0 or self.advType == 1 or self.advType == 2 or self.advType == 4
           or self.advType == 6):
            addrType = not not packetList[4] & 64
            addr = packetList[6:12]
            addr.reverse()
            addr += [addrType]
        elif (self.advType == 3 or self.advType == 5):
            addrType = not not packetList[4] & 64
            addr = packetList[12:18]
            addr.reverse()
            addr += [addrType]

        self.advAddress = addr

    def extractName(self, packetList):
        name = ""
        if (self.advType == 0 or self.advType == 2 or self.advType == 6):
            i = 12
            while i < len(packetList):
                length = packetList[i]
                if (i+length+1) > len(packetList) or length == 0:
                    break
                type = packetList[i+1]
                if type == 8 or type == 9:
                    nameList = packetList[i+2:i+length+1]
                    name = ""
                    for j in nameList:
                        name += chr(j)
                i += (length+1)
            name = '"'+name+'"'
        elif (self.advType == 1):
            name = "[ADV_DIRECT_IND]"

        self.name = name  # .decode(encoding="UTF-8")

    def extractLength(self, packetList):
        length = packetList[5]
        self.length = length


def parseLittleEndian(list):
    total = 0
    for i in range(len(list)):
        total += (list[i] << (8*i))
    return total


def toLittleEndian(value, size):
    list = [0]*size
    for i in range(size):
        list[i] = (value >> (i*8)) % 256
    return list


================================================
FILE: src/protocols/BLE/Adafruit_BLESniffer/SnifferAPI/Sniffer.py
================================================
from __future__ import absolute_import
import sys
import os
import threading
import logging
from . import SnifferCollector
from . import Logger, Version


def initLog():
    Logger.initLogger()

    logging.info("--------------------------------------------------------")
    logging.info("Software version: " + Version.getReadableVersionString(Version.getRevision()))


initLog()


class Sniffer(threading.Thread, SnifferCollector.SnifferCollector):

    # Sniffer constructor. portnum argument is optional. If not provided,
    # the software will try to locate the firwmare automatically (may take time).
    # NOTE: portnum is 0-indexed, while Windows names are 1-indexed
    def __init__(self, portnum=None):
        threading.Thread.__init__(self)
        SnifferCollector.SnifferCollector.__init__(self, portnum)
        self.daemon = True

        self.subscribe("COMPORT_FOUND", self.comPortFound)

    # API STARTS HERE

    # Get [number] number of packets since last fetch (-1 means all)
    # Note that the packet buffer is limited to about 80000 packets.
    # Returns: A list of Packet objects
    def getPackets(self, number=-1):
        return self._getPackets(number)

    # Get a list of devices which are advertising in range of the Sniffer.
    # Returns: A DeviceList object.
    def getDevices(self):
        return self._devices

    # Signal the Sniffer firmware to sniff a specific device.
    # "device" argument is of type Device
    # if "followOnlyAdvertisements" is True the sniffer will not follow the device into a connection.  # noqa: E501
    # Returns nothing
    def follow(self, device=None, followOnlyAdvertisements=False):
        self._startFollowing(device, followOnlyAdvertisements)

    # Signal the Sniffer to scan for advertising devices by sending the REQ_SCAN_CONT UART packet.
    # This will cause it to stop sniffing any device it is sniffing at the moment.
    # Returns nothing.
    def scan(self):
        self._startScanning()

    # Send a temporary key to the sniffer to use when decrypting encrypted communication.
    # Returns nothing.
    def sendTK(self, TK):
        self._packetReader.sendTK(TK)

    # Set the preset COM port number. Only use this during startup. Set to None to search all ports.
    # Returns nothing.
    def setPortnum(self, portnum):
        self._portnum = portnum
        self._packetReader.portnum = portnum

    # Set the order in which the sniffer cycles through adv channels when following a device.
    # hopSequence must be a list of length 1, 2, or 3, and each item must be either 37, 38, or 39.
    # The same channel cannot occur more than once in the list.
    # Returns nothing.
    def setAdvHopSequence(self, hopSequence):
        self._packetReader.sendHopSequence(hopSequence)

    # Gracefully shut down the sniffer threads and connections.
    # Returns nothing.
    def doExit(self):
        return self._doExit()

    # NOTE: Methods with decorator @property can be used as (read-only) properties
    # Example: mMissedPackets = sniffer.missedPackets

    # The number of missed packets over the UART, as determined by the packet counter in the header.
    @property
    def missedPackets(self):
        return self._missedPackets

    # The number of packets which were sniffed in the last BLE connection.
    # From CONNECT_REQ until link loss/termination.
    @property
    def packetsInLastConnection(self):
        return self._packetsInLastConnection

    # The packet counter value of the last received connect request.
    @property
    def connectEventPacketCounterValue(self):
        return self._connectEventPacketCounterValue

    # A Packet object containing the last received connect request.
    @property
    def currentConnectRequest(self):
        return self._currentConnectRequest

    # A boolean indicating whether the sniffed device is in a connection.
    @property
    def inConnection(self):
        return self._inConnection

    # The internal state of the sniffer.
    # States are defined in SnifferCollector module. Valid values are 0-2.
    @property
    def state(self):
        return self._state

    # The COM port of the sniffer hardware. During initialization, this value is a preset.
    @property
    def portnum(self):
        return self._portnum

    # The version number of the API software.
    @property
    def swversion(self):
        return self._swversion

    # The version number of the sniffer firmware.
    @property
    def fwversion(self):
        return self._fwversion

    # API ENDS HERE

    # Private method
    def run(self):
        try:
            self._setup()
            self.runSniffer()
        except (KeyboardInterrupt) as e:
            unused_exc_type, unused_exc_obj, exc_tb = sys.exc_info()
            fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
            lineno = exc_tb.tb_lineno
            logging.info("exiting ("+str(type(e))+" in "+fname+" at "+str(lineno)+"): "+str(e))
            self.goodExit = False
        except Exception as e:
            logging.exception("CRASH")
            self.goodExit = False
        else:
            self.goodExit = True

    # Private method
    def comPortFound(self, notification):
        # logging.info("Com port found")
        self._portnum = notification.msg["comPort"]
        self._boardId = self._makeBoardId()
        # self._packetReader.comport = self.portnum

    # Private method
    def runSniffer(self):
        if not self._exit:
            self._continuouslyPipe()
        else:
            self.goodExit = False

    # Private method
    def sendTestPacketToSniffer(self, payload):
        self._sendTestPacket(payload)

    # Private method
    def getTestPacketFromSniffer(self):
        return self._getTestPacket()


================================================
FILE: src/protocols/BLE/Adafruit_BLESniffer/SnifferAPI/SnifferCollector.py
================================================
from __future__ import absolute_import
from . import Packet, Exceptions, CaptureFiles, Devices, Notifications, Version
import threading
import logging
import copy
from serial import SerialException
from six.moves import range


REQ_FOLLOW = 0x00
EVENT_FOLLOW = 0x01
EVENT_DEVICE = 0x02
REQ_SINGLE_PACKET = 0x03
RESP_SINGLE_PACKET = 0x04
EVENT_CONNECT = 0x05
EVENT_PACKET = 0x06
REQ_SCAN_CONT = 0x07
RESP_SCAN_CONT = 0x08
EVENT_DISCONNECT = 0x09
EVENT_ERROR = 0x0A
EVENT_EMPTY_DATA_PACKET = 0x0B
SET_TEMPORARY_KEY = 0x0C
PING_REQ = 0x0D
PING_RESP = 0x0E
TEST_COMMAND_ID = 0x0F
UART_TEST_START = 0x11
UART_DUMMY_PACKET = 0x12
SWITCH_BAUD_RATE_REQ = 0x13
SWITCH_BAUD_RATE_RESP = 0x14
GO_IDLE = 0xFE

STATE_INITIALIZING = 0
STATE_SCANNING = 1
STATE_FOLLOWING = 2

ADV_ACCESS_ADDRESS = [0xD6, 0xBE, 0x89, 0x8E]


class SnifferCollector(Notifications.Notifier):
    def __init__(self, portnum=None, *args, **kwargs):
        Notifications.Notifier.__init__(self, *args, **kwargs)
        self._portnum = portnum
        self._swversion = Version.getRevision()
        self._fwversion = 0
        self._setState(STATE_INITIALIZING)
        self._captureHandler = CaptureFiles.CaptureFileHandler()
        self._exit = False
        self._connectionAccessAddress = None
        self._packetListLock = threading.RLock()
        with self._packetListLock:
            self._packets = []

        self._packetReader = Packet.PacketReader(
            self._portnum,  callbacks=[("*", self.passOnNotification)])
        self._devices = Devices.DeviceList(
            callbacks=[("*", self.passOnNotification)])

        self._missedPackets = 0
        self._packetsInLastConnection = None
        self._connectEventPacketCounterValue = None
        self._inConnection = False
        self._currentConnectRequest = None

        self._nProcessedPackets = 0

        self._switchingBaudRate = False

        self._attemptedBaudRates = []

        self._boardId = self._makeBoardId()

    def __del__(self):
        self._doExit()

    def _setup(self):
        self._packetReader.setup()
        if self._exit:
            return

        if self._packetReader.fwversion < self.swversion:
            self.notify("OLD_FW_VERSION", {
                        "version": self._packetReader.fwversion})

        self._fwversion = self._packetReader.fwversion

        self._startScanning()

        self._setState(STATE_SCANNING)

    def _makeBoardId(self):
        try:
            boardId = int(self._packetReader.uart.ser.name.split("COM")[1])
            logging.info("board ID: %d" % boardId)
        except (IndexError, AttributeError):
            import random
            random.seed()
            boardId = random.randint(0, 255)
            logging.info("board ID (random): %d" % boardId)

        return boardId

    @property
    def state(self):
        return self._state

    def _setState(self, newState):
        self._state = newState
        self.notify("STATE_CHANGE", newState)

    def _switchBaudRate(self, newBaudRate):
        if newBaudRate in self._packetReader.uart.ser.BAUDRATES:
            self._packetReader.sendSwitchBaudRate(newBaudRate)
            self._switchingBaudRate = True
            self._proposedBaudRate = newBaudRate
            self._attemptedBaudRates.append(newBaudRate)

    def _processBLEPacket(self, packet):
        packet.boardId = self._boardId
        self._appendPacket(packet)

        self.notify("NEW_BLE_PACKET", {"packet": packet})
        self._captureHandler.writePacket(packet)

        self._nProcessedPackets += 1
        if packet.OK:
            try:
                if packet.blePacket.accessAddress == ADV_ACCESS_ADDRESS:

                    if self.state == STATE_FOLLOWING and packet.blePacket.advType == 5:
                        self._connectionAccessAddress = packet.blePacket.accessAddress

                    if self.state == STATE_SCANNING:
                        if (packet.blePacket.advType == 0
                            or packet.blePacket.advType == 1
                            or packet.blePacket.advType == 2
                            or packet.blePacket.advType == 4
                            or packet.blePacket.advType == 6
                            ) and (packet.blePacket.advAddress is not None
                                   ) and (packet.crcOK and not packet.direction):

                            newDevice = Devices.Device(
                                address=packet.blePacket.advAddress, name=packet.blePacket.name,
                                RSSI=packet.RSSI, txAdd=packet.txAdd)
                            self._devices.appendOrUpdate(newDevice)

            except Exception as e:
                logging.exception("packet processing error")
                self.notify("PACKET_PROCESSING_ERROR", {"errorString": str(e)})

    def _continuouslyPipe(self):

        while not self._exit:
            try:
                packet = self._packetReader.getPacket(timeout=2)
                if not packet.valid:
                    raise Exceptions.InvalidPacketException("")
            except Exceptions.SnifferTimeout as e:
                logging.info(str(e))
                packet = None
            except (SerialException, ValueError):
                logging.exception("UART read error")
                logging.error("Lost contact with sniffer hardware.")
                self._doExit()
            except Exceptions.InvalidPacketException:
                # logging.error("Continuously pipe: Invalid packet, skipping.")
                pass
            else:
                if packet.id == EVENT_PACKET:
                    self._processBLEPacket(packet)
                elif packet.id == EVENT_FOLLOW:
                    # This packet has no value for the user.
                    pass

                elif packet.id == EVENT_CONNECT:
                    self._connectEventPacketCounterValue = packet.packetCounter
                    self._inConnection = True
                    # copy it because packets are eventually deleted
                    self._currentConnectRequest = copy.copy(self._findPacketByPacketCounter(
                        self._connectEventPacketCounterValue-1))
                elif packet.id == EVENT_DISCONNECT:
                    if self._inConnection:
                        self._packetsInLastConnection = packet.packetCounter - \
                            self._connectEventPacketCounterValue
                        self._inConnection = False
                elif packet.id == SWITCH_BAUD_RATE_RESP and self._switchingBaudRate:
                    self._switchingBaudRate = False
                    if (packet.baudRate == self._proposedBaudRate):
                        self._packetReader.switchBaudRate(
                            self._proposedBaudRate)
                    else:
                        self._switchBaudRate(packet.baudRate)

    def _findPacketByPacketCounter(self, packetCounterValue):
        with self._packetListLock:
            for i in range(-1, -1-len(self._packets), -1):
                # iterate backwards through packets
                if self._packets[i].packetCounter == packetCounterValue:
                    return self._packets[i]
        return None

    def _startScanning(self):
        logging.info("starting scan")

        if self.state == STATE_FOLLOWING:
            logging.info("Stopped sniffing device")

        self._devices.clear()
        self._setState(STATE_SCANNING)
        self._packetReader.sendScan()
        self._packetReader.sendTK([0])

    def _doExit(self):
        self._exit = True
        self.notify("APP_EXIT")
        self._packetReader.doExit()

    def _startFollowing(self, device, followOnlyAdvertisements=False):

        self._devices.setFollowed(device)
        logging.info("Sniffing device " +
                     str(self._devices.index(device)) + ' - "'+device.name+'"')
        self._packetReader.sendFollow(
            device.address, device.txAdd, followOnlyAdvertisements)
        self._setState(STATE_FOLLOWING)

    def _appendPacket(self, packet):
        with self._packetListLock:
            if len(self._packets) > 100000:
                self._packets = self._packets[20000:]
            self._packets.append(packet)

    def _getPackets(self, number=-1):
        with self._packetListLock:
            returnList = self._packets[0:number]
            self._packets = self._packets[number:]
        return returnList

    def _sendTestPacket(self, payload):
        self._packetReader.sendTestPacket(payload)

    def _getTestPacket(self):
        return self._packetReader.getPacket()


================================================
FILE: src/protocols/BLE/Adafruit_BLESniffer/SnifferAPI/UART.py
================================================
from __future__ import absolute_import
import logging
import serial
import collections
import serial.tools.list_ports as list_ports
from . import Exceptions


class Uart:
    def __init__(self, portnum=None, useByteQueue=False):
        self.ser = None
        try:
            self.ser = serial.Serial(
                port=portnum,
                baudrate=460800,
                bytesize=serial.EIGHTBITS,
                parity=serial.PARITY_NONE,
                stopbits=serial.STOPBITS_ONE,
                timeout=None,  # seconds
                writeTimeout=None,
                rtscts=True
            )

        except Exception as e:
            if self.ser:
                self.ser.close()
            raise

        self.useByteQueue = useByteQueue
        self.byteQueue = collections.deque()

        # if self.ser.name != None:
        # print "UART %s on port %s" % ("open" if self.ser else "closed", self.ser.name)

    def __del__(self):
        if self.ser:
            logging.info("closing UART")
            self.ser.close()

    def switchBaudRate(self, newBaudRate):
        self.ser.baudrate = newBaudRate

    def read(self, length, timeout=None):
     
Download .txt
gitextract_1myw_xe2/

├── .gitignore
├── LICENSE
├── README.md
├── setup.py
└── src/
    ├── Entity/
    │   ├── __init__.py
    │   ├── attack.py
    │   ├── attack_suite.py
    │   ├── input_format.py
    │   └── protocol.py
    ├── GUI/
    │   ├── __init__.py
    │   ├── custom_widgets.py
    │   ├── hard_coded_texts.py
    │   ├── tkinter.py
    │   └── utils.py
    ├── Utils/
    │   ├── CommonUtil/
    │   │   └── __init__.py
    │   ├── ExtendUtil/
    │   │   ├── __init__.py
    │   │   ├── export_attack_suite_template.py
    │   │   ├── export_attack_template.py
    │   │   ├── export_protocol_template.py
    │   │   ├── export_util.py
    │   │   └── import_util.py
    │   ├── FilterUtil/
    │   │   ├── __init__.py
    │   │   └── pyshark_filter_util.py
    │   ├── FuzzerUtil/
    │   │   ├── __init__.py
    │   │   └── radamsa_util.py
    │   ├── RandomUtil/
    │   │   ├── __init__.py
    │   │   └── random_generated_names.py
    │   ├── ReportUtil/
    │   │   ├── __init__.py
    │   │   └── report_generator.py
    │   ├── SnifferUtil/
    │   │   ├── __init__.py
    │   │   └── generic_sniffer.py
    │   └── __init__.py
    ├── __init__.py
    ├── captured_packets/
    │   └── __init__.py
    ├── module_installer.py
    ├── peniot.py
    └── protocols/
        ├── AMQP/
        │   ├── __init__.py
        │   ├── amqp_protocol.py
        │   ├── amqp_scanner.py
        │   ├── attacks/
        │   │   ├── __init__.py
        │   │   ├── amqp_dos_attack.py
        │   │   ├── amqp_fuzzing_attack_suite.py
        │   │   ├── amqp_payload_size_fuzzer.py
        │   │   └── amqp_random_payload_fuzzing.py
        │   └── examples/
        │       ├── __init__.py
        │       ├── receiver_example.py
        │       └── sender_example.py
        ├── BLE/
        │   ├── Adafruit_BLESniffer/
        │   │   ├── .gitignore
        │   │   ├── API Manifest.txt
        │   │   ├── LICENSE.txt
        │   │   ├── README.md
        │   │   ├── SnifferAPI/
        │   │   │   ├── CaptureFiles.py
        │   │   │   ├── Devices.py
        │   │   │   ├── Exceptions.py
        │   │   │   ├── Logger.py
        │   │   │   ├── Notifications.py
        │   │   │   ├── Packet.py
        │   │   │   ├── Sniffer.py
        │   │   │   ├── SnifferCollector.py
        │   │   │   ├── UART.py
        │   │   │   ├── Version.py
        │   │   │   ├── __init__.py
        │   │   │   └── myVersion.py
        │   │   ├── __init__.py
        │   │   ├── documentation.html
        │   │   ├── requirements.txt
        │   │   ├── setup.cfg
        │   │   ├── sniffer.py
        │   │   ├── sniffer_uart_protocol.xlsx
        │   │   └── wireshark_dissector_source/
        │   │       ├── OSX/
        │   │       │   └── readme.md
        │   │       ├── packet-btle.c
        │   │       └── packet-nordic_ble.c
        │   ├── BLETest.py
        │   ├── __init__.py
        │   ├── attacks/
        │   │   ├── __init__.py
        │   │   ├── ble_replay_attack.py
        │   │   └── ble_sniff_attack.py
        │   ├── ble_advertiser.py
        │   ├── ble_device.py
        │   ├── ble_protocol.py
        │   ├── ble_replay_attack.py
        │   ├── ble_sniff.py
        │   └── ble_tools.py
        ├── CoAP/
        │   ├── __init__.py
        │   ├── attacks/
        │   │   ├── __init__.py
        │   │   ├── coap_dos_attack.py
        │   │   ├── coap_fuzzing_attack_suite.py
        │   │   ├── coap_payload_size_fuzzer.py
        │   │   ├── coap_random_payload_fuzzing.py
        │   │   ├── coap_replay_attack.py
        │   │   └── coap_sniff_attack.py
        │   ├── coap_protocol.py
        │   ├── coap_scanner.py
        │   └── examples/
        │       ├── __init__.py
        │       ├── client_example.py
        │       ├── resource_example.py
        │       └── server_example.py
        ├── MQTT/
        │   ├── __init__.py
        │   ├── attacks/
        │   │   ├── __init__.py
        │   │   ├── mqtt_dos_attack.py
        │   │   ├── mqtt_fuzzing_attack_suite.py
        │   │   ├── mqtt_generation_based_fuzzing.py
        │   │   ├── mqtt_payload_size_fuzzer.py
        │   │   ├── mqtt_random_payload_fuzzing.py
        │   │   ├── mqtt_replay_attack.py
        │   │   ├── mqtt_sniff_attack.py
        │   │   └── mqtt_topic_name_fuzzing.py
        │   ├── examples/
        │   │   ├── Demo/
        │   │   │   ├── __init__.py
        │   │   │   ├── demo_publisher.py
        │   │   │   └── demo_subscriber.py
        │   │   ├── __init__.py
        │   │   ├── publisher_example.py
        │   │   └── subscriber_example.py
        │   ├── mqtt_protocol.py
        │   └── mqtt_scanner.py
        └── __init__.py
Download .txt
SYMBOL INDEX (756 symbols across 74 files)

FILE: src/Entity/attack.py
  class Attack (line 6) | class Attack(object):
    method __init__ (line 11) | def __init__(self, name, inputs, default_parameters, definition, logge...
    method get_attack_name (line 24) | def get_attack_name(self):
    method set_attack_name (line 27) | def set_attack_name(self, name):
    method get_inputs (line 31) | def get_inputs(self):
    method set_inputs (line 34) | def set_inputs(self, inputs):
    method insert_input (line 38) | def insert_input(self, _input):
    method get_default_parameters (line 42) | def get_default_parameters(self):
    method set_default_parameters (line 45) | def set_default_parameters(self, default_parameters):
    method insert_default_parameters (line 49) | def insert_default_parameters(self, _default_parameter):
    method get_definition (line 53) | def get_definition(self):
    method set_definition (line 56) | def set_definition(self, definition):
    method set_input_value (line 59) | def set_input_value(self, input_name):
    method run (line 64) | def run(self):
    method stop_attack (line 70) | def stop_attack(self):
    method load_default_parameters (line 73) | def load_default_parameters(self):

FILE: src/Entity/attack_suite.py
  class AttackSuite (line 1) | class AttackSuite(object):
    method __init__ (line 6) | def __init__(self, name, attacks):
    method get_attack_suite_name (line 10) | def get_attack_suite_name(self):
    method set_attack_suite_name (line 13) | def set_attack_suite_name(self, name):
    method get_attacks (line 17) | def get_attacks(self):
    method set_attacks (line 20) | def set_attacks(self, attacks):
    method insert_attack (line 24) | def insert_attack(self, attack):
    method run (line 28) | def run(self):

FILE: src/Entity/input_format.py
  class InputFormat (line 1) | class InputFormat(object):
    method __init__ (line 3) | def __init__(self, label_name, name, value, _type, default_value=None,...
    method get_label_name (line 14) | def get_label_name(self):
    method set_label_name (line 17) | def set_label_name(self, label_name):
    method get_name (line 21) | def get_name(self):
    method set_name (line 24) | def set_name(self, name):
    method get_value (line 28) | def get_value(self):
    method set_value (line 31) | def set_value(self, value):
    method get_type (line 35) | def get_type(self):
    method set_type (line 38) | def set_type(self, _type):
    method set_mandatory (line 42) | def set_mandatory(self, mandadory):
    method is_mandatory (line 46) | def is_mandatory(self):
    method set_default_value (line 49) | def set_default_value(self, default_value):
    method get_default_value (line 53) | def get_default_value(self):
    method is_secret (line 56) | def is_secret(self):
    method set_secret (line 59) | def set_secret(self, secret):
    method is_from_captured_packets (line 63) | def is_from_captured_packets(self):
    method set_from_captured_packets (line 66) | def set_from_captured_packets(self, from_captured_packets):

FILE: src/Entity/protocol.py
  class Protocol (line 1) | class Protocol(object):
    method __init__ (line 6) | def __init__(self, name, attack_suites, definition):
    method get_protocol_name (line 11) | def get_protocol_name(self):
    method set_protocol_name (line 14) | def set_protocol_name(self, name):
    method get_attack_suites (line 18) | def get_attack_suites(self):
    method set_attack_suites (line 21) | def set_attack_suites(self, attack_suites):
    method get_definition (line 25) | def get_definition(self):
    method set_definition (line 28) | def set_definition(self, new_def):
    method insert_attack_suite (line 32) | def insert_attack_suite(self, attack_suite):

FILE: src/GUI/custom_widgets.py
  class Header (line 5) | class Header(Frame):
    method __init__ (line 10) | def __init__(self, parent_window):
  class CustomButton (line 20) | class CustomButton(Button):
    method __init__ (line 25) | def __init__(self, parent_window, text, _function, row, columnspan=Non...
  class CustomLabel (line 32) | class CustomLabel(Label):
    method __init__ (line 37) | def __init__(self, parent_window, text, row, column, rowspan=None, col...
  class CustomRadiobutton (line 42) | class CustomRadiobutton(Radiobutton):
    method __init__ (line 47) | def __init__(self, parent_window, text, row, column, sticky, variable,...

FILE: src/GUI/hard_coded_texts.py
  function get_project_name (line 38) | def get_project_name():
  function get_about_us (line 42) | def get_about_us():
  function get_help (line 52) | def get_help():
  function get_extension_help (line 65) | def get_extension_help():
  function get_logger_name (line 71) | def get_logger_name():

FILE: src/GUI/tkinter.py
  class HomePage (line 19) | class HomePage(Frame):
    method __init__ (line 28) | def __init__(self, parent_window):
  class AboutUs (line 52) | class AboutUs(Frame):
    method __init__ (line 57) | def __init__(self, parent_window):
  class Help (line 74) | class Help(Frame):
    method __init__ (line 79) | def __init__(self, parent_window):
  class ViewCapturedPackets (line 95) | class ViewCapturedPackets(Frame):
    method __init__ (line 101) | def __init__(self, parent_window):
    method generate_content (line 108) | def generate_content(self):
    method delete_captured_packets_file (line 149) | def delete_captured_packets_file(self, file_name):
    method download_file (line 157) | def download_file(self, file_name):
  class ProtocolsPage (line 188) | class ProtocolsPage(Frame):
    method __init__ (line 193) | def __init__(self, parent_window):
  class ExtensionPage (line 226) | class ExtensionPage(Frame):
    method __init__ (line 231) | def __init__(self, parent_window):
  class ImportPage (line 259) | class ImportPage(Frame):
    method __init__ (line 264) | def __init__(self, parent_window):
    method import_button_click (line 336) | def import_button_click(self, file_path, option, selected_protocol):
    method get_protocol_names (line 349) | def get_protocol_names(self):
  class ExportPage (line 357) | class ExportPage(Frame):
    method __init__ (line 358) | def __init__(self, parent_window):
  class TabFrame (line 383) | class TabFrame(Frame):
    method __init__ (line 384) | def __init__(self, parent_window, option):
  class ExtensionHelp (line 465) | class ExtensionHelp(Frame):
    method __init__ (line 470) | def __init__(self, parent_window):
  class AttacksPage (line 486) | class AttacksPage(Frame):
    method __init__ (line 491) | def __init__(self, parent_window, protocol):
    method delete_protocol (line 535) | def delete_protocol(self):
  class AttackSuiteDetailsPage (line 541) | class AttackSuiteDetailsPage(Frame):
    method __init__ (line 546) | def __init__(self, parent_window, protocol, attack_suite):
  class AttackDetailsPage (line 576) | class AttackDetailsPage(Frame):
    method __init__ (line 581) | def __init__(self, parent_window, protocol, attack, attack_suite):
    method delete_attack (line 620) | def delete_attack(self):
  class InputsPage (line 632) | class InputsPage(Frame):
    method __init__ (line 637) | def __init__(self, parent_window, protocol, attack, attack_suite):
    method get_file_path (line 704) | def get_file_path(self, entry):
    method set_input_values (line 711) | def set_input_values(self):
    method navigate_to_attack_reporting_page (line 739) | def navigate_to_attack_reporting_page(self):
    method load_default_parameters_to_variables (line 753) | def load_default_parameters_to_variables(self):
    method _check_value_type (line 758) | def _check_value_type(_input, _value):
  class AttackReportingPage (line 768) | class AttackReportingPage(Frame):
    method __init__ (line 773) | def __init__(self, parent_window, protocol, attack, attack_suite):
    method write (line 814) | def write(self, text):
    method readline (line 821) | def readline(self):
    method get_number (line 832) | def get_number(self):
    method perform_attack (line 846) | def perform_attack(self):
    method attack_stopper (line 855) | def attack_stopper(self):
    method report_generator (line 865) | def report_generator(self):
  function run (line 882) | def run():

FILE: src/GUI/utils.py
  function is_default_protocol (line 16) | def is_default_protocol(protocol_name):
  function delete_protocol (line 25) | def delete_protocol(protocol_name):
  function delete_attack (line 34) | def delete_attack(attack_name):
  function pop_up_window (line 53) | def pop_up_window(root, protocol_name, definition, justify=LEFT):
  function get_protocols (line 73) | def get_protocols():
  function get_attacks (line 106) | def get_attacks(package_name):
  function get_captured_packet_files (line 165) | def get_captured_packet_files():
  function change_frame (line 181) | def change_frame(old_frame, new_frame):
  function create_root (line 193) | def create_root():
  function center_widget (line 213) | def center_widget(window):
  function startup_calls (line 236) | def startup_calls():
  function shutdown_calls (line 243) | def shutdown_calls(root):

FILE: src/Utils/CommonUtil/__init__.py
  function get_current_datetime_for_filename_format (line 9) | def get_current_datetime_for_filename_format():
  function get_current_datetime_for_report_format (line 13) | def get_current_datetime_for_report_format():
  function get_boolean_value (line 17) | def get_boolean_value(bool_str):

FILE: src/Utils/ExtendUtil/export_attack_suite_template.py
  class _ATTACK_SUITE_COMBINED_NAME (line 16) | class _ATTACK_SUITE_COMBINED_NAME(AttackSuite):
    method __init__ (line 18) | def __init__(self):

FILE: src/Utils/ExtendUtil/export_attack_template.py
  class _ATTACK_COMBINED_NAME (line 18) | class _ATTACK_COMBINED_NAME(Attack):
    method __init__ (line 48) | def __init__(self):
    method pre_attack_init (line 65) | def pre_attack_init(self):
    method run (line 69) | def run(self):

FILE: src/Utils/ExtendUtil/export_protocol_template.py
  class _PROTOCOL_NAME (line 21) | class _PROTOCOL_NAME(Protocol):
    method __init__ (line 23) | def __init__(self):

FILE: src/Utils/ExtendUtil/export_util.py
  class ExportTypes (line 15) | class ExportTypes(Enum):
  class ExportOptions (line 23) | class ExportOptions(Enum):
  class ExportUtil (line 33) | class ExportUtil(object):
    method get_export_texts_and_values (line 52) | def get_export_texts_and_values():
    method export_function_factory (line 59) | def export_function_factory(export_type):
    method export_files_with_zip (line 71) | def export_files_with_zip(output_name, list_of_files, output_path="./"):
    method export_files_with_tar (line 89) | def export_files_with_tar(output_name, list_of_files, output_path="./"):
    method export_protocol (line 109) | def export_protocol(protocol_name, export_path, export_type, output_na...
    method export_attack (line 147) | def export_attack(protocol_name, attack_name, export_path, export_type...
    method export_attack_suite (line 186) | def export_attack_suite(protocol_name, attack_suite_name, export_path,...
    method _create_temporary_file_and_replace_regex (line 226) | def _create_temporary_file_and_replace_regex(template_name=None, regex...
    method _replace_regex (line 245) | def _replace_regex(content, substitution_list_as_tuples):
    method export_action (line 251) | def export_action(protocol_name, attack_name, attack_suite_name, file_...

FILE: src/Utils/ExtendUtil/import_util.py
  class ImportOptions (line 15) | class ImportOptions(Enum):
  class ImportUtil (line 25) | class ImportUtil(object):
    method startup (line 38) | def startup():
    method shutdown (line 57) | def shutdown():
    method trigger_import (line 71) | def trigger_import(input_path, protocol_name=None):
    method import_function_factory (line 97) | def import_function_factory(input_path):
    method import_zip (line 113) | def import_zip(input_path, full_out_dir_path):
    method import_tar (line 126) | def import_tar(input_path, full_out_dir_path):
    method import_protocol (line 139) | def import_protocol(file_path):
    method import_attack_or_attack_suite (line 144) | def import_attack_or_attack_suite(file_path, protocol_name):
    method _is_file_name (line 149) | def _is_file_name(name):
    method _do_not_import_names (line 157) | def _do_not_import_names(name):
    method import_action (line 161) | def import_action(file_path, option, protocol_name=None):

FILE: src/Utils/FilterUtil/pyshark_filter_util.py
  class PySharkFilter (line 7) | class PySharkFilter:
    method __init__ (line 12) | def __init__(self, layer_name, field_name, value):
    method set_layer_name (line 17) | def set_layer_name(self, layer_name):
    method get_layer_name (line 21) | def get_layer_name(self):
    method set_field_name (line 24) | def set_field_name(self, field_name):
    method get_field_name (line 28) | def get_field_name(self):
    method set_value (line 31) | def set_value(self, value):
    method get_value (line 35) | def get_value(self):
    method apply_filter_to_packet (line 38) | def apply_filter_to_packet(self, packet):

FILE: src/Utils/FuzzerUtil/radamsa_util.py
  function radamsa_malformed_input_generator (line 10) | def radamsa_malformed_input_generator(input_string, output_count=1):
  function get_ascii_decodable_radamsa_malformed_input (line 35) | def get_ascii_decodable_radamsa_malformed_input(input_string, output_cou...

FILE: src/Utils/RandomUtil/random_generated_names.py
  function get_random_client_name (line 6) | def get_random_client_name():
  function get_random_file_name (line 11) | def get_random_file_name():

FILE: src/Utils/ReportUtil/report_generator.py
  class PeniotPDF (line 6) | class PeniotPDF(FPDF):
    method header (line 11) | def header(self):
    method footer (line 20) | def footer(self):
    method add_title_and_date (line 27) | def add_title_and_date(self, attack_name):
    method add_attack_logs (line 34) | def add_attack_logs(self, attack_logs):
  class GenerateReport (line 39) | class GenerateReport(object):
    method generate_pdf_from_text (line 42) | def generate_pdf_from_text(protocol_name, attack_name, attack_logs, di...

FILE: src/Utils/SnifferUtil/generic_sniffer.py
  function filter_packets_by_filter_list (line 16) | def filter_packets_by_filter_list(packets, filter_list):
  class GenericSniffer (line 29) | class GenericSniffer:
    method __init__ (line 37) | def __init__(self, timeout=DEFAULT_SNIFF_TIMEOUT, interface=DEFAULT_IN...
    method start_live_capture (line 54) | def start_live_capture(self):
    method get_captured_packets (line 66) | def get_captured_packets(self):
    method filter_packets_by_protocol (line 72) | def filter_packets_by_protocol(self, protocol=None):

FILE: src/protocols/AMQP/amqp_protocol.py
  class AMQP (line 6) | class AMQP(Protocol):
    method __init__ (line 8) | def __init__(self):
  class TestAMQPProtocol (line 20) | class TestAMQPProtocol(unittest.TestCase):
    method setUp (line 21) | def setUp(self):
    method tearDown (line 24) | def tearDown(self):
    method test_name (line 27) | def test_name(self):
    method test_attacks (line 30) | def test_attacks(self):

FILE: src/protocols/AMQP/amqp_scanner.py
  class AMQPScanner (line 7) | class AMQPScanner:
    method __init__ (line 13) | def __init__(self):
    method scan (line 17) | def scan(timeout=generic_sniffer.DEFAULT_SNIFF_TIMEOUT, interface=gene...

FILE: src/protocols/AMQP/attacks/amqp_dos_attack.py
  class AMQPDoSAttack (line 13) | class AMQPDoSAttack(Attack):
    method __init__ (line 33) | def __init__(self):
    method signal_handler (line 55) | def signal_handler(self, sig, frame):
    method stop_attack (line 58) | def stop_attack(self):
    method pre_attack_init (line 65) | def pre_attack_init(self):
    method run (line 76) | def run(self):
  class TestMQTTDoSAttack (line 88) | class TestMQTTDoSAttack(unittest.TestCase):
    method setUp (line 89) | def setUp(self):
    method tearDown (line 92) | def tearDown(self):
    method test_name (line 95) | def test_name(self):
    method test_inputs (line 98) | def test_inputs(self):
    method test_non_initialized_inputs (line 104) | def test_non_initialized_inputs(self):
    method test_after_getting_inputs (line 110) | def test_after_getting_inputs(self):
    method test_dos_attack (line 126) | def test_dos_attack(self):

FILE: src/protocols/AMQP/attacks/amqp_fuzzing_attack_suite.py
  class AMQPFuzzingAttackSuite (line 6) | class AMQPFuzzingAttackSuite(AttackSuite):
    method __init__ (line 8) | def __init__(self):
  class TestAMQPFuzzingAttackSuite (line 13) | class TestAMQPFuzzingAttackSuite(unittest.TestCase):
    method setUp (line 14) | def setUp(self):
    method tearDown (line 17) | def tearDown(self):
    method test_name (line 20) | def test_name(self):
    method test_attack_list (line 23) | def test_attack_list(self):
    method test_attacks (line 29) | def test_attacks(self):

FILE: src/protocols/AMQP/attacks/amqp_payload_size_fuzzer.py
  class AMQPPayloadSizeFuzzerAttack (line 14) | class AMQPPayloadSizeFuzzerAttack(Attack):
    method __init__ (line 36) | def __init__(self):
    method signal_handler (line 55) | def signal_handler(self, sig, frame):
    method stop_attack (line 58) | def stop_attack(self):
    method pre_attack_init (line 65) | def pre_attack_init(self):
    method run (line 80) | def run(self):
  class TestCoAPPayloadSizeAttack (line 111) | class TestCoAPPayloadSizeAttack(unittest.TestCase):
    method setUp (line 112) | def setUp(self):
    method tearDown (line 115) | def tearDown(self):
    method test_name (line 118) | def test_name(self):
    method test_inputs (line 121) | def test_inputs(self):
    method test_non_initialized_inputs (line 127) | def test_non_initialized_inputs(self):
    method test_after_getting_inputs (line 133) | def test_after_getting_inputs(self):
    method test_invalid_fuzzing_turn (line 149) | def test_invalid_fuzzing_turn(self):
    method test_payload_size_fuzzing_attack (line 161) | def test_payload_size_fuzzing_attack(self):

FILE: src/protocols/AMQP/attacks/amqp_random_payload_fuzzing.py
  class AMQPRandomPayloadFuzzingAttack (line 15) | class AMQPRandomPayloadFuzzingAttack(Attack):
    method __init__ (line 37) | def __init__(self):
    method signal_handler (line 59) | def signal_handler(self, sig, frame):
    method stop_attack (line 62) | def stop_attack(self):
    method pre_attack_init (line 69) | def pre_attack_init(self):
    method run (line 80) | def run(self):
  class TestAMQPRandomPayloadAttack (line 125) | class TestAMQPRandomPayloadAttack(unittest.TestCase):
    method setUp (line 126) | def setUp(self):
    method tearDown (line 129) | def tearDown(self):
    method test_name (line 132) | def test_name(self):
    method test_inputs (line 135) | def test_inputs(self):
    method test_non_initialized_inputs (line 141) | def test_non_initialized_inputs(self):
    method test_after_getting_inputs (line 147) | def test_after_getting_inputs(self):
    method test_invalid_fuzzing_turn (line 163) | def test_invalid_fuzzing_turn(self):
    method test_random_payload_fuzzing_attack (line 175) | def test_random_payload_fuzzing_attack(self):

FILE: src/protocols/AMQP/examples/receiver_example.py
  function signal_handler (line 25) | def signal_handler(sig, frame):
  function callback (line 33) | def callback(ch, method, properties, body):
  function receive_procedure (line 37) | def receive_procedure(channel_to_receive, queue_name=DEFAULT_QUEUE_NAME):

FILE: src/protocols/AMQP/examples/sender_example.py
  function signal_handler (line 26) | def signal_handler(sig, frame):
  function send_procedure (line 34) | def send_procedure(channel_to_send, exchange=DEFAULT_EXCHANGE, routing_k...

FILE: src/protocols/BLE/Adafruit_BLESniffer/SnifferAPI/CaptureFiles.py
  class CaptureFileHandler (line 49) | class CaptureFileHandler:
    method __init__ (line 50) | def __init__(self, clear=False):
    method startNewFile (line 61) | def startNewFile(self):
    method doRollover (line 65) | def doRollover(self):
    method readLine (line 76) | def readLine(self, lineNum):
    method readAll (line 83) | def readAll(self):
    method writeString (line 89) | def writeString(self, msgString):
    method writeList (line 93) | def writeList(self, msgList):
    method writePacketList (line 96) | def writePacketList(self, packetList):
    method writePacket (line 99) | def writePacket(self, packet):
    method makePacketHeader (line 102) | def makePacketHeader(self, length):
  function toList (line 132) | def toList(myString):

FILE: src/protocols/BLE/Adafruit_BLESniffer/SnifferAPI/Devices.py
  class DeviceList (line 6) | class DeviceList(Notifications.Notifier):
    method __init__ (line 7) | def __init__(self, *args, **kwargs):
    method __len__ (line 13) | def __len__(self):
    method __repr__ (line 16) | def __repr__(self):
    method clear (line 19) | def clear(self):
    method appendOrUpdate (line 22) | def appendOrUpdate(self, newDevice):
    method append (line 44) | def append(self, device):
    method find (line 48) | def find(self, id):
    method remove (line 65) | def remove(self, id):
    method index (line 84) | def index(self, device):
    method setFollowed (line 99) | def setFollowed(self, device):
    method asList (line 110) | def asList(self):
  class Device (line 114) | class Device:
    method __init__ (line 115) | def __init__(self, address, name, RSSI, txAdd=1):

FILE: src/protocols/BLE/Adafruit_BLESniffer/SnifferAPI/Exceptions.py
  class SnifferTimeout (line 1) | class SnifferTimeout(Exception):
  class UARTPacketError (line 5) | class UARTPacketError(Exception):
  class InvalidPacketException (line 9) | class InvalidPacketException(Exception):
  class SnifferWatchDogTimeout (line 15) | class SnifferWatchDogTimeout(SnifferTimeout):
  class ExitCodeException (line 21) | class ExitCodeException(Exception):

FILE: src/protocols/BLE/Adafruit_BLESniffer/SnifferAPI/Logger.py
  function initLogger (line 38) | def initLogger():
  function shutdownLogger (line 68) | def shutdownLogger():
  function clearLog (line 74) | def clearLog():
  function getTimestamp (line 84) | def getTimestamp():
  function addTimestamp (line 93) | def addTimestamp():
  function readAll (line 102) | def readAll():
  class MyRotatingFileHandler (line 112) | class MyRotatingFileHandler(logHandlers.RotatingFileHandler):
    method doRollover (line 113) | def doRollover(self):
  class LogFlusher (line 124) | class LogFlusher(threading.Thread):
    method __init__ (line 125) | def __init__(self, logHandler):
    method run (line 134) | def run(self):
    method doFlush (line 139) | def doFlush(self):
    method stop (line 143) | def stop(self):

FILE: src/protocols/BLE/Adafruit_BLESniffer/SnifferAPI/Notifications.py
  class Notification (line 5) | class Notification():
    method __init__ (line 6) | def __init__(self, key, msg=None):
    method __repr__ (line 12) | def __repr__(self):
  class Notifier (line 16) | class Notifier():
    method __init__ (line 17) | def __init__(self, callbacks=[]):
    method subscribe (line 26) | def subscribe(self, key, callback):
    method getCallbacks (line 31) | def getCallbacks(self, key):
    method notify (line 38) | def notify(self, key=None, msg=None, notification=None):
    method passOnNotification (line 52) | def passOnNotification(self, notification):

FILE: src/protocols/BLE/Adafruit_BLESniffer/SnifferAPI/Packet.py
  class PacketReader (line 78) | class PacketReader(Notifications.Notifier):
    method __init__ (line 79) | def __init__(self, portnum=None, callbacks=[]):
    method setup (line 94) | def setup(self):
    method doExit (line 99) | def doExit(self):
    method encodeToSLIP (line 105) | def encodeToSLIP(self, byteList):
    method decodeFromSLIP (line 126) | def decodeFromSLIP(self, timeout=None):
    method getSerialByte (line 155) | def getSerialByte(self, timeout=None):
    method handlePacketHistory (line 161) | def handlePacketHistory(self, packet):
    method getPacket (line 175) | def getPacket(self, timeout=None):
    method useByteQueue (line 188) | def useByteQueue(self, useByteQueue=True):
    method getByteQueue (line 191) | def getByteQueue(self):
    method sendPacket (line 194) | def sendPacket(self, id, payload, timeout=None):
    method sendScan (line 201) | def sendScan(self, timeout=None):
    method sendFollow (line 204) | def sendFollow(self, addr, txAdd=1, followOnlyAdvertisements=False, ti...
    method sendPingReq (line 209) | def sendPingReq(self, timeout=1):
    method sendTK (line 212) | def sendTK(self, TK, timeout=None):
    method sendSwitchBaudRate (line 223) | def sendSwitchBaudRate(self, newBaudRate, timeout=None):
    method switchBaudRate (line 226) | def switchBaudRate(self, newBaudRate):
    method sendHopSequence (line 229) | def sendHopSequence(self, hopSequence):
    method sendGoIdle (line 237) | def sendGoIdle(self, timeout=None):
    method findSerialPort (line 240) | def findSerialPort(self):
  class Packet (line 325) | class Packet:
    method __init__ (line 327) | def __init__(self, packetList):
    method __repr__ (line 347) | def __repr__(self):
    method readStaticHeader (line 350) | def readStaticHeader(self, packetList):
    method readDynamicHeader (line 355) | def readDynamicHeader(self, packetList):
    method readPayload (line 364) | def readPayload(self, packetList):
    method readFlags (line 414) | def readFlags(self):
    method getList (line 421) | def getList(self):
    method validatePacketList (line 424) | def validatePacketList(self, packetList):
  class BlePacket (line 435) | class BlePacket():
    method __init__ (line 436) | def __init__(self, packetList):
    method __repr__ (line 445) | def __repr__(self):
    method extractAccessAddress (line 448) | def extractAccessAddress(self, packetList):
    method extractAdvType (line 451) | def extractAdvType(self, packetList):
    method extractAdvAddress (line 454) | def extractAdvAddress(self, packetList):
    method extractName (line 470) | def extractName(self, packetList):
    method extractLength (line 491) | def extractLength(self, packetList):
  function parseLittleEndian (line 496) | def parseLittleEndian(list):
  function toLittleEndian (line 503) | def toLittleEndian(value, size):

FILE: src/protocols/BLE/Adafruit_BLESniffer/SnifferAPI/Sniffer.py
  function initLog (line 10) | def initLog():
  class Sniffer (line 20) | class Sniffer(threading.Thread, SnifferCollector.SnifferCollector):
    method __init__ (line 25) | def __init__(self, portnum=None):
    method getPackets (line 37) | def getPackets(self, number=-1):
    method getDevices (line 42) | def getDevices(self):
    method follow (line 49) | def follow(self, device=None, followOnlyAdvertisements=False):
    method scan (line 55) | def scan(self):
    method sendTK (line 60) | def sendTK(self, TK):
    method setPortnum (line 65) | def setPortnum(self, portnum):
    method setAdvHopSequence (line 73) | def setAdvHopSequence(self, hopSequence):
    method doExit (line 78) | def doExit(self):
    method missedPackets (line 86) | def missedPackets(self):
    method packetsInLastConnection (line 92) | def packetsInLastConnection(self):
    method connectEventPacketCounterValue (line 97) | def connectEventPacketCounterValue(self):
    method currentConnectRequest (line 102) | def currentConnectRequest(self):
    method inConnection (line 107) | def inConnection(self):
    method state (line 113) | def state(self):
    method portnum (line 118) | def portnum(self):
    method swversion (line 123) | def swversion(self):
    method fwversion (line 128) | def fwversion(self):
    method run (line 134) | def run(self):
    method comPortFound (line 151) | def comPortFound(self, notification):
    method runSniffer (line 158) | def runSniffer(self):
    method sendTestPacketToSniffer (line 165) | def sendTestPacketToSniffer(self, payload):
    method getTestPacketFromSniffer (line 169) | def getTestPacketFromSniffer(self):

FILE: src/protocols/BLE/Adafruit_BLESniffer/SnifferAPI/SnifferCollector.py
  class SnifferCollector (line 39) | class SnifferCollector(Notifications.Notifier):
    method __init__ (line 40) | def __init__(self, portnum=None, *args, **kwargs):
    method __del__ (line 72) | def __del__(self):
    method _setup (line 75) | def _setup(self):
    method _makeBoardId (line 90) | def _makeBoardId(self):
    method state (line 103) | def state(self):
    method _setState (line 106) | def _setState(self, newState):
    method _switchBaudRate (line 110) | def _switchBaudRate(self, newBaudRate):
    method _processBLEPacket (line 117) | def _processBLEPacket(self, packet):
    method _continuouslyPipe (line 150) | def _continuouslyPipe(self):
    method _findPacketByPacketCounter (line 193) | def _findPacketByPacketCounter(self, packetCounterValue):
    method _startScanning (line 201) | def _startScanning(self):
    method _doExit (line 212) | def _doExit(self):
    method _startFollowing (line 217) | def _startFollowing(self, device, followOnlyAdvertisements=False):
    method _appendPacket (line 226) | def _appendPacket(self, packet):
    method _getPackets (line 232) | def _getPackets(self, number=-1):
    method _sendTestPacket (line 238) | def _sendTestPacket(self, payload):
    method _getTestPacket (line 241) | def _getTestPacket(self):

FILE: src/protocols/BLE/Adafruit_BLESniffer/SnifferAPI/UART.py
  class Uart (line 9) | class Uart:
    method __init__ (line 10) | def __init__(self, portnum=None, useByteQueue=False):
    method __del__ (line 35) | def __del__(self):
    method switchBaudRate (line 40) | def switchBaudRate(self, newBaudRate):
    method read (line 43) | def read(self, length, timeout=None):
    method readByte (line 59) | def readByte(self, timeout=None):
    method readList (line 66) | def readList(self, size, timeout=None):
    method writeList (line 69) | def writeList(self, array, timeout=None):
  function list_serial_ports (line 85) | def list_serial_ports():

FILE: src/protocols/BLE/Adafruit_BLESniffer/SnifferAPI/Version.py
  function getRevision (line 7) | def getRevision():
  function getVersionString (line 11) | def getVersionString(mRevision=getRevision()):
  function getPureVersionString (line 25) | def getPureVersionString(mRevision=getRevision()):
  function getUserGuideFileName (line 29) | def getUserGuideFileName(version=pdfVersion, platformName="win", deliver...
  function getReadableVersionString (line 34) | def getReadableVersionString(mRevision=getRevision()):
  function getFileNameVersionString (line 38) | def getFileNameVersionString(mRevision=getRevision(), itemName="", platf...

FILE: src/protocols/BLE/Adafruit_BLESniffer/sniffer.py
  function setup (line 24) | def setup(serport, delay=6):
  function scanForDevices (line 43) | def scanForDevices(scantime=5):
  function selectDevice (line 59) | def selectDevice(devlist):
  function dumpPackets (line 100) | def dumpPackets():

FILE: src/protocols/BLE/Adafruit_BLESniffer/wireshark_dissector_source/packet-btle.c
  function reverse_byte_order (line 457) | void
  function reverse_byte_order_inplace (line 467) | void
  function dissect_feature_set (line 480) | void
  function dissect_channel_map (line 506) | void
  function proto_tree (line 537) | proto_tree* add_adv_data_attr(proto_tree* tree, tvbuff_t* tvb, const int...
  function dissect_adv_data_attr (line 566) | void
  function dissect_adv_data (line 751) | void
  function dissect_adv_ind_or_nonconn_or_scan (line 774) | void
  function dissect_adv_direct_ind (line 807) | void
  function dissect_scan_req (line 833) | void
  function dissect_scan_rsp (line 861) | void
  function dissect_connect_req (line 892) | void
  function dissect_ll_enc_req (line 943) | void
  function dissect_ll_enc_rsp (line 962) | void
  function dissect_ll_control (line 1058) | void
  function dissect_btle (line 1137) | static void
  function proto_register_btle (line 1344) | void
  function proto_reg_handoff_btle (line 1883) | void

FILE: src/protocols/BLE/Adafruit_BLESniffer/wireshark_dissector_source/packet-nordic_ble.c
  function guint8 (line 220) | static guint8
  function guint8 (line 226) | static guint8
  function guint8 (line 232) | static guint8
  function guint8 (line 238) | static guint8
  function guint8 (line 244) | static guint8
  function guint8 (line 250) | static guint8
  function guint8 (line 256) | static guint8
  function guint8 (line 262) | static guint8
  function guint8 (line 268) | static guint8
  function guint8 (line 274) | static guint8
  function guint8 (line 280) | static guint8
  function guint8 (line 286) | static guint8
  function guint8 (line 292) | static guint8
  function gboolean (line 307) | static gboolean
  function array_copy (line 322) | static void array_copy(void* dst, const void* src, int len)
  function tvbuff_t (line 332) | static tvbuff_t *
  function gboolean (line 339) | static gboolean
  function dissect_packet_counter (line 409) | static void
  function dissect_id (line 415) | static void
  function gboolean (line 423) | static gboolean
  function dissect_channel (line 484) | static void
  function dissect_rssi (line 492) | static void
  function dissect_event_counter (line 500) | static void
  function dissect_ble_delta_time (line 511) | static void
  function dissect_ble_hlen (line 532) | static void
  function dissect_protover (line 540) | static void
  function guint32 (line 550) | static guint32
  function dissect_header_0_9_7 (line 566) | static void
  function dissect_header_1_0_0 (line 592) | static void
  function dissect_nordic_ble (line 632) | static int
  function proto_register_nordic_ble (line 688) | void
  function proto_reg_handoff_nordic_ble (line 829) | void

FILE: src/protocols/BLE/BLETest.py
  class BLETest (line 7) | class BLETest:
    method run_test (line 10) | def run_test(attack_name):

FILE: src/protocols/BLE/attacks/ble_replay_attack.py
  class BLEReplayAttack (line 8) | class BLEReplayAttack(Attack):
    method __init__ (line 15) | def __init__(self):
    method run (line 25) | def run(self):
    method stop_attack (line 29) | def stop_attack(self):

FILE: src/protocols/BLE/attacks/ble_sniff_attack.py
  class BLESniffAttack (line 8) | class BLESniffAttack(Attack):
    method __init__ (line 16) | def __init__(self):
    method run (line 26) | def run(self):
    method signal_handler (line 32) | def signal_handler(self, sig, frame):
    method stop_attack (line 35) | def stop_attack(self):

FILE: src/protocols/BLE/ble_device.py
  class BLEDevice (line 4) | class BLEDevice:
    method __init__ (line 10) | def __init__(self, address):
    method connect (line 16) | def connect(self):
    method writecmd (line 32) | def writecmd(self, handle, value):

FILE: src/protocols/BLE/ble_protocol.py
  class BLE (line 4) | class BLE(Protocol):
    method __init__ (line 6) | def __init__(self):

FILE: src/protocols/BLE/ble_replay_attack.py
  class BLEReplayAttackHelper (line 5) | class BLEReplayAttackHelper:
    method __init__ (line 10) | def __init__(self, file_path):
    method run (line 15) | def run(self):
    method create_tmp_file (line 21) | def create_tmp_file(self):
    method get_write_requests (line 29) | def get_write_requests(self):
    method replay_write_requests (line 75) | def replay_write_requests(self):
    method delete_tmp_file (line 90) | def delete_tmp_file(self):

FILE: src/protocols/BLE/ble_sniff.py
  class BLESniffer (line 10) | class BLESniffer:
    method __init__ (line 14) | def __init__(self, serial_portt):
    method run (line 33) | def run(self):
    method stop_attack (line 93) | def stop_attack(self):
    method create_file_name (line 99) | def create_file_name():

FILE: src/protocols/BLE/ble_tools.py
  class BLEScanner (line 8) | class BLEScanner:
    method scan (line 17) | def scan(interface, timeout):
  class BLEPeripheral (line 30) | class BLEPeripheral:
    method __init__ (line 37) | def __init__(self, address, address_type, interface):
    method getServices (line 40) | def getServices(self):
    method getCharacteristics (line 46) | def getCharacteristics(self):
    method getAddress (line 52) | def getAddress(self):
    method getAddressType (line 58) | def getAddressType(self):
    method getInterface (line 61) | def getInterface(self):

FILE: src/protocols/CoAP/__init__.py
  class CoAPMethods (line 24) | class CoAPMethods(enum.Enum):
  function does_method_have_payload (line 32) | def does_method_have_payload(method):
  function make_request (line 41) | def make_request(client, _path, _method_type, _payload=None):
  function get_coap_methods_by_name (line 64) | def get_coap_methods_by_name(method_string):
  function get_coap_methods_as_string (line 81) | def get_coap_methods_as_string(method):

FILE: src/protocols/CoAP/attacks/coap_dos_attack.py
  class CoAPDoSAttack (line 14) | class CoAPDoSAttack(Attack):
    method __init__ (line 35) | def __init__(self):
    method signal_handler (line 56) | def signal_handler(self, sig, frame):
    method stop_attack (line 59) | def stop_attack(self):
    method pre_attack_init (line 66) | def pre_attack_init(self):
    method run (line 70) | def run(self):
  class TestCoAPDoSAttack (line 82) | class TestCoAPDoSAttack(unittest.TestCase):
    method setUp (line 83) | def setUp(self):
    method tearDown (line 86) | def tearDown(self):
    method test_name (line 89) | def test_name(self):
    method test_inputs (line 92) | def test_inputs(self):
    method test_non_initialized_inputs (line 98) | def test_non_initialized_inputs(self):
    method test_after_getting_inputs (line 104) | def test_after_getting_inputs(self):
    method test_dos_attack (line 119) | def test_dos_attack(self):

FILE: src/protocols/CoAP/attacks/coap_fuzzing_attack_suite.py
  class CoAPFuzzingAttackSuite (line 9) | class CoAPFuzzingAttackSuite(AttackSuite):
    method __init__ (line 11) | def __init__(self):
  class TestCoAPFuzzingAttackSuite (line 16) | class TestCoAPFuzzingAttackSuite(unittest.TestCase):
    method setUp (line 17) | def setUp(self):
    method tearDown (line 20) | def tearDown(self):
    method test_name (line 23) | def test_name(self):
    method test_attack_list (line 26) | def test_attack_list(self):
    method test_attacks (line 32) | def test_attacks(self):

FILE: src/protocols/CoAP/attacks/coap_payload_size_fuzzer.py
  class CoAPPayloadSizeFuzzerAttack (line 15) | class CoAPPayloadSizeFuzzerAttack(Attack):
    method __init__ (line 36) | def __init__(self):
    method signal_handler (line 55) | def signal_handler(self, sig, frame):
    method stop_attack (line 58) | def stop_attack(self):
    method pre_attack_init (line 66) | def pre_attack_init(self):
    method run (line 74) | def run(self):
  class TestCoAPPayloadSizeAttack (line 111) | class TestCoAPPayloadSizeAttack(unittest.TestCase):
    method setUp (line 112) | def setUp(self):
    method tearDown (line 115) | def tearDown(self):
    method test_name (line 118) | def test_name(self):
    method test_inputs (line 121) | def test_inputs(self):
    method test_non_initialized_inputs (line 127) | def test_non_initialized_inputs(self):
    method test_after_getting_inputs (line 133) | def test_after_getting_inputs(self):
    method test_invalid_method (line 148) | def test_invalid_method(self):
    method test_invalid_fuzzing_turn (line 159) | def test_invalid_fuzzing_turn(self):
    method test_payload_size_fuzzing_attack (line 170) | def test_payload_size_fuzzing_attack(self):

FILE: src/protocols/CoAP/attacks/coap_random_payload_fuzzing.py
  class CoAPRandomPayloadFuzzingAttack (line 16) | class CoAPRandomPayloadFuzzingAttack(Attack):
    method __init__ (line 39) | def __init__(self):
    method signal_handler (line 61) | def signal_handler(self, sig, frame):
    method stop_attack (line 64) | def stop_attack(self):
    method pre_attack_init (line 72) | def pre_attack_init(self):
    method run (line 80) | def run(self):
  class TestCoAPRandomPayloadAttack (line 126) | class TestCoAPRandomPayloadAttack(unittest.TestCase):
    method setUp (line 127) | def setUp(self):
    method tearDown (line 130) | def tearDown(self):
    method test_name (line 133) | def test_name(self):
    method test_inputs (line 136) | def test_inputs(self):
    method test_non_initialized_inputs (line 142) | def test_non_initialized_inputs(self):
    method test_after_getting_inputs (line 148) | def test_after_getting_inputs(self):
    method test_invalid_method (line 163) | def test_invalid_method(self):
    method test_invalid_fuzzing_turn (line 174) | def test_invalid_fuzzing_turn(self):
    method test_random_payload_fuzzing_attack (line 185) | def test_random_payload_fuzzing_attack(self):

FILE: src/protocols/CoAP/attacks/coap_replay_attack.py
  class CoAPReplayAttack (line 13) | class CoAPReplayAttack(Attack):
    method __init__ (line 28) | def __init__(self):
    method signal_handler (line 45) | def signal_handler(self, sig, frame):
    method stop_attack (line 48) | def stop_attack(self):
    method pre_attack_init (line 52) | def pre_attack_init(self):
    method run (line 59) | def run(self):
    method pre_attack_process (line 72) | def pre_attack_process(self):
  class TestCoAPReplayAttack (line 85) | class TestCoAPReplayAttack(unittest.TestCase):
    method setUp (line 86) | def setUp(self):
    method tearDown (line 89) | def tearDown(self):
    method test_name (line 92) | def test_name(self):
    method test_non_initialized_inputs (line 95) | def test_non_initialized_inputs(self):
    method test_after_getting_inputs (line 101) | def test_after_getting_inputs(self):
    method test_replay_attack (line 113) | def test_replay_attack(self):

FILE: src/protocols/CoAP/attacks/coap_sniff_attack.py
  class CoAPSniffAttack (line 13) | class CoAPSniffAttack(Attack):
    method __init__ (line 26) | def __init__(self):
    method signal_handler (line 43) | def signal_handler(self, sig, frame):
    method stop_attack (line 46) | def stop_attack(self):
    method run (line 50) | def run(self):
  class TestCoAPSniffAttack (line 61) | class TestCoAPSniffAttack(unittest.TestCase):
    method setUp (line 62) | def setUp(self):
    method tearDown (line 65) | def tearDown(self):
    method test_name (line 68) | def test_name(self):
    method test_non_initialized_inputs (line 71) | def test_non_initialized_inputs(self):
    method test_after_getting_inputs (line 77) | def test_after_getting_inputs(self):
    method test_sniff_attack (line 89) | def test_sniff_attack(self):

FILE: src/protocols/CoAP/coap_protocol.py
  class CoAP (line 6) | class CoAP(Protocol):
    method __init__ (line 8) | def __init__(self):
  class TestCoAPProtocol (line 31) | class TestCoAPProtocol(unittest.TestCase):
    method setUp (line 32) | def setUp(self):
    method tearDown (line 35) | def tearDown(self):
    method test_name (line 38) | def test_name(self):
    method test_attacks (line 41) | def test_attacks(self):

FILE: src/protocols/CoAP/coap_scanner.py
  class CoAPScanner (line 9) | class CoAPScanner:
    method __init__ (line 15) | def __init__(self):
    method scan (line 19) | def scan(timeout=generic_sniffer.DEFAULT_SNIFF_TIMEOUT, interface=gene...
    method get_raw_udp_payload_as_bytes (line 30) | def get_raw_udp_payload_as_bytes(packet):
    method get_raw_frame_as_bytes (line 34) | def get_raw_frame_as_bytes(packet):

FILE: src/protocols/CoAP/examples/client_example.py
  function signal_handler (line 23) | def signal_handler(sig, frame):
  function client_procedure (line 31) | def client_procedure(host, port, path):

FILE: src/protocols/CoAP/examples/resource_example.py
  class BasicResource (line 4) | class BasicResource(Resource):
    method __init__ (line 6) | def __init__(self, name="BasicResource", coap_server=None):
    method render_GET (line 11) | def render_GET(self, request):
    method render_PUT (line 14) | def render_PUT(self, request):
    method render_POST (line 18) | def render_POST(self, request):
    method render_DELETE (line 24) | def render_DELETE(self, request):
    method render_GET_advanced (line 27) | def render_GET_advanced(self, request, response):
    method render_PUT_advanced (line 30) | def render_PUT_advanced(self, request, response):
    method render_POST_advanced (line 33) | def render_POST_advanced(self, request, response):
    method render_DELETE_advanced (line 36) | def render_DELETE_advanced(self, request, response):

FILE: src/protocols/CoAP/examples/server_example.py
  class CoAPServer (line 20) | class CoAPServer(CoAP):
    method __init__ (line 21) | def __init__(self, host, port, path):
  function server_procedure (line 26) | def server_procedure(host, port, path):

FILE: src/protocols/MQTT/attacks/mqtt_dos_attack.py
  class MQTTDoSAttack (line 17) | class MQTTDoSAttack(Attack):
    method __init__ (line 37) | def __init__(self):
    method signal_handler (line 58) | def signal_handler(self, sig, frame):
    method stop_attack (line 61) | def stop_attack(self):
    method pre_attack_init (line 71) | def pre_attack_init(self):
    method run (line 75) | def run(self):
  class TestMQTTDoSAttack (line 107) | class TestMQTTDoSAttack(unittest.TestCase):
    method setUp (line 108) | def setUp(self):
    method tearDown (line 111) | def tearDown(self):
    method test_name (line 114) | def test_name(self):
    method test_inputs (line 117) | def test_inputs(self):
    method test_non_initialized_inputs (line 123) | def test_non_initialized_inputs(self):
    method test_after_getting_inputs (line 129) | def test_after_getting_inputs(self):
    method test_dos_attack (line 144) | def test_dos_attack(self):

FILE: src/protocols/MQTT/attacks/mqtt_fuzzing_attack_suite.py
  class MQTTFuzzingAttackSuite (line 8) | class MQTTFuzzingAttackSuite(AttackSuite):
    method __init__ (line 10) | def __init__(self):
  class TestMQTTFuzzingAttackSuite (line 15) | class TestMQTTFuzzingAttackSuite(unittest.TestCase):
    method setUp (line 16) | def setUp(self):
    method tearDown (line 19) | def tearDown(self):
    method test_name (line 22) | def test_name(self):
    method test_attack_list (line 25) | def test_attack_list(self):
    method test_attacks (line 31) | def test_attacks(self):

FILE: src/protocols/MQTT/attacks/mqtt_generation_based_fuzzing.py
  class MQTTGenerationBasedFuzzingAttack (line 17) | class MQTTGenerationBasedFuzzingAttack(Attack):
    method __init__ (line 35) | def __init__(self):
    method signal_handler (line 50) | def signal_handler(self, sig, frame):
    method stop_attack (line 53) | def stop_attack(self):
    method pre_attack_init (line 61) | def pre_attack_init(self):
    method send_subscribe_or_unsubscribe (line 68) | def send_subscribe_or_unsubscribe(self, fuzz_client, message_type, top...
    method random_topic_generator (line 107) | def random_topic_generator(self, message_type, possible_characters, po...
    method run (line 124) | def run(self):
  class TestMQTTGenerationBasedFuzzingAttack (line 183) | class TestMQTTGenerationBasedFuzzingAttack(unittest.TestCase):
    method setUp (line 184) | def setUp(self):
    method tearDown (line 187) | def tearDown(self):
    method test_name (line 190) | def test_name(self):
    method test_inputs (line 193) | def test_inputs(self):
    method test_non_initialized_inputs (line 199) | def test_non_initialized_inputs(self):
    method test_after_getting_inputs (line 205) | def test_after_getting_inputs(self):
    method testGenerationBasedFuzzingAttack (line 220) | def testGenerationBasedFuzzingAttack(self):

FILE: src/protocols/MQTT/attacks/mqtt_payload_size_fuzzer.py
  class MQTTPayloadSizeFuzzerAttack (line 15) | class MQTTPayloadSizeFuzzerAttack(Attack):
    method __init__ (line 33) | def __init__(self):
    method signal_handler (line 49) | def signal_handler(self, sig, frame):
    method stop_attack (line 52) | def stop_attack(self):
    method pre_attack_init (line 60) | def pre_attack_init(self):
    method run (line 71) | def run(self):
  class TestMQTTPayloadSizeAttack (line 101) | class TestMQTTPayloadSizeAttack(unittest.TestCase):
    method setUp (line 102) | def setUp(self):
    method tearDown (line 105) | def tearDown(self):
    method test_name (line 108) | def test_name(self):
    method test_inputs (line 111) | def test_inputs(self):
    method test_non_initialized_inputs (line 117) | def test_non_initialized_inputs(self):
    method test_after_getting_inputs (line 123) | def test_after_getting_inputs(self):
    method test_invalid_fuzzing_turn (line 138) | def test_invalid_fuzzing_turn(self):
    method test_payload_size_fuzzing_attack (line 149) | def test_payload_size_fuzzing_attack(self):

FILE: src/protocols/MQTT/attacks/mqtt_random_payload_fuzzing.py
  class MQTTRandomPayloadFuzzingAttack (line 17) | class MQTTRandomPayloadFuzzingAttack(Attack):
    method __init__ (line 37) | def __init__(self):
    method signal_handler (line 56) | def signal_handler(self, sig, frame):
    method stop_attack (line 59) | def stop_attack(self):
    method pre_attack_init (line 67) | def pre_attack_init(self):
    method run (line 74) | def run(self):
  class TestMQTTRandomPayloadAttack (line 118) | class TestMQTTRandomPayloadAttack(unittest.TestCase):
    method setUp (line 119) | def setUp(self):
    method tearDown (line 122) | def tearDown(self):
    method test_name (line 125) | def test_name(self):
    method test_inputs (line 128) | def test_inputs(self):
    method test_non_initialized_inputs (line 134) | def test_non_initialized_inputs(self):
    method test_after_getting_inputs (line 140) | def test_after_getting_inputs(self):
    method test_invalid_fuzzing_turn (line 155) | def test_invalid_fuzzing_turn(self):
    method test_random_payload_fuzzing_attack (line 166) | def test_random_payload_fuzzing_attack(self):

FILE: src/protocols/MQTT/attacks/mqtt_replay_attack.py
  class MQTTReplayAttack (line 15) | class MQTTReplayAttack(Attack):
    method __init__ (line 31) | def __init__(self):
    method signal_handler (line 47) | def signal_handler(self, sig, frame):
    method stop_attack (line 50) | def stop_attack(self):
    method pre_attack_init (line 57) | def pre_attack_init(self):
    method run (line 70) | def run(self):
    method pre_attack_process (line 86) | def pre_attack_process(self):
  class TestMQTTReplayAttack (line 100) | class TestMQTTReplayAttack(unittest.TestCase):
    method setUp (line 101) | def setUp(self):
    method tearDown (line 104) | def tearDown(self):
    method test_name (line 107) | def test_name(self):
    method test_non_initialized_inputs (line 110) | def test_non_initialized_inputs(self):
    method test_after_getting_inputs (line 116) | def test_after_getting_inputs(self):
    method test_replay_attack (line 128) | def test_replay_attack(self):

FILE: src/protocols/MQTT/attacks/mqtt_sniff_attack.py
  class MQTTSniffAttack (line 13) | class MQTTSniffAttack(Attack):
    method __init__ (line 26) | def __init__(self):
    method signal_handler (line 45) | def signal_handler(self, sig, frame):
    method stop_attack (line 48) | def stop_attack(self):
    method input_check (line 53) | def input_check(self):
    method run (line 59) | def run(self):
  class TestMQTTSniffAttack (line 71) | class TestMQTTSniffAttack(unittest.TestCase):
    method setUp (line 72) | def setUp(self):
    method tearDown (line 75) | def tearDown(self):
    method test_name (line 78) | def test_name(self):
    method test_non_initialized_inputs (line 81) | def test_non_initialized_inputs(self):
    method test_after_getting_inputs (line 87) | def test_after_getting_inputs(self):
    method test_sniff_attack (line 99) | def test_sniff_attack(self):

FILE: src/protocols/MQTT/attacks/mqtt_topic_name_fuzzing.py
  class MQTTTopicNameFuzzingAttack (line 14) | class MQTTTopicNameFuzzingAttack(Attack):
    method __init__ (line 28) | def __init__(self):
    method signal_handler (line 43) | def signal_handler(self, sig, frame):
    method stop_attack (line 46) | def stop_attack(self):
    method pre_attack_init (line 53) | def pre_attack_init(self):
    method run (line 60) | def run(self):
  class TestMQTTTopicNameFuzzingAttack (line 83) | class TestMQTTTopicNameFuzzingAttack(unittest.TestCase):
    method setUp (line 84) | def setUp(self):
    method tearDown (line 87) | def tearDown(self):
    method test_name (line 90) | def test_name(self):
    method test_inputs (line 93) | def test_inputs(self):
    method test_non_initialized_inputs (line 99) | def test_non_initialized_inputs(self):
    method test_after_getting_inputs (line 105) | def test_after_getting_inputs(self):
    method test_payload_size_fuzzing_attack (line 120) | def test_payload_size_fuzzing_attack(self):

FILE: src/protocols/MQTT/examples/Demo/demo_publisher.py
  function signal_handler (line 21) | def signal_handler(sig, frame):
  function publish_procedure (line 30) | def publish_procedure(publisher_client, broker_host_name=DEFAULT_BROKER_...
  function data_generator (line 56) | def data_generator():

FILE: src/protocols/MQTT/examples/Demo/demo_subscriber.py
  class DemoSubscriber (line 21) | class DemoSubscriber(object):
    method __init__ (line 25) | def __init__(self):
    method on_message (line 29) | def on_message(self, client, userdata, message):
    method on_message_append (line 36) | def on_message_append(self, message):
    method start_processing_of_temperatures (line 45) | def start_processing_of_temperatures(self):
  class TemperatureData (line 52) | class TemperatureData(object):
    method __init__ (line 56) | def __init__(self, temperature_string):
    method get_date (line 64) | def get_date(self):
    method set_date (line 67) | def set_date(self, date):
    method get_temperature (line 70) | def get_temperature(self):
    method set_temperature (line 73) | def set_temperature(self, temperature):
    method __repr__ (line 76) | def __repr__(self):
  function signal_handler (line 80) | def signal_handler(sig, frame):
  function subscribe_procedure (line 89) | def subscribe_procedure(subscriber_client, broker_host_name=DEFAULT_BROK...

FILE: src/protocols/MQTT/examples/publisher_example.py
  function signal_handler (line 23) | def signal_handler(sig, frame):
  function on_message (line 32) | def on_message(client, userdata, message):
  function on_connect (line 36) | def on_connect(client, userdata, flags, rc):
  function publish_procedure (line 40) | def publish_procedure(publisher_client, broker_host_name=DEFAULT_BROKER_...

FILE: src/protocols/MQTT/examples/subscriber_example.py
  function signal_handler (line 23) | def signal_handler(sig, frame):
  function on_message (line 32) | def on_message(client, userdata, message):
  function on_connect (line 36) | def on_connect(client, userdata, flags, rc):
  function subscribe_procedure (line 40) | def subscribe_procedure(subscriber_client, broker_host_name=DEFAULT_BROK...

FILE: src/protocols/MQTT/mqtt_protocol.py
  class MQTT (line 6) | class MQTT(Protocol):
    method __init__ (line 8) | def __init__(self):
  class TestMQTTProtocol (line 31) | class TestMQTTProtocol(unittest.TestCase):
    method setUp (line 32) | def setUp(self):
    method tearDown (line 35) | def tearDown(self):
    method test_name (line 38) | def test_name(self):
    method test_attacks (line 41) | def test_attacks(self):

FILE: src/protocols/MQTT/mqtt_scanner.py
  class MQTTScanner (line 15) | class MQTTScanner:
    method __init__ (line 21) | def __init__(self):
    method scan (line 25) | def scan(timeout=generic_sniffer.DEFAULT_SNIFF_TIMEOUT, interface=gene...
    method get_raw_tcp_payload_as_bytes (line 36) | def get_raw_tcp_payload_as_bytes(packet):
    method get_raw_frame_as_bytes (line 40) | def get_raw_frame_as_bytes(packet):
Condensed preview — 116 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (458K chars).
[
  {
    "path": ".gitignore",
    "chars": 1275,
    "preview": "# Byte-compiled / optimized / DLL files\n__pycache__/\n*.py[cod]\n*$py.class\n\n# C extensions\n*.so\n\n# Distribution / packagi"
  },
  {
    "path": "LICENSE",
    "chars": 1118,
    "preview": "MIT License\n\nCopyright (c) 2018 Berat Cankar, Bigehan Bingöl, Doğukan Çavdaroğlu, Ebru Çelebi\n\nPermission is hereby gran"
  },
  {
    "path": "README.md",
    "chars": 7835,
    "preview": "# PENIOT: Penetration Testing Tool for IoT\n\n#### Table of Contents\n* [Project Description](#Project-Description)\n    * ["
  },
  {
    "path": "setup.py",
    "chars": 824,
    "preview": "from os import path\nfrom setuptools import setup, find_packages\nimport sys\n\nsys.path.insert(0, \"src\")\n\nwith open(path.jo"
  },
  {
    "path": "src/Entity/__init__.py",
    "chars": 475,
    "preview": "\"\"\"\n    This package contains the following entities:\n\n    1) Protocol\n    2) Attack Suite\n    3) Attack\n    4) Input Fo"
  },
  {
    "path": "src/Entity/attack.py",
    "chars": 2216,
    "preview": "import logging\n\nfrom GUI import hard_coded_texts as hct\n\n\nclass Attack(object):\n    name = None\n    inputs = []\n    defa"
  },
  {
    "path": "src/Entity/attack_suite.py",
    "chars": 649,
    "preview": "class AttackSuite(object):\n\n    name = None\n    attacks = []\n\n    def __init__(self, name, attacks):\n        self.name ="
  },
  {
    "path": "src/Entity/input_format.py",
    "chars": 1709,
    "preview": "class InputFormat(object):\n\n    def __init__(self, label_name, name, value, _type, default_value=None, mandatory=False, "
  },
  {
    "path": "src/Entity/protocol.py",
    "chars": 852,
    "preview": "class Protocol(object):\n\n    name = None\n    attack_suites = []\n\n    def __init__(self, name, attack_suites, definition)"
  },
  {
    "path": "src/GUI/__init__.py",
    "chars": 68,
    "preview": "\"\"\"\n    This package includes graphical user interface of PENIOT\n\"\"\""
  },
  {
    "path": "src/GUI/custom_widgets.py",
    "chars": 1855,
    "preview": "from Tkinter import *\nfrom hard_coded_texts import get_project_name\n\n\nclass Header(Frame):\n    \"\"\"\n    Generic header te"
  },
  {
    "path": "src/GUI/hard_coded_texts.py",
    "chars": 2621,
    "preview": "\"\"\"\n       This file contains some methods which return hard-coded texts and constant texts\n\"\"\"\n\n\n# Window title, size a"
  },
  {
    "path": "src/GUI/tkinter.py",
    "chars": 37326,
    "preview": "import logging\nimport tkFileDialog\nimport ttk\nfrom threading import Timer\n\nfrom custom_widgets import *\nfrom hard_coded_"
  },
  {
    "path": "src/GUI/utils.py",
    "chars": 8741,
    "preview": "# This file contains methods which are used in the GUI.\nimport importlib\nimport inspect\nimport os\nimport pkgutil\nimport "
  },
  {
    "path": "src/Utils/CommonUtil/__init__.py",
    "chars": 672,
    "preview": "\"\"\"\n    Common Utilities\n    It contains necessary functionalities used commonly in project.\n\"\"\"\n\nimport datetime\n\n\ndef "
  },
  {
    "path": "src/Utils/ExtendUtil/__init__.py",
    "chars": 117,
    "preview": "\"\"\"\n    Extendability Utilities\n    It contains necessary functionality used for importing and exporting scripts.\n\"\"\""
  },
  {
    "path": "src/Utils/ExtendUtil/export_attack_suite_template.py",
    "chars": 1354,
    "preview": "#################################################################################\n#                               IMPORT"
  },
  {
    "path": "src/Utils/ExtendUtil/export_attack_template.py",
    "chars": 3569,
    "preview": "#################################################################################\n#                               IMPORT"
  },
  {
    "path": "src/Utils/ExtendUtil/export_protocol_template.py",
    "chars": 2184,
    "preview": "#################################################################################\n#                               IMPORT"
  },
  {
    "path": "src/Utils/ExtendUtil/export_util.py",
    "chars": 10663,
    "preview": "from enum import Enum\nfrom Utils.RandomUtil import random_generated_names as random_util\n\nimport logging\nimport os\nimpor"
  },
  {
    "path": "src/Utils/ExtendUtil/import_util.py",
    "chars": 6462,
    "preview": "from enum import Enum\nfrom os import listdir\nfrom os.path import isfile, join\n\nimport logging\nimport os\nimport shutil\nim"
  },
  {
    "path": "src/Utils/FilterUtil/__init__.py",
    "chars": 172,
    "preview": "\"\"\"\n    Filtering Utilities\n    It contains necessary functionalities used for filtering packets in several attacks\n\n   "
  },
  {
    "path": "src/Utils/FilterUtil/pyshark_filter_util.py",
    "chars": 1501,
    "preview": "import logging\n\nlogging.basicConfig(level=logging.DEBUG, format=\"%(asctime)s:%(levelname)s:%(name)s : %(message)s\")\nlogg"
  },
  {
    "path": "src/Utils/FuzzerUtil/__init__.py",
    "chars": 144,
    "preview": "\"\"\"\n    Fuzzer Utilities\n    It contains necessary functionalities used for fuzzing attacks\n\n    1) Radamsa Random Fuzzi"
  },
  {
    "path": "src/Utils/FuzzerUtil/radamsa_util.py",
    "chars": 1785,
    "preview": "import logging\nimport subprocess\n\nlogging.basicConfig(level=logging.DEBUG, format=\"%(asctime)s:%(levelname)s:%(name)s:%("
  },
  {
    "path": "src/Utils/RandomUtil/__init__.py",
    "chars": 112,
    "preview": "\"\"\"\n    Random Utilities\n    It contains necessary functionalities that is related to randomized operations.\n\"\"\""
  },
  {
    "path": "src/Utils/RandomUtil/random_generated_names.py",
    "chars": 502,
    "preview": "import random\nimport string\nimport time\n\n\ndef get_random_client_name():\n    return 'peniot-cli-' + ''.join(random.choice"
  },
  {
    "path": "src/Utils/ReportUtil/__init__.py",
    "chars": 125,
    "preview": "\"\"\"\n    Report Generation Utilities\n    It contains necessary functionalities used for reporting\n\n    1) Report Generato"
  },
  {
    "path": "src/Utils/ReportUtil/report_generator.py",
    "chars": 8573,
    "preview": "from fpdf import FPDF\n\nfrom Utils.CommonUtil import get_current_datetime_for_report_format, get_current_datetime_for_fil"
  },
  {
    "path": "src/Utils/SnifferUtil/__init__.py",
    "chars": 126,
    "preview": "\"\"\"\n    Sniffer Utilities\n    It contains necessary functionalities used for sniffers\n\n    1) Generic Sniffer with PySha"
  },
  {
    "path": "src/Utils/SnifferUtil/generic_sniffer.py",
    "chars": 3305,
    "preview": "import logging\nimport os\n\nimport pyshark\nfrom Utils.FilterUtil import pyshark_filter_util as pyshark_filter_util\n\nloggin"
  },
  {
    "path": "src/Utils/__init__.py",
    "chars": 34,
    "preview": "\"\"\"\n    General Utility Module\n\"\"\""
  },
  {
    "path": "src/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/captured_packets/__init__.py",
    "chars": 427,
    "preview": "\"\"\"\n    This package contains the all captured packets.\n    The files inside this package follows these rules:\n        -"
  },
  {
    "path": "src/module_installer.py",
    "chars": 1235,
    "preview": "print \"Checking whether we have necessary dependencies installed...\"\n\ntry:\n    import paho.mqtt\n\n    print \"[+] You have"
  },
  {
    "path": "src/peniot.py",
    "chars": 106,
    "preview": "# Run the program driver of tkinter\n\nif __name__ == '__main__':\n    from GUI.tkinter import run\n    run()\n"
  },
  {
    "path": "src/protocols/AMQP/__init__.py",
    "chars": 116,
    "preview": "\"\"\"\n    This package contains the following functionalities:\n\n    1) Example usage of AMQP.\n    2) AMQP Scanner\n\"\"\"\n"
  },
  {
    "path": "src/protocols/AMQP/amqp_protocol.py",
    "chars": 1412,
    "preview": "import unittest\n\nfrom Entity.protocol import Protocol\n\n\nclass AMQP(Protocol):\n\n    def __init__(self):\n        amqp_defi"
  },
  {
    "path": "src/protocols/AMQP/amqp_scanner.py",
    "chars": 1137,
    "preview": "from Utils.SnifferUtil import generic_sniffer as generic_sniffer\n\n# Capturing via TShark\namqp_layer_filter = \"amqp\"\n\n\ncl"
  },
  {
    "path": "src/protocols/AMQP/attacks/__init__.py",
    "chars": 181,
    "preview": "\"\"\"\n    This is a package that contains attacks to AMQP protocol.\n    Currently, it supports the following attacks\n\n    "
  },
  {
    "path": "src/protocols/AMQP/attacks/amqp_dos_attack.py",
    "chars": 5175,
    "preview": "import logging\nimport multiprocessing\nimport signal\nimport time\nimport unittest\n\nimport pika\n\nfrom Entity.attack import "
  },
  {
    "path": "src/protocols/AMQP/attacks/amqp_fuzzing_attack_suite.py",
    "chars": 1307,
    "preview": "from amqp_payload_size_fuzzer import *\nfrom amqp_random_payload_fuzzing import *\nfrom Entity.attack_suite import AttackS"
  },
  {
    "path": "src/protocols/AMQP/attacks/amqp_payload_size_fuzzer.py",
    "chars": 6907,
    "preview": "import logging\nimport multiprocessing\nimport random\nimport signal\nimport time\nimport unittest\n\nimport pika\n\nfrom Entity."
  },
  {
    "path": "src/protocols/AMQP/attacks/amqp_random_payload_fuzzing.py",
    "chars": 7633,
    "preview": "import logging\nimport multiprocessing\nimport random\nimport signal\nimport time\nimport unittest\n\nimport pika\n\nfrom Entity."
  },
  {
    "path": "src/protocols/AMQP/examples/__init__.py",
    "chars": 122,
    "preview": "\"\"\"\n    This package contains the following functionalities:\n\n    1) AMQP Sender Example\n    2) AMQP Receiver Example\n\"\""
  },
  {
    "path": "src/protocols/AMQP/examples/receiver_example.py",
    "chars": 2242,
    "preview": "import pika\n\nimport argparse\nimport logging\nimport signal\nimport sys\nimport time\n\nDEFAULT_BROKER_HOST = \"localhost\"\nDEFA"
  },
  {
    "path": "src/protocols/AMQP/examples/sender_example.py",
    "chars": 2691,
    "preview": "import pika\n\nimport argparse\nimport logging\nimport signal\nimport sys\nimport time\n\nDEFAULT_BROKER_HOST = \"localhost\"\nDEFA"
  },
  {
    "path": "src/protocols/BLE/Adafruit_BLESniffer/.gitignore",
    "chars": 77,
    "preview": "# Byte-compiled / optimized / DLL files\n__pycache__/\n*.py[cod]\n\n*.pcap\nlogs/\n"
  },
  {
    "path": "src/protocols/BLE/Adafruit_BLESniffer/API Manifest.txt",
    "chars": 370,
    "preview": "API Manifest.txt\ndocumentation.html\nexample.py\nLICENSE.txt\nNordic Semiconductor Sniffer API Guide.pdf\nsniffer_uart_proto"
  },
  {
    "path": "src/protocols/BLE/Adafruit_BLESniffer/LICENSE.txt",
    "chars": 1427,
    "preview": "All files in this package is released under the license below, except the \nWireshark dissector source files packet-nordi"
  },
  {
    "path": "src/protocols/BLE/Adafruit_BLESniffer/README.md",
    "chars": 2354,
    "preview": "# Python API for Bluefruit LE Sniffer \n\nThis repository contains the Python API for Adafruit's Bluefruit LE Sniffer, and"
  },
  {
    "path": "src/protocols/BLE/Adafruit_BLESniffer/SnifferAPI/CaptureFiles.py",
    "chars": 3775,
    "preview": "from __future__ import absolute_import\nimport time\nimport os\nimport logging\nfrom . import Logger\n\nLINKTYPE_BLUETOOTH_LE_"
  },
  {
    "path": "src/protocols/BLE/Adafruit_BLESniffer/SnifferAPI/Devices.py",
    "chars": 3814,
    "preview": "from __future__ import absolute_import\nfrom . import Notifications\nimport logging\n\n\nclass DeviceList(Notifications.Notif"
  },
  {
    "path": "src/protocols/BLE/Adafruit_BLESniffer/SnifferAPI/Exceptions.py",
    "chars": 275,
    "preview": "class SnifferTimeout(Exception):\n    pass\n\n\nclass UARTPacketError(Exception):\n    pass\n\n\nclass InvalidPacketException(Ex"
  },
  {
    "path": "src/protocols/BLE/Adafruit_BLESniffer/SnifferAPI/Logger.py",
    "chars": 4265,
    "preview": "from __future__ import absolute_import\nfrom __future__ import print_function\nimport time\nimport os\nimport logging\nimport"
  },
  {
    "path": "src/protocols/BLE/Adafruit_BLESniffer/SnifferAPI/Notifications.py",
    "chars": 1676,
    "preview": "from __future__ import absolute_import\nimport threading\n\n\nclass Notification():\n    def __init__(self, key, msg=None):\n "
  },
  {
    "path": "src/protocols/BLE/Adafruit_BLESniffer/SnifferAPI/Packet.py",
    "chars": 18040,
    "preview": "from __future__ import absolute_import\nfrom . import UART, Exceptions, Notifications\nimport time\nimport logging\nimport o"
  },
  {
    "path": "src/protocols/BLE/Adafruit_BLESniffer/SnifferAPI/Sniffer.py",
    "chars": 5788,
    "preview": "from __future__ import absolute_import\nimport sys\nimport os\nimport threading\nimport logging\nfrom . import SnifferCollect"
  },
  {
    "path": "src/protocols/BLE/Adafruit_BLESniffer/SnifferAPI/SnifferCollector.py",
    "chars": 8650,
    "preview": "from __future__ import absolute_import\nfrom . import Packet, Exceptions, CaptureFiles, Devices, Notifications, Version\ni"
  },
  {
    "path": "src/protocols/BLE/Adafruit_BLESniffer/SnifferAPI/UART.py",
    "chars": 2440,
    "preview": "from __future__ import absolute_import\nimport logging\nimport serial\nimport collections\nimport serial.tools.list_ports as"
  },
  {
    "path": "src/protocols/BLE/Adafruit_BLESniffer/SnifferAPI/Version.py",
    "chars": 1343,
    "preview": "from __future__ import absolute_import\nfrom . import myVersion\n\npdfVersion = \"1.2\"\n\n\ndef getRevision():\n    return myVer"
  },
  {
    "path": "src/protocols/BLE/Adafruit_BLESniffer/SnifferAPI/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/protocols/BLE/Adafruit_BLESniffer/SnifferAPI/myVersion.py",
    "chars": 69,
    "preview": "version = 1111\nversionString = \"1.0.1\"\nversionNameAppendix = \"_1111\"\n"
  },
  {
    "path": "src/protocols/BLE/Adafruit_BLESniffer/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/protocols/BLE/Adafruit_BLESniffer/documentation.html",
    "chars": 10957,
    "preview": "<html>\n<style>\ntable\n{\nwidth:850px;\n}\ntable,th,td\n{\nborder:1px solid black;\nborder-collapse:collapse\n}\n\ndiv\n{\nwidth:auto"
  },
  {
    "path": "src/protocols/BLE/Adafruit_BLESniffer/requirements.txt",
    "chars": 26,
    "preview": "six>=1.11.0\npyserial>=3.4\n"
  },
  {
    "path": "src/protocols/BLE/Adafruit_BLESniffer/setup.cfg",
    "chars": 30,
    "preview": "[flake8]\n\nmax-line-length=100\n"
  },
  {
    "path": "src/protocols/BLE/Adafruit_BLESniffer/sniffer.py",
    "chars": 8214,
    "preview": "from __future__ import absolute_import\nfrom __future__ import print_function\nfrom six.moves import input\n\nfrom protocols"
  },
  {
    "path": "src/protocols/BLE/Adafruit_BLESniffer/sniffer_uart_protocol.xlsx",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/protocols/BLE/Adafruit_BLESniffer/wireshark_dissector_source/OSX/readme.md",
    "chars": 497,
    "preview": "This file should be place in the ~/.wireshark/plugins folder on your OS X development machine, so \n`~/.wireshark/plugins"
  },
  {
    "path": "src/protocols/BLE/Adafruit_BLESniffer/wireshark_dissector_source/packet-btle.c",
    "chars": 66157,
    "preview": "/* packet-btle.c\n * Routines for Bluetooth Low Energy dissection\n * Copyright 2013, Mike Ryan, mikeryan /at/ isecpartner"
  },
  {
    "path": "src/protocols/BLE/Adafruit_BLESniffer/wireshark_dissector_source/packet-nordic_ble.c",
    "chars": 27135,
    "preview": "/* packet-nordic_ble.c\n * Routines for nordic ble sniffer dissection\n * Copyright 201x, YOUR_NAME <YOUR_EMAIL_ADDRESS>\n "
  },
  {
    "path": "src/protocols/BLE/BLETest.py",
    "chars": 187,
    "preview": "\"\"\"\n    BLE (Bluetooth Low Energy) Testing Class\n    Call necessary tests from this class\n\"\"\"\n\n\nclass BLETest:\n\n    @sta"
  },
  {
    "path": "src/protocols/BLE/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/protocols/BLE/attacks/__init__.py",
    "chars": 117,
    "preview": "\"\"\"\n    This package contains the following BLE attacks:\n        1) BLE Sniff attack\n        2) BLE Replay attack\n\"\"\""
  },
  {
    "path": "src/protocols/BLE/attacks/ble_replay_attack.py",
    "chars": 922,
    "preview": "import logging\n\nfrom Entity.attack import Attack\nfrom Entity.input_format import InputFormat\nfrom protocols.BLE.ble_repl"
  },
  {
    "path": "src/protocols/BLE/attacks/ble_sniff_attack.py",
    "chars": 1042,
    "preview": "import logging\n\nfrom Entity.attack import Attack\nfrom Entity.input_format import InputFormat\nfrom protocols.BLE.ble_snif"
  },
  {
    "path": "src/protocols/BLE/ble_advertiser.py",
    "chars": 714,
    "preview": "from bluetooth.ble import BeaconService\nimport time\nimport argparse\n\n# This one uses pybluez library!!!\n\nDEFAULT_ADVERTI"
  },
  {
    "path": "src/protocols/BLE/ble_device.py",
    "chars": 979,
    "preview": "import pexpect\n\n\nclass BLEDevice:\n    \"\"\"\n    Represents a BLE device.\n    It uses `gatttool` to connect a BLE device.\n "
  },
  {
    "path": "src/protocols/BLE/ble_protocol.py",
    "chars": 210,
    "preview": "from Entity.protocol import Protocol\n\n\nclass BLE(Protocol):\n\n    def __init__(self):\n        ble_definition = \"\"\n       "
  },
  {
    "path": "src/protocols/BLE/ble_replay_attack.py",
    "chars": 3382,
    "preview": "import os\nfrom protocols.BLE.ble_device import BLEDevice\n\n\nclass BLEReplayAttackHelper:\n    \"\"\"\n    This is the helper c"
  },
  {
    "path": "src/protocols/BLE/ble_sniff.py",
    "chars": 3916,
    "preview": "import os\nimport sys\nimport time\n\nfrom Utils import CommonUtil\nfrom protocols.BLE.Adafruit_BLESniffer import sniffer\nfro"
  },
  {
    "path": "src/protocols/BLE/ble_tools.py",
    "chars": 1759,
    "preview": "from bluepy import btle\n\n\"\"\"\n    This class enables us to scan for BLE devices. \n\"\"\"\n\n\nclass BLEScanner:\n    \"\"\"\n    Sca"
  },
  {
    "path": "src/protocols/CoAP/__init__.py",
    "chars": 2691,
    "preview": "\"\"\"\n    This package contains the following functionalities:\n\n    1) Example usage of CoAP.\n    2) Attacks that is done "
  },
  {
    "path": "src/protocols/CoAP/attacks/__init__.py",
    "chars": 287,
    "preview": "\"\"\"\n    This is a package that contains attacks to CoAP protocol.\n    Currently, it supports the following attacks\n\n    "
  },
  {
    "path": "src/protocols/CoAP/attacks/coap_dos_attack.py",
    "chars": 4852,
    "preview": "import logging\nimport multiprocessing\nimport signal\nimport time\nimport unittest\n\nfrom coapthon.client.helperclient impor"
  },
  {
    "path": "src/protocols/CoAP/attacks/coap_fuzzing_attack_suite.py",
    "chars": 1347,
    "preview": "from Entity.attack_suite import AttackSuite\nfrom coap_payload_size_fuzzer import *\nfrom coap_random_payload_fuzzing impo"
  },
  {
    "path": "src/protocols/CoAP/attacks/coap_payload_size_fuzzer.py",
    "chars": 7249,
    "preview": "import logging\nimport multiprocessing\nimport random\nimport signal\nimport time\nimport unittest\n\nfrom coapthon.client.help"
  },
  {
    "path": "src/protocols/CoAP/attacks/coap_random_payload_fuzzing.py",
    "chars": 8245,
    "preview": "import logging\nimport multiprocessing\nimport random\nimport signal\nimport time\nimport unittest\n\nfrom coapthon.client.help"
  },
  {
    "path": "src/protocols/CoAP/attacks/coap_replay_attack.py",
    "chars": 4841,
    "preview": "import logging\nimport signal\nimport socket\nimport time\nimport unittest\n\nfrom Entity.attack import Attack\nfrom Entity.inp"
  },
  {
    "path": "src/protocols/CoAP/attacks/coap_sniff_attack.py",
    "chars": 3532,
    "preview": "import logging\nimport signal\nimport time\nimport unittest\n\nfrom Entity.attack import Attack\nfrom Entity.input_format impo"
  },
  {
    "path": "src/protocols/CoAP/coap_protocol.py",
    "chars": 2521,
    "preview": "from Entity.protocol import Protocol\n\nimport unittest\n\n\nclass CoAP(Protocol):\n\n    def __init__(self):\n        co_ap_def"
  },
  {
    "path": "src/protocols/CoAP/coap_scanner.py",
    "chars": 1751,
    "preview": "from Utils.SnifferUtil import generic_sniffer as generic_sniffer\n\nimport socket\n\n# Capturing via TShark\ncoap_layer_filte"
  },
  {
    "path": "src/protocols/CoAP/examples/__init__.py",
    "chars": 149,
    "preview": "\"\"\"\n    This package contains the following functionalities:\n\n    1) CoAP Server Example\n    2) CoAP Client Example\n    "
  },
  {
    "path": "src/protocols/CoAP/examples/client_example.py",
    "chars": 1694,
    "preview": "from coapthon.client.helperclient import HelperClient\n\nimport argparse\nimport logging\nimport signal\nimport sys\nimport ti"
  },
  {
    "path": "src/protocols/CoAP/examples/resource_example.py",
    "chars": 1003,
    "preview": "from coapthon.resources.resource import Resource\n\n\nclass BasicResource(Resource):\n\n    def __init__(self, name=\"BasicRes"
  },
  {
    "path": "src/protocols/CoAP/examples/server_example.py",
    "chars": 1431,
    "preview": "from coapthon.server.coap import CoAP\nfrom resource_example import BasicResource\n\nimport argparse\n# import logging\n\nDEFA"
  },
  {
    "path": "src/protocols/MQTT/__init__.py",
    "chars": 253,
    "preview": "\"\"\"\n    This package includes the following functionalities\n\n    1) Attacks to perform on MQTT protocol\n    2) MQTT subs"
  },
  {
    "path": "src/protocols/MQTT/attacks/__init__.py",
    "chars": 230,
    "preview": "\"\"\"\n    This is a package that contains attacks to MQTT protocol.\n    Currently, it supports the following attacks\n\n    "
  },
  {
    "path": "src/protocols/MQTT/attacks/mqtt_dos_attack.py",
    "chars": 5970,
    "preview": "import multiprocessing\nimport random\nimport signal\nimport string\nimport sys\nimport logging\nimport time\nimport unittest\n\n"
  },
  {
    "path": "src/protocols/MQTT/attacks/mqtt_fuzzing_attack_suite.py",
    "chars": 1480,
    "preview": "from mqtt_generation_based_fuzzing import *\nfrom mqtt_payload_size_fuzzer import *\nfrom mqtt_random_payload_fuzzing impo"
  },
  {
    "path": "src/protocols/MQTT/attacks/mqtt_generation_based_fuzzing.py",
    "chars": 10860,
    "preview": "import multiprocessing\nimport unittest\n\nimport paho.mqtt.client as paho\n\nimport logging\nimport random\nimport signal\nimpo"
  },
  {
    "path": "src/protocols/MQTT/attacks/mqtt_payload_size_fuzzer.py",
    "chars": 6265,
    "preview": "import paho.mqtt.client as paho\n\nimport multiprocessing\nimport logging\nimport random\nimport time\nimport signal\nimport un"
  },
  {
    "path": "src/protocols/MQTT/attacks/mqtt_random_payload_fuzzing.py",
    "chars": 7033,
    "preview": "import multiprocessing\nimport unittest\n\nimport paho.mqtt.client as paho\n\nimport logging\nimport random\nimport signal\nimpo"
  },
  {
    "path": "src/protocols/MQTT/attacks/mqtt_replay_attack.py",
    "chars": 5407,
    "preview": "import logging\nimport signal\nimport time\nimport unittest\n\nimport paho.mqtt.client as paho\n\nfrom protocols.MQTT.mqtt_scan"
  },
  {
    "path": "src/protocols/MQTT/attacks/mqtt_sniff_attack.py",
    "chars": 3827,
    "preview": "import logging\nimport signal\nimport time\nimport unittest\n\nfrom protocols.MQTT.mqtt_scanner import MQTTScanner\nfrom Entit"
  },
  {
    "path": "src/protocols/MQTT/attacks/mqtt_topic_name_fuzzing.py",
    "chars": 5173,
    "preview": "import logging\nimport multiprocessing\nimport signal\nimport time\nimport unittest\n\nimport paho.mqtt.client as paho\n\nfrom E"
  },
  {
    "path": "src/protocols/MQTT/examples/Demo/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/protocols/MQTT/examples/Demo/demo_publisher.py",
    "chars": 2552,
    "preview": "import paho.mqtt.client as paho\n\nimport argparse\nimport logging\nimport signal\nimport sys\nimport time\n\nfrom Utils.RandomU"
  },
  {
    "path": "src/protocols/MQTT/examples/Demo/demo_subscriber.py",
    "chars": 4129,
    "preview": "import paho.mqtt.client as paho\n\nimport argparse\nimport logging\nimport signal\nimport sys\nimport threading\n\nfrom Utils.Ra"
  },
  {
    "path": "src/protocols/MQTT/examples/__init__.py",
    "chars": 203,
    "preview": "\"\"\"\n    This package is written to understand basic connection and communication mechanisms by local broker servers.\n   "
  },
  {
    "path": "src/protocols/MQTT/examples/publisher_example.py",
    "chars": 2528,
    "preview": "import paho.mqtt.client as paho\n\nimport argparse\nimport logging\nimport signal\nimport sys\nimport time\n\nDEFAULT_BROKER_HOS"
  },
  {
    "path": "src/protocols/MQTT/examples/subscriber_example.py",
    "chars": 2391,
    "preview": "import paho.mqtt.client as paho\n\nimport argparse\nimport logging\nimport signal\nimport sys\nimport time\n\nDEFAULT_BROKER_HOS"
  },
  {
    "path": "src/protocols/MQTT/mqtt_protocol.py",
    "chars": 2762,
    "preview": "from Entity.protocol import Protocol\n\nimport unittest\n\n\nclass MQTT(Protocol):\n\n    def __init__(self):\n        mqtt_defi"
  },
  {
    "path": "src/protocols/MQTT/mqtt_scanner.py",
    "chars": 5437,
    "preview": "from Utils.SnifferUtil import generic_sniffer as generic_sniffer\n\nfrom scapy.all import *\n\n# Since MQTT runs on TCP/IP, "
  },
  {
    "path": "src/protocols/__init__.py",
    "chars": 58,
    "preview": "\"\"\"\n    This package contains all available protocols.\n\"\"\""
  }
]

About this extraction

This page contains the full source code of the yakuza8/peniot GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 116 files (418.4 KB), approximately 108.8k tokens, and a symbol index with 756 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!