Full Code of NESCAU-UFLA/FuzzingTool for AI

master ee0a3c149fb9 cached
157 files
3.2 MB
854.3k tokens
761 symbols
1 requests
Download .txt
Showing preview only (3,416K chars total). Download the full file or copy to clipboard to get everything.
Repository: NESCAU-UFLA/FuzzingTool
Branch: master
Commit: ee0a3c149fb9
Files: 157
Total size: 3.2 MB

Directory structure:
gitextract_qgtvmx_a/

├── .github/
│   ├── CODE_OF_CONDUCT.md
│   ├── CONTRIBUTING.md
│   ├── ISSUE_TEMPLATE/
│   │   ├── BUG_REPORT.md
│   │   └── FEATURE_REQUEST.md
│   └── workflows/
│       ├── cd.yml
│       ├── ci.yml
│       ├── quality.yml
│       ├── sast.yml
│       └── sca.yml
├── .gitignore
├── CONTRIBUTORS.md
├── LICENSE
├── README.md
├── requirements.txt
├── setup.py
├── src/
│   ├── fuzzingtool/
│   │   ├── __init__.py
│   │   ├── api.py
│   │   ├── conn/
│   │   │   ├── __init__.py
│   │   │   ├── request_parser.py
│   │   │   └── requesters/
│   │   │       ├── __init__.py
│   │   │       ├── requester.py
│   │   │       └── subdomain_requester.py
│   │   ├── core/
│   │   │   ├── __init__.py
│   │   │   ├── bases/
│   │   │   │   ├── __init__.py
│   │   │   │   ├── base_encoder.py
│   │   │   │   ├── base_observer.py
│   │   │   │   ├── base_plugin.py
│   │   │   │   ├── base_scanner.py
│   │   │   │   ├── base_validator.py
│   │   │   │   ├── base_wordlist.py
│   │   │   │   └── job_provider.py
│   │   │   ├── blacklist_status.py
│   │   │   ├── defaults/
│   │   │   │   ├── __init__.py
│   │   │   │   ├── encoders/
│   │   │   │   │   ├── __init__.py
│   │   │   │   │   └── chain_encoder.py
│   │   │   │   ├── scanners/
│   │   │   │   │   ├── __init__.py
│   │   │   │   │   ├── data_scanner.py
│   │   │   │   │   ├── path_scanner.py
│   │   │   │   │   └── subdomain_scanner.py
│   │   │   │   └── wordlists/
│   │   │   │       ├── __init__.py
│   │   │   │       ├── file_wordlist.py
│   │   │   │       └── list_wordlist.py
│   │   │   ├── dictionary.py
│   │   │   ├── filter.py
│   │   │   ├── fuzzer.py
│   │   │   ├── job_manager.py
│   │   │   ├── matcher.py
│   │   │   ├── payloader.py
│   │   │   ├── plugins/
│   │   │   │   ├── __init__.py
│   │   │   │   ├── encoders/
│   │   │   │   │   ├── __init__.py
│   │   │   │   │   ├── base64.py
│   │   │   │   │   ├── hex.py
│   │   │   │   │   ├── html.py
│   │   │   │   │   ├── html_dec.py
│   │   │   │   │   ├── html_hex.py
│   │   │   │   │   ├── plain.py
│   │   │   │   │   └── url.py
│   │   │   │   ├── scanners/
│   │   │   │   │   ├── __init__.py
│   │   │   │   │   ├── backups.py
│   │   │   │   │   ├── grep.py
│   │   │   │   │   ├── reflected.py
│   │   │   │   │   └── wappalyzer.py
│   │   │   │   └── wordlists/
│   │   │   │       ├── __init__.py
│   │   │   │       ├── crt_sh.py
│   │   │   │       ├── dns_dumpster.py
│   │   │   │       ├── dns_zone.py
│   │   │   │       ├── overflow.py
│   │   │   │       └── robots.py
│   │   │   ├── recursion_manager.py
│   │   │   └── summary.py
│   │   ├── decorators/
│   │   │   ├── __init__.py
│   │   │   ├── plugin_meta.py
│   │   │   └── report_meta.py
│   │   ├── exceptions/
│   │   │   ├── __init__.py
│   │   │   ├── base_exceptions.py
│   │   │   ├── main_exceptions.py
│   │   │   ├── param_exceptions.py
│   │   │   ├── plugin_exceptions.py
│   │   │   └── request_exceptions.py
│   │   ├── factories/
│   │   │   ├── __init__.py
│   │   │   ├── base_factories.py
│   │   │   ├── plugin_factory.py
│   │   │   └── wordlist_factory.py
│   │   ├── fuzz_lib.py
│   │   ├── fuzzingtool.py
│   │   ├── interfaces/
│   │   │   ├── __init__.py
│   │   │   └── cli/
│   │   │       ├── __init__.py
│   │   │       ├── cli_arguments.py
│   │   │       ├── cli_controller.py
│   │   │       └── cli_output.py
│   │   ├── objects/
│   │   │   ├── __init__.py
│   │   │   ├── base_objects.py
│   │   │   ├── error.py
│   │   │   ├── fuzz_word.py
│   │   │   ├── http_history.py
│   │   │   ├── payload.py
│   │   │   ├── result.py
│   │   │   └── scanner_result.py
│   │   ├── persistence/
│   │   │   ├── __init__.py
│   │   │   ├── base_report.py
│   │   │   ├── logger.py
│   │   │   ├── report.py
│   │   │   └── reports/
│   │   │       ├── __init__.py
│   │   │       ├── csv_report.py
│   │   │       ├── json_report.py
│   │   │       └── txt_report.py
│   │   └── utils/
│   │       ├── __init__.py
│   │       ├── argument_utils.py
│   │       ├── consts.py
│   │       ├── file_utils.py
│   │       ├── http_utils.py
│   │       ├── result_utils.py
│   │       └── utils.py
│   └── fuzzingtool.py
├── tests/
│   ├── __init__.py
│   ├── conn/
│   │   ├── __init__.py
│   │   ├── requesters/
│   │   │   ├── __init__.py
│   │   │   ├── test_requester.py
│   │   │   └── test_subdomain_requester.py
│   │   └── test_request_parser.py
│   ├── core/
│   │   ├── __init__.py
│   │   ├── test_blacklist_status.py
│   │   ├── test_filter.py
│   │   ├── test_job_manager.py
│   │   ├── test_matcher.py
│   │   ├── test_payloader.py
│   │   └── test_recursion_manager.py
│   ├── decorators/
│   │   └── test_plugin_meta.py
│   ├── factories/
│   │   ├── test_plugin_factory.py
│   │   └── test_wordlist_factory.py
│   ├── interfaces/
│   │   ├── __init__.py
│   │   └── cli/
│   │       ├── __init__.py
│   │       ├── test_cli_arguments.py
│   │       └── test_cli_output.py
│   ├── mock_utils/
│   │   ├── __init__.py
│   │   ├── args_decorator.py
│   │   ├── response_mock.py
│   │   └── wordlist_mock.py
│   ├── objects/
│   │   ├── __init__.py
│   │   ├── test_error.py
│   │   ├── test_fuzz_word.py
│   │   ├── test_http_history.py
│   │   ├── test_payload.py
│   │   └── test_result.py
│   ├── persistence/
│   │   ├── test_logger.py
│   │   └── test_report.py
│   ├── test_fuzz_lib.py
│   └── utils/
│       ├── __init__.py
│       ├── test_argument_utils.py
│       ├── test_file_utils.py
│       ├── test_http_utils.py
│       ├── test_result_utils.py
│       └── test_utils.py
└── wordlists/
    ├── enumeration/
    │   ├── paths.txt
    │   └── subdomains.txt
    └── injection/
        ├── sqli.txt
        └── xss.txt

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

================================================
FILE: .github/CODE_OF_CONDUCT.md
================================================
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to make participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation.

## Our Standards
Examples of behavior that contributes to creating a positive environment include:
 * Using welcoming and inclusive language
 * Being respectful of differing viewpoints and experiences
 * Gracefully accepting constructive criticism
 * Focusing on what is best for the community
 * Showing empathy towards other community members

Examples of unacceptable behavior by participants include:
 * The use of sexualized language or imagery and unwelcome sexual attention or advances
 * Trolling, insulting/derogatory comments, and personal or political attacks
 * Public or private harassment
 * Publishing others’ private information, such as a physical or electronic address, without explicit permission
 * Other conduct which could reasonably be considered inappropriate in a professional setting

## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.

Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.

## Scope
This Code of Conduct applies within all project spaces, and it also applies when an individual is representing the project or its community in public spaces. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.

## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at nescau@ufla.br. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.

Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project’s leadership.

## Attribution
This Code of Conduct is adapted from the Contributor Covenant, version 1.4, available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html

================================================
FILE: .github/CONTRIBUTING.md
================================================
# Contributing
Before contribute to the FuzzingTool project, please read our [Code of Conduct](https://github.com/NESCAU-UFLA/FuzzingTool/blob/master/.github/CODE_OF_CONDUCT.md).

## Bug Report
Read our document [BUG_REPORT.md](https://github.com/NESCAU-UFLA/FuzzingTool/blob/master/.github/ISSUE_TEMPLATE/BUG_REPORT.md) to check the issue template for bug reporting.

## Feature Request
Read our document [FEATURE_REQUEST.md](https://github.com/NESCAU-UFLA/FuzzingTool/blob/master/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.md) to check the issue template for request a feature.

## Wordlist contributing
Feel free to conribute to our [wordlists](https://github.com/NESCAU-UFLA/FuzzingTool/tree/master/wordlists). Just remember to update the file header with your name as contributor.

## Code contributing
You can contribute for FuzzingTool project with:
 * Code refatoring (better encapsulation, for example);
 * Implement new features;
 * Bugfixes;

### Code guidelines
If you want to code contribute for FuzzingTool, follow this guideline:
 * Variable names must be cohesive with the context. Do not drop variable names like `x, y, z`;
 * Every function or method must have a description about it on comments, with the parameters and the return (if it has). An exception is for the methods that already have their meanings builded in (like class constructors if no parameters are passed, and destructors), and overriding methods. See this example:
 ```py
def concatenate(paramOne: int, paramTwo: str):
    """Concatenates the first parameter into the second parameter

    @type paramOne: int
    @param paramOne: An example of integer parameter
    @type paramTwo: str
    @param paramTwo: An example of string parameter
    @returns str: The concatenation of the given parameters
    """
    return f"{str(paramOne)}{paramTwo}"
 ```
 * Every class attribute that are being initialized on the constructor, must have an description. If you want to include a description for attributes that are outside of the constructor, just put inside the respectived method that are being called. For example:
 ```py
class Foo:
    """Class that handles with Foo

    Attributes:
        counter: A counter for the each Foo's method call
        varOne: A example variable to store the value for the first parameter
        varTwo: A example variable to store the value for the second parameter
    """
    def __init__(self, numOne: int, numTwo: int):
        """Class constructor

        @type numOne: int
        @param numOne: The first parameter of the example
        @type numTwo: int
        @param numTwo: The second parameter of the example
        """
        # No need to follow protected (_) or private (__) prefixes on attribute names
        self.counter = 0
        self._varOne = numOne
        self.__varTwo = numTwo
    
    def sum(self):
        """Make the sum between attributes and store the result into a buffer
        
        Attribute:
            sumBuffer: A buffer to store the sum results
        """
        self.counter += 1
        self.sumBuffer = self._varOne + self.__varTwo
 ```
 * Do not leave blank lines when inside a function or method, just to separate between each class, method or function.

================================================
FILE: .github/ISSUE_TEMPLATE/BUG_REPORT.md
================================================
---
name: BUG REPORT
about: Report a bug
title: ''
labels: bug
assignees: ''

---

## Bug reporting
**Description**: A clear and concise description of the problem.

### Context
 * FuzzingTool version (output of FuzzingTool --version);
 * Python version (output of python3 --version);
 * Operating System;

### Report
**Reproducing:**
 1. Run `...`;
 2. Error here.

**Curent behavior**: A description of the current behavior.

**Expected behavior**: A description of the expected behavior.

**Screenshots**: If you have any screenshots, put them above.

**Additional info**: Add any other info about the problem here.


================================================
FILE: .github/ISSUE_TEMPLATE/FEATURE_REQUEST.md
================================================
---
name: FEATURE REQUEST
about: Request a feature
title: ''
labels: enhancement
assignees: ''

---

## Feature request
**Context**: Is a solution or a feature request?

**Description**: Describe the context here.

**Additional info**: Add any other info about the problem here.

================================================
FILE: .github/workflows/cd.yml
================================================
name: delivery

on:
  release:
    types: [published]

jobs:
  pypi_upload:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@master
      - name: "Installing dependencies"
        run: pip install setuptools wheel twine

      - name: "Build and publish to PyPI"
        env:
          TWINE_USERNAME: __token__
          TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }}
        run: |
          python3 setup.py sdist bdist_wheel
          python3 -m twine upload dist/*

================================================
FILE: .github/workflows/ci.yml
================================================
name: integration

on: push

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Installing dependencies
        run: pip install flake8 setuptools pytest

      - name: Linter
        run: flake8 src/fuzzingtool --extend-ignore=E501,E731 --per-file-ignores="__init__.py:F401,F403,W292" --statistics

      - name: Package
        run: |
          python3 setup.py sdist
          cd dist
          pip3 install *

      - name: Test
        run: python3 -m pytest


================================================
FILE: .github/workflows/quality.yml
================================================
name: code quality

on:
  push:
    branches:
      - master
  pull_request:
    branches:
      - develop
      - master
  workflow_dispatch:

jobs:
  sonarcloud:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
        with:
          # Disabling shallow clone is recommended for improving relevancy of reporting
          fetch-depth: 0
      - name: Installing Dependencies
        run: pip install setuptools pytest pytest-cov

      - name: Build
        run: |
          python3 setup.py sdist
          cd dist
          pip3 install *

      - name: Generate Coverage
        run: |
          pytest --cov=src/fuzzingtool --cov-report=xml

      - name: Fix Code Coverage Path
        run: |
          sed -i 's/\/home\/runner\/work\/FuzzingTool\/FuzzingTool\//\/github\/workspace\//g' coverage.xml

      - name: SonarCloud Scan
        uses: sonarsource/sonarcloud-github-action@master
        env:
          GITHUB_TOKEN: ${{ secrets.TOKEN_GITHUB }}
          SONAR_TOKEN: ${{ secrets.SONARCLOUD_TOKEN }}
        with:
          args: >
            -Dsonar.organization=nescau-ufla
            -Dsonar.projectKey=NESCAU-UFLA_FuzzingTool
            -Dsonar.python.version=3
            -Dsonar.python.coverage.reportPaths=coverage.xml
            -Dsonar.sources=src/fuzzingtool/
            -Dsonar.tests=tests/

================================================
FILE: .github/workflows/sast.yml
================================================
name: sast

on: push

jobs:
  bandit:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@master
      - name: Installing bandit
        run: pip install bandit

      - name: Running bandit (1st round)
        run: python3 -m bandit -r src/fuzzingtool
        continue-on-error: true
      
      - name: Running bandit (2nd round)
        run: python3 -m bandit -ll -r src/fuzzingtool


================================================
FILE: .github/workflows/sca.yml
================================================
name: sca

on: push

jobs:
  snyk:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@master
      - name: Run Snyk to check for vulnerabilities
        uses: snyk/actions/python-3.8@master
        env:
          SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}


================================================
FILE: .gitignore
================================================
# Pycache
__pycache__/

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

# VSCode
.vscode

# Coverage
.coverage
coverage.xml

# Tests
.pytest_cache

================================================
FILE: CONTRIBUTORS.md
================================================
## Contributors
 * <a target="_blank" href="https://www.linkedin.com/in/gmprestes/"><b>Gabriel Prestes</b></a>: Designed the logo


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

Copyright (c) 2020 - present Vitor Oriel

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
================================================
<p align="center">
 <img src="https://user-images.githubusercontent.com/43549176/110254984-525fb200-7f70-11eb-84f0-9afdcab9725a.png" height="200" /><br/>
 <a href="https://github.com/NESCAU-UFLA/FuzzingTool/releases/latest">
  <img src="https://img.shields.io/github/release/NESCAU-UFLA/fuzzingtool.svg?&color=darkred" />
 </a>
 <img src="https://img.shields.io/static/v1?label=python&message=3.6%20|%203.7%20|%203.8%20|%203.9&color=informational&logo=python" />
 <img src="https://img.shields.io/static/v1?label=OS&message=GNU/Linux&color=orange&logo=linux" />
 <a href="https://pypi.org/project/FuzzingTool/">
  <img src="https://img.shields.io/pypi/dm/fuzzingtool.svg" />
 </a>
 <a href="https://github.com/NESCAU-UFLA/FuzzingTool/blob/master/LICENSE">
  <img src="https://img.shields.io/static/v1?label=license&message=MIT&color=brightgreen" />
 </a>
 <br/>
 <a href="https://sonarcloud.io/summary/new_code?id=NESCAU-UFLA_FuzzingTool">
  <img src="https://sonarcloud.io/api/project_badges/measure?project=NESCAU-UFLA_FuzzingTool&metric=alert_status" />
 </a>
 <a href="https://sonarcloud.io/summary/new_code?id=NESCAU-UFLA_FuzzingTool">
  <img src="https://sonarcloud.io/api/project_badges/measure?project=NESCAU-UFLA_FuzzingTool&metric=coverage" />
</a>
</p>

FuzzingTool is a web penetration testing tool, that handles with fuzzing. After the test is completed, all possible vulnerable entries (and the response data) are saved on a report file.
<br/>

## Disclaimer
We're not responsible for the misuse of this tool. This project was created for educational purposes and should not be used in environments without legal authorization.

## Screenshot
![screenshot](https://user-images.githubusercontent.com/43549176/166966746-b4e8f130-eeb7-4ba4-a7b0-b385a81bb16e.png)

## Getting Started
Before we start the *penetration testings*, take a look at the **installing** and **prerequisites**.

### Installing from Pypi
FuzzingTool is now on Pypi! You can install with:
```
$ pip install FuzzingTool
```

### Installing from source
If you want to install it manually, download the last release or clone this repository, and also follow the next prerequisites.

#### Prerequisites
 * Go to the project source folder, and run:
 ```
 $ pip install -r requirements.txt
 ```

### User's Manual
Reach out the user's manual (command list and usage examples) on our [wiki page](https://github.com/NESCAU-UFLA/FuzzingTool/wiki).

## Versioning
We use [SemVer](https://semver.org/) for versioning. For the versions available, see the [tags on this repository](https://github.com/NESCAU-UFLA/FuzzingTool/releases).

## Authors
 * **Vitor Oriel**
   * [GitHub](https://github.com/VitorOriel)
   * [Linkedin](https://www.linkedin.com/in/vitor-oriel-borges)
   * Email: vitorwixmix@gmail.com

## Contributing
If you want to contribute to FuzzingTool project, please read [CONTRIBUTING.md](https://github.com/NESCAU-UFLA/FuzzingTool/blob/master/.github/CONTRIBUTING.md).

## License
This project is licensed under the MIT License - see the [LICENSE](https://github.com/NESCAU-UFLA/FuzzingTool/blob/master/LICENSE) for details.


================================================
FILE: requirements.txt
================================================
#
# This file is autogenerated by pip-compile
# To update, run:
#
#    pip-compile --output-file=requirements.txt setup.py
#
beautifulsoup4>=4.9.3
    # via FuzzingTool (setup.py)
certifi>=2020.12.5
    # via requests
chardet>=4.0.0
    # via requests
dnspython>=2.1.0
    # via FuzzingTool (setup.py)
idna>=2.10
    # via requests
requests>=2.25.1
    # via FuzzingTool (setup.py)
soupsieve>=2.2.1
    # via beautifulsoup4
urllib3>=1.26.5
    # via requests
python-Wappalyzer>=0.3.1
    # via FuzzingTool (setup.py)


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

from src.fuzzingtool import __version__


def read(fname):
    return open(os.path.join(os.path.dirname(__file__), fname)).read()


install_requires = [
    'requests>=2.25.1',
    'beautifulsoup4>=4.9.3',
    'dnspython>=2.1.0',
    'python-Wappalyzer>=0.3.1',
]

dev_requires = [
    'pytest',
    'pytest-cov',
]

setup(
    name="FuzzingTool",
    version=__version__,
    author="Vitor Oriel C N Borges",
    author_email="vitorwixmix@gmail.com",
    description=("Software for fuzzing, used on web application pentestings."),
    long_description=read('./README.md'),
    long_description_content_type='text/markdown',
    license="MIT",
    keywords="pentesting-tools python3 fuzzing web-security",
    url="https://github.com/NESCAU-UFLA/FuzzingTool/",
    packages=find_packages(where='src'),
    package_dir={'fuzzingtool': 'src/fuzzingtool'},
    entry_points={
        'console_scripts': [
            'fuzzingtool = fuzzingtool.fuzzingtool:main_cli'
        ]
    },
    install_requires=install_requires,
    extras_require={
        'dev': dev_requires
    },
    python_requires=">=3.6",
    classifiers=[
        "Development Status :: 4 - Beta",
        "Natural Language :: English",
        "License :: OSI Approved :: MIT License",
        "Operating System :: POSIX :: Linux",
        "Programming Language :: Python :: 3.6",
        "Programming Language :: Python :: 3.7",
        "Programming Language :: Python :: 3.8",
        "Programming Language :: Python :: 3.9",
    ],
)


================================================
FILE: src/fuzzingtool/__init__.py
================================================
# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>
#
# 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.

APP_VERSION = {
    'MAJOR_VERSION': 3,
    "MINOR_VERSION": 14,
    "PATCH": 0
}


__name__ = "FuzzingTool"
__version__ = '.'.join([str(value) for value in APP_VERSION.values()])
__author__ = "Vitor Oriel C N Borges"
__license__ = "MIT"
__copyright__ = "Copyright 2020 - present Vitor Oriel"


================================================
FILE: src/fuzzingtool/api.py
================================================
# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>
#
# 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.

from .fuzz_lib import FuzzLib
from .interfaces.cli.cli_arguments import CliArguments


def fuzz(**kwargs) -> None:
    FuzzLib(**kwargs).main()


def fuzz_cli(args: str, **kwargs) -> None:
    args = ['fuzzingtool'] + args.split(' ')
    args = vars(CliArguments(args).get_arguments())
    args.update(kwargs)
    FuzzLib(**args).main()


================================================
FILE: src/fuzzingtool/conn/__init__.py
================================================
# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>
#
# 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.

from .requesters import *
from .request_parser import *

================================================
FILE: src/fuzzingtool/conn/request_parser.py
================================================
# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>
#
# 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.

from typing import Dict
from ..objects.fuzz_word import FuzzWord
from ..utils.consts import FUZZING_MARK


def check_is_subdomain_fuzzing(url: str) -> bool:
    """Checks if the fuzzing tests will occur on subdomain

    @type url: str
    @param url: The target URL
    @returns bool: The subdomain fuzzing flag
    """
    return (('.' in url and FUZZING_MARK in url)
            and url.index(FUZZING_MARK) < url.index('.'))


def check_is_url_discovery(url: FuzzWord) -> bool:
    """Checks if the fuzzing type is url fuzzing for discovery

    @type url: FuzzWord
    @param url: The target URL object
    @returns bool: The url discovery fuzzing flag
    """
    return (url.has_fuzzing and '?' not in url.word)


def check_is_data_fuzzing(
    url_params: Dict[FuzzWord, FuzzWord],
    body: Dict[FuzzWord, FuzzWord],
    header: Dict[str, FuzzWord]
) -> bool:
    """Checks if the fuzzing type is DataFuzzing

    @type url_params: Dict[FuzzWord, FuzzWord]
    @param url_params: The target URL parameters
    @type body: Dict[FuzzWord, FuzzWord]
    @param body: The target body data
    @type header: Dict[str, FuzzWord]
    @param header: The target HTTP header
    @returns bool: The data fuzzing flag
    """
    for key, value in url_params.items():
        if key.has_fuzzing or value.has_fuzzing:
            return True
    for key, value in body.items():
        if key.has_fuzzing or value.has_fuzzing:
            return True
    for value in header.values():
        if value.has_fuzzing:
            return True
    return False


class RequestParser:
    """Class that handle with request arguments parsing

    Attributes:
        payload: The payload used in the request
    """
    def __init__(self):
        self.__payload = ''

    def get_method(self, method: FuzzWord) -> str:
        """The new method getter

        @type method: dict
        @param method: The method dictionary
        @returns str: The new target method
        """
        return method.get_payloaded_word(self.__payload)

    def get_url(self, url: FuzzWord) -> str:
        """The new url getter

        @type url: dict
        @param url: The URL dictionary
        @returns str: The new target URL
        """
        return url.get_payloaded_word(self.__payload)

    def get_header(self, header: dict) -> dict:
        """The new HTTP Header getter

        @type httpHeder: dict
        @param header: The HTTP Header
        @returns dict: The new HTTP Header
        """
        return {key: value.get_payloaded_word(self.__payload)
                for key, value in header.items()}

    def get_data(self, data: Dict[FuzzWord, FuzzWord]) -> dict:
        """The new data getter

        @type data: Dict[FuzzWord, FuzzWord]
        @param data: The request data dict
        @returns dict: The new request data dict
        """
        if not data:
            return {}
        return {
            key.get_payloaded_word(self.__payload): value.get_payloaded_word(self.__payload)
            for key, value in data.items()
        }

    def set_payload(self, payload: str) -> None:
        """The payload setter

        @type payload: str
        @param payload: The payload used in the request
        """
        self.__payload = payload


request_parser = RequestParser()


================================================
FILE: src/fuzzingtool/conn/requesters/__init__.py
================================================
# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>
#
# 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.

from .requester import Requester
from .subdomain_requester import SubdomainRequester

================================================
FILE: src/fuzzingtool/conn/requesters/requester.py
================================================
# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>
#
# 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.

from threading import Lock
import random
import time
from typing import List, Dict, Tuple

import requests
import urllib3.exceptions

from ..request_parser import (check_is_url_discovery,
                              check_is_data_fuzzing, request_parser)
from ...utils.consts import FuzzType
from ...utils.http_utils import get_parsed_url, get_pure_url, get_url_without_scheme
from ...objects.fuzz_word import FuzzWord
from ...exceptions.request_exceptions import RequestException


class Requester:
    """Class that handle with the requests

    Attributes:
        url: The target URL
        method: The request method
        body: The body data of the request
        headers: The HTTP header
        proxy: The proxy used in the request
        proxies: The list with valid proxies gived by a file
        timeout: The request timeout before raise a TimeoutException
        follow_redirects: The follow redirections flag
        methods: The methods list to be used on fuzzing
        lock: The threads locker to set up the payload on the fuzzing entries
    """
    def __init__(self,
                 url: str,
                 method: str = 'GET',
                 body: str = None,
                 headers: Dict[str, str] = None,
                 follow_redirects: bool = True,
                 proxy: str = None,
                 proxies: List[str] = None,
                 timeout: int = 0,
                 cookie: str = None,
                 is_session: bool = False,
                 replay_proxy: str = None):
        """Class constructor

        @type url: str
        @param url: The target URL
        @type method: str
        @param method: The request http verb (method)
        @type methods: list
        @param methods: The request methods list
        @type body: str
        @param body: The body data of the request
        @type headers: dict
        @param headers: The HTTP header of the request
        @type follow_redirects: bool
        @param follow_redirects: The follow redirects flag
        @type proxy: str
        @param proxy: The proxy used in the request
        @type proxies: list
        @param proxies: The list with the proxies used in the requests
        @type timeout: int
        @param timeout: The request timeout
        @type cookie: str
        @param cookie: The cookie HTTP header value
        @type is_session: bool
        @param is_session: The flag to say if the requests will be made as session request
        @type replay_proxy: str
        @param replay_proxy: The proxy for replay request on matched responses
        """
        self._url, url_params = self.__setup_url(url)
        self.__url_params = self.__build_data_dict(url_params)
        self.__method = FuzzWord(method)
        self.__body = self.__build_data_dict(body)
        self.__header = self.__setup_header(headers)
        self.__proxy = self.__setup_proxy(proxy) if proxy else {}
        self.__proxies = ([self.__setup_proxy(proxy) for proxy in proxies]
                          if proxies else [])
        self.__follow_redirects = follow_redirects
        self.__fuzzing_type = self._set_fuzzing_type()
        if not timeout:
            if self.is_url_discovery():
                timeout = 10
            else:
                timeout = None
        self.__timeout = timeout
        if is_session or self.is_path_fuzzing():
            self.__session = requests.Session()
            self._request = self.__session_request
        if cookie:
            self.__header['Cookie'] = FuzzWord(cookie)
        self.__replay_proxy = self.__setup_proxy(replay_proxy) if replay_proxy else {}
        self._lock = Lock()

    def get_url(self) -> str:
        """The url content getter

        @returns str: The target URL
        """
        return self._url.word

    def get_method(self) -> str:
        """The request method content getter

        @returns str: The request method
        """
        return self.__method.word

    def is_method_fuzzing(self) -> bool:
        """The method fuzzing flag getter

        @returns bool: The method fuzzing flag
        """
        return self.__fuzzing_type == FuzzType.HTTP_METHOD_FUZZING

    def is_data_fuzzing(self) -> bool:
        """The data fuzzing flag getter

        @returns bool: The data fuzzing flag
        """
        return self.__fuzzing_type == FuzzType.DATA_FUZZING

    def is_url_discovery(self) -> bool:
        """Checks if the fuzzing is for url discovery (path or subdomain)

        @returns bool: A flag to say if is url discovery fuzzing type
        """
        return self.__fuzzing_type == FuzzType.PATH_FUZZING or self.__fuzzing_type == FuzzType.SUBDOMAIN_FUZZING

    def is_path_fuzzing(self) -> bool:
        """Checks if the fuzzing will be path discovery

        @returns bool: A flag to say if is path fuzzing
        """
        return self.__fuzzing_type == FuzzType.PATH_FUZZING

    def get_fuzzing_type(self) -> int:
        """The fuzzing type getter

        @returns int: The fuzzing type
        """
        return self.__fuzzing_type

    def set_method(self, method: str) -> None:
        """The request method setter

        @type method: str
        @param method: The request method
        """
        self.__method = FuzzWord(method)

    def set_body(self, body: str) -> None:
        """The body data setter

        @type body: str
        @param body: The body data of the request
        """
        self.__body = self.__build_data_dict(body)

    def test_connection(self) -> None:
        """Test the connection with the target, and raise an exception if couldn't connect"""
        try:
            url = get_pure_url(self.get_url())
            requests.get(
                url,
                proxies=self.__proxy,
                headers=request_parser.get_header(self.__header),
                timeout=(self.__timeout
                         if self.__timeout
                         else 10)  # Default 10 seconds to make a request
            )
        except requests.exceptions.ProxyError:
            raise RequestException("Can't connect to the proxy")
        except requests.exceptions.SSLError:
            raise RequestException(f"SSL couldn't be validated on {url}")
        except requests.exceptions.Timeout:
            raise RequestException(f"Connection to {url} timed out")
        except requests.exceptions.InvalidHeader as e:
            e = str(e)
            invalid_header = e[e.rindex(': ')+2:]
            raise RequestException(f"Invalid header {invalid_header}")
        except (
            requests.exceptions.ConnectionError,
            requests.exceptions.RequestException
        ):
            raise RequestException(f"Failed to establish a connection to {url}")

    def request(self,
                payload: str = '',
                replay_proxy: bool = False) -> Tuple[requests.Response, float]:
        """Make a request and get the response

        @type payload: str
        @param payload: The payload used in the request
        @type replay_proxy: bool
        @param replay_proxy: The replay proxy flag
        @returns Tuple[Response, float]: The response object of the request
        """
        if not replay_proxy:
            proxy = self.__proxy
            if self.__proxies:
                proxy = random.choice(self.__proxies)
        else:
            proxy = self.__replay_proxy
        method, url, body, url_params, headers = self.__get_request_parameters(payload)
        try:
            before = time.time()
            response = self._request(method, url, body, url_params, headers, proxy)
            rtt = (time.time() - before)
        except requests.exceptions.ProxyError:
            raise RequestException(f"Can't connect to the proxy {get_url_without_scheme(proxy['http'])}")
        except requests.exceptions.TooManyRedirects:
            raise RequestException(f"Too many redirects on {url}")
        except requests.exceptions.SSLError:
            raise RequestException(f"SSL couldn't be validated on {url}")
        except requests.exceptions.Timeout:
            raise RequestException(f"Connection to {url} timed out")
        except requests.exceptions.InvalidHeader as e:
            e = str(e)
            invalid_header = e[e.rindex(': ')+2:]
            raise RequestException(f"Invalid header {invalid_header}: {headers[invalid_header]}")
        except (
            requests.exceptions.ConnectionError,
            requests.exceptions.RequestException
        ):
            raise RequestException(f"Failed to establish a connection to {url}")
        except (
            UnicodeError,
            urllib3.exceptions.LocationParseError
        ):
            raise RequestException(f"Invalid hostname {get_parsed_url(url).hostname} for HTTP request")
        except ValueError as e:
            raise RequestException(str(e))
        else:
            return (response, rtt)

    def _request(self,
                 method: str,
                 url: str,
                 body: dict,
                 url_params: dict,
                 headers: dict,
                 proxy: dict) -> requests.Response:
        """Performs a request to the target

        @type method: str
        @param method: The request method
        @type url: str
        @param url: The target URL
        @type body: dict
        @param body: The body data to be send with the request
        @type url_params: dict
        @param url_params: The URL params to be send with the request
        @type headers: dict
        @param headers: The http header of the request
        @type proxy: str
        @param proxy: The proxy used in the request
        @returns Response: The response object of the request
        """
        return requests.request(
            method,
            url,
            data=body,
            params=url_params,
            headers=headers,
            proxies=proxy,
            timeout=self.__timeout,
            allow_redirects=self.__follow_redirects,
        )

    def _set_fuzzing_type(self) -> int:
        """Sets the fuzzing type

        @returns int: The fuzzing type int value
        """
        if self.__method.has_fuzzing:
            return FuzzType.HTTP_METHOD_FUZZING
        if check_is_url_discovery(self._url):
            return FuzzType.PATH_FUZZING
        if check_is_data_fuzzing(self.__url_params, self.__body, self.__header):
            return FuzzType.DATA_FUZZING
        return FuzzType.UNKNOWN_FUZZING

    def __setup_url(self, url: str) -> Tuple[FuzzWord, str]:
        """The URL setup

        @returns Tuple[FuzzWord, str]: The target URL dictionary and URL params
        """
        if '://' not in url:
            # No schema was defined, default protocol http
            url = f'http://{url}'
        if '/' not in get_url_without_scheme(url):
            # Insert a base path if wasn't specified
            url += '/'
        if '?' in url:
            url, params = url.split('?', 1)
        else:
            params = ''
        return (FuzzWord(url), params)

    def __build_data_dict(self, data: str) -> Dict[FuzzWord, FuzzWord]:
        """Build the data string into a data dict

        @type datat: str
        @param datat: The data to be used in the request
        @returns Dict[FuzzWord, FuzzWord]: The data dictionary
        """
        data_dict = {}
        if data:
            for variable in data.split('&'):
                if '=' in variable:
                    key, value = variable.split('=')
                    data_dict[FuzzWord(key)] = FuzzWord(value)
                else:
                    data_dict[FuzzWord(variable)] = FuzzWord()
        return data_dict

    def __setup_header(self, header: dict) -> dict:
        """Setup the HTTP Header

        @type header: dict
        @param header: The HTTP header dictionary
        @returns dict: The HTTP header dictionary
        """
        request_header = {}
        if not header:
            request_header['User-Agent'] = FuzzWord('FuzzingTool Requester Agent')
        else:
            for key, value in header.items():
                request_header[key] = FuzzWord(value)
            if 'Content-Length' in request_header.keys():
                del request_header['Content-Length']
        request_header['Accept-Encoding'] = FuzzWord('gzip, deflate')
        return request_header

    def __setup_proxy(self, proxy: str) -> Dict[str, str]:
        """Setup the proxy

        @type proxy: str
        @param proxy: The proxy used in the request
        @returns Dict[str, str]: The proxy dictionary
        """
        return {
            'http': f"http://{proxy}",
            'https': f"https://{proxy}",
        }

    def __get_request_parameters(self, payload: str) -> Tuple[
        str, str, dict, dict, dict
    ]:
        """Get the request parameters using in the request fields

        @type payload: str
        @param payload: The payload used in the request
        @returns tuple(str, str, dict, dict, dict): The parameters of the request
        """
        with self._lock:
            request_parser.set_payload(payload)
            return (
                request_parser.get_method(self.__method),
                request_parser.get_url(self._url),
                request_parser.get_data(self.__body),
                request_parser.get_data(self.__url_params),
                request_parser.get_header(self.__header),
            )

    def __session_request(self,
                          method: str,
                          url: str,
                          body: dict,
                          url_params: dict,
                          headers: dict,
                          proxy: dict) -> requests.Response:
        """Performs a request to the target using Session object

        @type method: str
        @param method: The request method
        @type url: str
        @param url: The target URL
        @type body: dict
        @param body: The body data to be send with the request
        @type url_params: dict
        @param url_params: The URL params to be send with the request
        @type headers: dict
        @param headers: The http header of the request
        @type proxy: str
        @param proxy: The proxy used in the request
        @returns Response: The response object of the request
        """
        return self.__session.send(
            self.__session.prepare_request(requests.Request(
                method,
                url,
                data=body,
                params=url_params,
                headers=headers,
            )),
            proxies=proxy,
            timeout=self.__timeout,
            allow_redirects=self.__follow_redirects,
        )


================================================
FILE: src/fuzzingtool/conn/requesters/subdomain_requester.py
================================================
# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>
#
# 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.

import socket
from typing import Tuple, Dict

from requests import Response

from .requester import Requester
from ..request_parser import request_parser
from ...utils.http_utils import get_parsed_url
from ...utils.consts import FuzzType
from ...exceptions.request_exceptions import InvalidHostname


class SubdomainRequester(Requester):
    """Class that handle with the requests for subdomain fuzzing"""
    def resolve_hostname(self, hostname: str) -> str:
        """Resolve the ip for the given hostname

        @type hostname: str
        @param hostname: The hostname of the target
        @returns str: The target IP
        """
        try:
            return socket.gethostbyname(hostname)
        except socket.gaierror:
            raise InvalidHostname(f"Can't resolve hostname {hostname}")

    def request(self,
                payload: str = '',
                replay_proxy: bool = False) -> Tuple[Response, float, Dict[str, str]]:
        with self._lock:
            request_parser.set_payload(payload)
            host = get_parsed_url(request_parser.get_url(self._url)).hostname
        ip = self.resolve_hostname(host)
        return (*(super().request(payload, replay_proxy)), ip)

    def _set_fuzzing_type(self) -> int:
        return FuzzType.SUBDOMAIN_FUZZING


================================================
FILE: src/fuzzingtool/core/__init__.py
================================================
# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>
#
# 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.

from .bases import *
from .defaults import *
from .blacklist_status import BlacklistStatus
from .dictionary import Dictionary
from .filter import Filter
from .fuzzer import Fuzzer
from .job_manager import JobManager
from .matcher import Matcher
from .payloader import Payloader
from .recursion_manager import RecursionManager
from .summary import Summary


================================================
FILE: src/fuzzingtool/core/bases/__init__.py
================================================
# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>
#
# 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.

from .base_encoder import BaseEncoder
from .base_scanner import BaseScanner
from .base_wordlist import BaseWordlist


================================================
FILE: src/fuzzingtool/core/bases/base_encoder.py
================================================
# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>
#
# 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.

from abc import ABC, abstractmethod


class BaseEncoder(ABC):
    charset = 'utf-8'

    def __str__(self) -> str:
        return type(self).__name__

    @abstractmethod
    def encode(self, payload: str) -> str:
        """Encode a payload into an specific encoding type

        @type payload: str
        @param payload: The payload used in the request
        @returns str: The encoded payload
        """
        pass


================================================
FILE: src/fuzzingtool/core/bases/base_observer.py
================================================
# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>
#
# 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.

from abc import ABC, abstractmethod

from ...objects.result import Result


class BaseObserver(ABC):
    """Base class for the observers"""
    @abstractmethod
    def update(self, subject_name: str, result: Result) -> None:
        """Update the Observer stats

        @type subject_name: str
        @param subject_name: The provider name
        @type result: Result
        @param result: The FuzzingTool result object
        """
        pass


================================================
FILE: src/fuzzingtool/core/bases/base_plugin.py
================================================
# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>
#
# 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.

from abc import ABC


class Plugin(ABC):
    """Class to represent a plugin in the app"""
    pass


================================================
FILE: src/fuzzingtool/core/bases/base_scanner.py
================================================
# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>
#
# 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.

from abc import abstractmethod
from queue import Queue

from .job_provider import JobProvider
from ...objects import Payload, Result, ScannerResult


class BaseScanner(JobProvider):
    """Base scanner (ABC)

    Attributes:
        payloads_queue: The payload queue for new requests
    """
    def __init__(self):
        self.payloads_queue = Queue()
        super().__init__()

    def __str__(self) -> str:
        return type(self).__name__

    def notify(self, result: Result) -> None:
        """Notify the observer with the new job

        @type result: Result
        @param result: The FuzzingTool result object
        """
        self._observer.update(str(self), result)

    @abstractmethod
    def scan(self, result: Result) -> bool:
        """Scan the FuzzingTool result

        @type result: Result
        @param result: The result object
        @reeturns bool: A match flag
        """
        pass

    def process(self, result: Result) -> None:
        """Process the FuzzingTool result from this base scanner.
           Do not override this function. If you need so, override _process method instead

        @type result: Result
        @param result: The result object
        """
        scanner_name = str(self)
        result.scanners_res[scanner_name] = ScannerResult(scanner_name)
        self._process(result)

    def get_self_res(self, result: Result) -> ScannerResult:
        """Get the self Scanner result

        @type result: Result
        @param result: The FuzzingTool result object
        @returns ScannerResult: The self scanner result object
        """
        return result.scanners_res[str(self)]

    def enqueue_payload(self, result: Result, payload: str) -> None:
        """Enqueue a payload into the payload queue for the next job

        @type result: Result
        @param result: The result of the payload
        @type payload: str
        @param payload: The payload that'll be enqueued
        """
        was_empty = self.payloads_queue.empty()
        self.payloads_queue.put(Payload().update(result._payload).with_recursion(payload))
        self.get_self_res(result).enqueued_payloads += 1
        if was_empty:
            self.notify(result)

    def _process(self, result: Result) -> None:
        """Process the FuzzingTool result through child scanner if needed

        @type result: Result
        @param result: The result object
        """
        pass


================================================
FILE: src/fuzzingtool/core/bases/base_validator.py
================================================
# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>
#
# 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.

from abc import ABC
import re
from typing import Pattern

from ...exceptions import BadArgumentFormat


class BaseValidator(ABC):
    """Base validator class for both Matcher and Filter

    Attributes:
        regexer: The regex object
    """
    def __init__(self, regex: str):
        """Class constructor

        @type regex: str
        @param regex: The regular expression to be setted
        """
        self._regexer = None if not regex else self.__build_regexer(regex)

    def __build_regexer(self, regex: str) -> Pattern[str]:
        """Build the regexer object

        @type regex: str
        @param regex: The regular expression to be setted
        @returns Pattern[str]: The regex object
        """
        try:
            regexer = re.compile(regex, re.IGNORECASE)
        except re.error:
            raise BadArgumentFormat(f"Invalid regex format {regex} on {type(self).__name__}")
        return regexer


================================================
FILE: src/fuzzingtool/core/bases/base_wordlist.py
================================================
# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>
#
# 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.

from abc import ABC, abstractmethod
from typing import List


class BaseWordlist(ABC):
    """Base wordlist

    Attributes:
        wordlist: The list with the payloads
    """
    def __init__(self):
        self.__wordlist = []

    def __len__(self) -> int:
        return len(self.__wordlist)

    def get(self) -> List[str]:
        """The wordlist getter

        @returns List[str]: The list with the payloads
        """
        return self.__wordlist

    def build(self) -> None:
        """Builds the wordlist"""
        self.__wordlist = self._build()

    @abstractmethod
    def _build(self) -> List[str]:
        """The wordlist builder

        @returns List[str]: The builded wordlist
        """
        pass


================================================
FILE: src/fuzzingtool/core/bases/job_provider.py
================================================
# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>
#
# 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.

from abc import ABC, abstractmethod

from .base_observer import BaseObserver


class JobProvider(ABC):
    """Base class for the job providers

    Attributes:
        observer: The observer that'll look for this job provider
    """
    def __init__(self):
        self._observer = None

    def set_observer(self, observer: BaseObserver) -> None:
        """The observer setter

        @type observer: BaseObserver
        @param observer: The observer that'll look for this job provider
        """
        self._observer = observer

    @abstractmethod
    def notify(self) -> None:
        """Notify the observer for some action"""
        pass


================================================
FILE: src/fuzzingtool/core/blacklist_status.py
================================================
# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>
#
# 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.

from typing import List, Dict, Callable

from ..utils.utils import split_str_to_list
from ..exceptions import BadArgumentType, MissingParameter, InvalidArgument


class BlacklistStatus:
    """Blacklist status handler object

    Attributes:
        codes: The list with the blacklisted status codes
        action_callback: The callback function to trigger when detect a blacklisted status
    """
    def __init__(self,
                 status: str,
                 action: str,
                 action_param: str,
                 action_callbacks: Dict[str, Callable[[int], None]]):
        """Class constructor

        @type status: str
        @param status: The blacklist status codes in string format
        @type action: str
        @param action: The action taken when detects a status in blacklist
        @type action_param: str
        @param action_param: The parameter for the action, if it requires
        @type action_callbacks: Dict[str, Callable[[int], None]]
        @param action_callbacks: The action callbacks
        """
        self.codes = self.build_status_list(status)
        if action:
            self.do_action, self.action_param = self.set_action_callback(
                action, action_param, action_callbacks
            )

    def do_action(self, status: int) -> None:
        """Do an ction when a status code is detected

        @type status: int
        @param status: The status code of the response
        """
        pass

    def build_status_list(self, status: str) -> List[int]:
        """Build the blacklisted status codes

        @type status: str
        @param status: The blacklisted status codes
        @returns List[int]: The parsed blacklisted status codes
        """
        try:
            return [int(status) for status in split_str_to_list(status)]
        except ValueError:
            raise BadArgumentType("Status code must be an integer")

    def set_action_callback(self,
                            action: str,
                            action_param: str,
                            action_callbacks: str) -> Callable[[int], None]:
        """Get the action callback if a blacklisted status code is set

        @type action: str
        @param action: The action taken when detects a status in blacklist
        @type action_param: str
        @param action_param: The parameter for the action, if it requires
        @type action_callbacks: dict
        @param action_callbacks: The action callbacks
        @returns Callable[[int], None]: A callback function for the blacklisted status code
        """
        if action == 'stop':
            return (action_callbacks['stop'], None)
        if action == 'wait':
            if not action_param:
                raise MissingParameter("Must set a time to wait, in seconds")
            try:
                action_param = float(action_param)
            except ValueError:
                raise BadArgumentType("Time to wait must be a number")
            return (action_callbacks['wait'], action_param)
        raise InvalidArgument(f"Invalid type of blacklist action: {action}")


================================================
FILE: src/fuzzingtool/core/defaults/__init__.py
================================================
# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>
#
# 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.

from .encoders import *
from .scanners import *
from .wordlists import *

================================================
FILE: src/fuzzingtool/core/defaults/encoders/__init__.py
================================================
# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>
#
# 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.

from .chain_encoder import ChainEncoder

================================================
FILE: src/fuzzingtool/core/defaults/encoders/chain_encoder.py
================================================
# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>
#
# 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.

from typing import List

from ...bases.base_encoder import BaseEncoder


class ChainEncoder(BaseEncoder):
    """Class that handle with the chain encoders

    Attributes:
        encoders: The encoders list to be chained
    """
    def __init__(self, encoders: List[BaseEncoder]):
        """Class constructor

        @type encoders: List[BaseEncoder]
        @param encoders: The encoders list to be chained
        """
        self.__encoders = encoders
        self.__str_repr = '@'.join(str(encoder) for encoder in encoders)

    def __str__(self) -> str:
        return self.__str_repr

    def getEncoders(self) -> List[BaseEncoder]:
        """The encoders list getter

        @return List[BaseEncoder]: The encoders list
        """
        return self.__encoders

    def encode(self, payload: str) -> str:
        encoded = payload
        for encoder in self.__encoders:
            encoded = encoder.encode(encoded)
        return encoded


================================================
FILE: src/fuzzingtool/core/defaults/scanners/__init__.py
================================================
# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>
#
# 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.

from .data_scanner import DataScanner
from .path_scanner import PathScanner
from .subdomain_scanner import SubdomainScanner

================================================
FILE: src/fuzzingtool/core/defaults/scanners/data_scanner.py
================================================
# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>
#
# 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.

from ...bases.base_scanner import BaseScanner
from ....objects.result import Result


class DataScanner(BaseScanner):
    __author__ = ("Vitor Oriel",)

    def scan(self, result: Result) -> bool:
        return True

    def _process(self, result: Result) -> None:
        self.get_self_res(result).data['payload_length'] = len(result.payload)


================================================
FILE: src/fuzzingtool/core/defaults/scanners/path_scanner.py
================================================
# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>
#
# 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.

from ...bases.base_scanner import BaseScanner
from ....objects.result import Result


class PathScanner(BaseScanner):
    __author__ = ("Vitor Oriel",)

    def scan(self, result: Result) -> bool:
        return True

    def _process(self, result: Result) -> None:
        self.get_self_res(result).data['redirected'] = ''
        if result.history.status > 300 and result.history.status < 400:
            self.get_self_res(result).data['redirected'] = result.history.response.headers['Location']


================================================
FILE: src/fuzzingtool/core/defaults/scanners/subdomain_scanner.py
================================================
# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>
#
# 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.

from ...bases.base_scanner import BaseScanner
from ....objects.result import Result


class SubdomainScanner(BaseScanner):
    __author__ = ("Vitor Oriel",)

    def scan(self, result: Result) -> bool:
        return True


================================================
FILE: src/fuzzingtool/core/defaults/wordlists/__init__.py
================================================
# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>
#
# 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.

from .file_wordlist import FileWordlist
from .list_wordlist import ListWordlist

================================================
FILE: src/fuzzingtool/core/defaults/wordlists/file_wordlist.py
================================================
# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>
#
# 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.

from typing import List

from ...bases.base_wordlist import BaseWordlist
from ....utils.file_utils import read_file
from ....exceptions import BuildWordlistFails


class FileWordlist(BaseWordlist):
    __author__ = ("Vitor Oriel",)

    def __init__(self, file_path: str):
        self.file_path = file_path
        super().__init__()

    def _build(self) -> List[str]:
        try:
            return list(set(read_file(self.file_path)))
        except FileNotFoundError as e:
            raise BuildWordlistFails(str(e))


================================================
FILE: src/fuzzingtool/core/defaults/wordlists/list_wordlist.py
================================================
# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>
#
# 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.

from typing import List

from ...bases.base_wordlist import BaseWordlist
from ....utils.utils import split_str_to_list, check_range_list


class ListWordlist(BaseWordlist):
    __author__ = ("Vitor Oriel",)

    def __init__(self, payload_list: str):
        payload_list = payload_list[1:-1]
        self.payload_list = payload_list
        super().__init__()

    def _build(self) -> List[str]:
        builded_list = []
        for payload in split_str_to_list(self.payload_list):
            builded_list.extend(check_range_list(payload))
        return builded_list


================================================
FILE: src/fuzzingtool/core/dictionary.py
================================================
# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>
#
# 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.

from queue import Queue
from typing import List

from .payloader import Payloader
from ..objects.payload import Payload


class Dictionary:
    """Dictionary object handler

    Attributes:
        wordlist: The wordlist that contains the payloads backup
        size: The payload queue size
        payloads: The queue that contains all payloads inside the wordlist
    """
    def __init__(self, wordlist: list):
        """Class constructor

        @type wordlist: list
        @param wordlist: The wordlist with the payloads
        """
        self.wordlist = wordlist
        self.__size = 0
        self.__payloads = Queue()

    def __next__(self) -> List[Payload]:
        """Gets the next payload to be processed

        @returns list: The payloads used in the request
        """
        self.__size -= 1
        return Payloader.get_customized_payload(self.__payloads.get())

    def __len__(self) -> int:
        """Gets the wordlist length

        @returns int: The wordlist length
        """
        length_prefix = len(Payloader.prefix)
        if length_prefix == 0:
            length_prefix = 1
        length_suffix = len(Payloader.suffix)
        if length_suffix == 0:
            length_suffix = 1
        length_encoders = len(Payloader.encoder)
        if length_encoders == 0:
            length_encoders = 1
        return (self.__size
                * length_suffix
                * length_prefix
                * length_encoders)

    def is_empty(self) -> bool:
        """The payloads empty queue flag getter

        @returns bool: The payloads empty queue flag
        """
        return self.__payloads.empty()

    def reload(self) -> None:
        """Reloads the payloads queue with the wordlist content"""
        for payload in self.wordlist:
            self.__payloads.put(payload)
            self.__size += 1

    def fill_from_queue(self, payloads_queue: Queue, clear: bool = False) -> None:
        """Fill the payloads queue with another queue

        @type payloads_queue: Queue
        @param payloads_queue: The other payload quele that'll enqueue the payloads
        @type clear: bool
        @param clear: The flag to say if the payload queue needs to be cleared before
        """
        if clear:
            self.__payloads = Queue()
            self.__size = 0
        while not payloads_queue.empty():
            self.__payloads.put(payloads_queue.get())
            self.__size += 1


================================================
FILE: src/fuzzingtool/core/filter.py
================================================
# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>
#
# 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.

from typing import List

from .bases.base_validator import BaseValidator
from ..objects.result import Result
from ..exceptions import BadArgumentType


class Filter(BaseValidator):
    """Class responsible to filter the results by exclusion rules

    Attributes:
        status_codes: The list with excluded status codes
        regexer: The regex object to exclude by regex
    """
    def __init__(self, status_code: str = None, regex: str = None):
        """Class constructor

        @type status_code: str
        @param status_code: The status code string for filtering
        @type regex: str
        @param regex: The regular expression for filtering
        """
        self._status_codes = [] if not status_code else self.__build_status_codes(status_code)
        super().__init__(regex)

    def check(self, result: Result) -> bool:
        """Checks if the filter configs matches with the result attributes

        @type result: Result
        @param result: The FuzzingTool result object
        @returns bool: A filter flag
        """
        if result.history.status in self._status_codes:
            return False
        if (self._regexer is not None and
                self._regexer.search(result.history.response.text)):
            return False
        return True

    def __build_status_codes(self, status_code: str) -> List[int]:
        """Build the status codes list

        @type status_code: str
        @param status_code: The status code string
        @returns List[str]: The list with status codes as integers
        """
        try:
            status_codes = [int(status) for status in status_code.split(',')]
        except ValueError:
            raise BadArgumentType(
                f"The filter status argument ({status_code}) must be integer"
            )
        return status_codes


================================================
FILE: src/fuzzingtool/core/fuzzer.py
================================================
# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>
#
# 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.

from threading import Thread, Event
import time
from typing import Callable, Union, Any

from requests.models import Response

from .dictionary import Dictionary
from ..conn.requesters import Requester
from ..objects import Error, Payload
from ..exceptions import RequestException, InvalidHostname


class Fuzzer:
    """Fuzzer class, the core of the software

    Attributes:
        requester: The requester object to deal with the requests
        dict: The dictionary object to handle with the payloads
        delay: The delay between each test
        running: A flag to say if the application is running or not
    """
    def __init__(self,
                 requester: Requester,
                 dictionary: Dictionary,
                 delay: float,
                 number_of_threads: int,
                 response_callback: Callable[[dict, bool], None],
                 exception_callbacks: Callable[[Response, float, Payload, Union[Any, None]], None]):
        """Class constructor

        @type requester: Requester
        @param requester: The requester object to deal with the requests
        @type dict: Dictionary
        @param dict: The dicttionary object to deal with the payload dictionary
        @type delay: float
        @param delay: The delay between each request
        @type number_of_threads: int
        @param number_of_threads: The number of threads
                                  used in the fuzzing tests
        @type response_callback: Callable
        @param response_callback: The callback function for the results
        @type exception_callbacks: List[Callable]
        @param exception_callbacks: The list that handles
                                    with exception callbacks
        """
        self.__requester = requester
        self.__dict = dictionary
        self.__delay = delay
        self.__running = True
        self.response_callback = response_callback
        self.exception_callbacks = exception_callbacks
        self.setup_threads(number_of_threads)

    def setup_threads(self, number_of_threads: int) -> None:
        """Handle with threads setup

        @type number_of_threads: int
        @param number_of_threads: The number of threads
                                  used in the fuzzing tests

        Attributes:
            threads: The list with the threads used in the application
            running_threads: The running threads count
            paused_threads: The paused threads count
            join_timeout: The join timeout for the threads
            player: The player event object handler
        """
        self.__threads = [Thread(target=self.run, daemon=True) for _ in range(number_of_threads)]
        self.__running_threads = number_of_threads
        self.__paused_threads = 0
        self.__join_timeout = 0.001*float(number_of_threads)
        self.__player = Event()

    def is_running(self) -> bool:
        """The running flag getter

        @returns bool: The running flag
        """
        return self.__running

    def is_paused(self) -> bool:
        """The paused flag getter

        @returns bool: The paused flag
        """
        return not self.__player.isSet()

    def run(self) -> None:
        """Run the threads"""
        while not self.__dict.is_empty():
            for payload in next(self.__dict):
                try:
                    response, rtt, *ip = self.__requester.request(str(payload))
                    self.response_callback(response, rtt, payload, *ip)
                except InvalidHostname as e:
                    self.exception_callbacks[0](Error(e, payload))
                except RequestException as e:
                    self.exception_callbacks[1](Error(e, payload))
                finally:
                    time.sleep(self.__delay)
            if self.is_paused():
                self.__paused_threads += 1
                self.__player.wait()
        self.__running_threads -= 1

    def join(self) -> bool:
        """Join the threads

        @returns bool: A flag to say if the threads are running or not
        """
        for thread in self.__threads:
            thread.join(self.__join_timeout)
            if thread.is_alive():
                return True
        return False

    def start(self) -> None:
        """Starts the fuzzer application"""
        self.__player.set()
        for thread in self.__threads:
            thread.start()

    def pause(self) -> None:
        """Pause the fuzzer application"""
        self.__player.clear()

    def stop(self) -> None:
        """Stop the fuzzer application"""
        self.__running = False
        self.pause()
        self.wait_until_pause()

    def resume(self) -> None:
        """Resume the fuzzer application"""
        self.__paused_threads = 0
        self.__player.set()

    def wait_until_pause(self) -> None:
        """Blocks until all threads are paused"""
        while self.__paused_threads < self.__running_threads:
            """Wait until all threads are paused"""
            pass
        time.sleep(0.1)


================================================
FILE: src/fuzzingtool/core/job_manager.py
================================================
# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>
#
# 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.

from queue import Queue
from typing import Dict

from .bases.base_observer import BaseObserver
from .dictionary import Dictionary
from ..objects import Payload, Result


class JobManager(BaseObserver):
    """Class responsible to manage the jobs

    Attributes:
        current_job: The current job index
        current_job_name: The current job that's running
        pending_jobs: The pending jobs to run
        total_jobs: The total jobs that'll run
        total_requests: The total requests that'll be made on fuzzing
        dictionary: The payload dictionary
        job_providers: The job providers that enqueue new payloads for requests
        max_rlevel: The maximum jobs recursion level
    """
    def __init__(self,
                 dictionary: Dictionary,
                 job_providers: Dict[str, Queue],
                 max_rlevel: int):
        """Class constructor

        @type dictionary: Dictionary
        @param dictionary: The dictionary that'll be filled with payloads
        @type job_providers: Dict[str, Queue[Payload]]
        @param job_providers: The job providers, with name and queue
        """
        wordlist_queue = Queue()
        for payload in dictionary.wordlist:
            wordlist_queue.put(Payload(payload))
        self.current_job = 0
        self.current_job_name = None
        self.pending_jobs = Queue()
        self.pending_jobs.put(("wordlist", wordlist_queue))
        self.total_jobs = 1
        self.total_requests = 0
        self.dictionary = dictionary
        self.job_providers = job_providers
        self.max_rlevel = max_rlevel

    def update(self, provider: str, result: Result) -> None:
        """Update the total jobs count

        @type provider: str
        @param provider: The provider name
        @type result: Result
        @param result: The FuzzingTool result object
        """
        self.total_jobs += 1
        result.job_description = f"Enqueued new job from {provider}"

    def get_job(self) -> None:
        """Gets a new job to run"""
        self.current_job += 1
        self.current_job_name, job_queue = self.pending_jobs.get()
        self.dictionary.fill_from_queue(job_queue, clear=True)
        self.total_requests = len(self.dictionary)

    def has_pending_jobs(self) -> bool:
        """Checks if has pending jobs to run

        @returns bool: The flag to say if has pending jobs to run
        """
        return not self.pending_jobs.empty()

    def has_pending_jobs_from_providers(self) -> bool:
        """Checks if has pending jobs from providers

        @returns bool: The flag to say if has pending jobs from providers
        """
        for job_queue in self.job_providers.values():
            if not job_queue.empty():
                return True
        return False

    def check_for_new_jobs(self) -> None:
        """Check for new jobs from providers
           If has, fill the dictionary with the payloads and enqueue the job
        """
        for job_provider, job_queue in self.job_providers.items():
            new_job = Queue()
            while not job_queue.empty():
                payload: Payload = job_queue.get()
                if payload.rlevel <= self.max_rlevel:
                    new_job.put(payload)
            if not new_job.empty():
                self.pending_jobs.put((job_provider, new_job))


================================================
FILE: src/fuzzingtool/core/matcher.py
================================================
# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>
#
# 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.

from typing import List, Dict, Tuple, Callable, Union, Type
import operator

from .bases.base_validator import BaseValidator
from ..objects.result import Result
from ..utils.utils import split_str_to_list
from ..exceptions import BadArgumentType


def get_status_code(status: str,
                    status_list: List[int],
                    status_range: List[int]) -> None:
    """Get the allowed status code list and range

    @type status: str
    @param status: The status cod given in the terminal
    @type status_list: List[int]
    @param status_list: The allowed status codes list
    @type status_range: List[int]
    @param status_range: The range of allowed status codes
    """
    try:
        if '-' not in status:
            status_list.append(int(status))
        else:
            code_left, code_right = (int(code) for code in status.split('-', 1))
            if code_right < code_left:
                code_left, code_right = code_right, code_left
            status_range[:] = [code_left, code_right]
    except ValueError:
        raise BadArgumentType(
            f"The match status argument ({status}) must be integer"
        )


class Matcher(BaseValidator):
    """Class to handle with the match validations

    Attributes:
        comparator: The dictionary with the default
                    entries to be compared with the current request
        status_code: The dictionary with the
                     allowed status codes (and range)
    """
    def __init__(self,
                 status_code: str = None,
                 time: str = None,
                 size: str = None,
                 words: str = None,
                 lines: str = None,
                 regex: str = None):
        """Class constructor

        @type status_code: str
        @param status_code: The allowed status codes string
        @type time: str
        @param time: The time to be compared with the RTT
        @type size: str
        @param size: The size to be compared with the response body length
        @type words: str
        @param words: The number of words to be compared with the response body
        @type lines: str
        @param lines: The number of lines to be compared with the response body
        @type regex: str
        @param regex: The regular expression to be compared with the response body
        """
        self._status_code = self.__build_status_code(status_code)
        self._comparator = self.__build_comparator(time, size, words, lines)
        super().__init__(regex)

    def status_code_is_default(self) -> bool:
        """Check if the allowed status is set as default config

        @returns bool: If the allowed status is the default or not
        """
        return self._status_code['is_default']

    def comparator_is_set(self) -> bool:
        """Check if any of the comparators are seted

        @returns bool: if any of the comparators are seted
                       returns True, else False
        """
        for value in self._comparator.values():
            if value is not None:
                return True
        return False

    def set_status_code(self, status_code: str) -> None:
        """The allowed status setter

        @type status_code: str
        @param status_code: The allowed status
        """
        self._status_code = self.__build_status_code(status_code)

    def set_comparator(self,
                       time: str,
                       size: str,
                       words: str,
                       lines: str) -> None:
        """The comparator setter

        @type time: str
        @param time: The time to be compared with the RTT
        @type size: str
        @param size: The size to be compared with the response body length
        @type words: str
        @param words: The number of words to be compared with the response body
        @type lines: str
        @param lines: The number of lines to be compared with the response body
        """
        self._comparator = self.__build_comparator(time, size, words, lines)

    def match(self, result: Result) -> bool:
        """Check if the request content has some predefined characteristics
           based on a payload, it'll be considered as vulnerable

        @type result: Result
        @param result: The actual result object
        @returns bool: A match flag
        """
        if not self._match_status(result.history.status):
            return False
        if (self._comparator['time'] is not None and
                not self._match_time(result.history.rtt, self._comparator['time'])):
            return False
        if (self._comparator['size'] is not None and
                not self._match_size(int(result.history.body_size), self._comparator['size'])):
            return False
        if (self._comparator['words'] is not None and
                not self._match_words(result.words, self._comparator['words'])):
            return False
        if (self._comparator['lines'] is not None and
                not self._match_lines(result.lines, self._comparator['lines'])):
            return False
        if (self._regexer is not None and
                not self._regexer.search(result.history.response.text)):
            return False
        return True

    def _match_status(self, status: int) -> bool:
        """Check if the result status match with the allowed status dict

        @type status: int
        @param status: The result status code
        @returns bool: if match returns True else False
        """
        return (status in self._status_code['list']
                or (self._status_code['range']
                    and (self._status_code['range'][0] <= status
                         and status <= self._status_code['range'][1])))

    def _match_time(self, time: float, comparator_time: float) -> bool:
        """Check if the result time match with the comparator dict

        @type time: int
        @param time: The result time
        @type comparator_time: int
        @param comparator_time: The time comparator
        @returns bool: if match returns True else False
        """
        pass

    def _match_size(self, size: int, comparator_size: int) -> bool:
        """Check if the result size match with the comparator dict

        @type size: int
        @param size: The result size
        @type comparator_size: int
        @param comparator_size: The size comparator
        @returns bool: if match returns True else False
        """
        pass

    def _match_words(self, words: float, comparator_words: float) -> bool:
        """Check if the result words match with the comparator dict

        @type words: int
        @param words: The result words
        @type comparator_words: int
        @param comparator_words: The words comparator
        @returns bool: if match returns True else False
        """
        pass

    def _match_lines(self, lines: float, comparator_lines: float) -> bool:
        """Check if the result lines match with the comparator dict

        @type lines: int
        @param lines: The result lines
        @type comparator_lines: int
        @param comparator_lines: The lines comparator
        @returns bool: if match returns True else False
        """
        pass

    def __build_status_code(self, status_code: str) -> dict:
        """Build the matcher attribute for allowed status

        @type status_code: str
        @param status_code: The allowed status codes to match results
        @returns dict: The allowed status code,
                       list and range, parsed into a dict
        """
        if not status_code:
            is_default = True
            allowed_list = [200]
        else:
            is_default = False
            allowed_list = []
        allowed_range = []
        for status in split_str_to_list(status_code):
            get_status_code(status, allowed_list, allowed_range)
        return {
            'is_default': is_default,
            'list': allowed_list,
            'range': allowed_range,
        }

    def __get_comparator_and_callback(self,
                                      comparator: str) -> Tuple[str, Callable]:
        """Gets the comparator and callback

        @type comparator: str
        @param comparator: The value to be compared
        @returns Tuple[str, Callable]: The comparator and match callback
        """
        def set_match(
            match: Dict[str, Callable], comparator: str
        ) -> Tuple[Callable, str]:
            """Set the match function and new comparator value

            @type match: Dict[str, Callable]
            @param match: The dictionary with available comparations
            @type comparator: str
            @param comparator: The value to be compared
            @returns Tuple[Callable, str]: The callback match function,
                                           and the new comparator value
            """
            comparator = str(comparator)
            for key, value in match.items():
                if key in comparator:
                    return (value, comparator.split(key, 1)[1])
            raise IndexError

        match_dict = {
            '>=': operator.ge,
            '<=': operator.le,
            '>': operator.gt,
            '<': operator.lt,
            '==': operator.eq,
            '!=': operator.ne,
        }
        try:
            match_callback, comparator = set_match(match_dict, comparator)
        except IndexError:
            match_callback = operator.gt
        return (comparator, match_callback)

    def __instance_comparator(
        self,
        cast_type: Union[Type[int], Type[float]],
        key: str,
        value: str
    ) -> Tuple[Union[int, float], Callable[[Union[int, float]], bool]]:
        """Instance the comparator value and callback

        @type cast_type: Union[Type[int], Type[float]]
        @param cast_type: The expected type of the value
        @type key: str
        @param key: The name of the comparator
        @type value: str
        @param value: The value of the comparator
        @returns tuple: The tuple with comparator value and callback
        """
        value_to_compare, comparator_callback = self.__get_comparator_and_callback(value)
        try:
            value_to_compare = cast_type(value_to_compare)
        except ValueError:
            if cast_type is int:
                raise BadArgumentType(
                    f"The {key} comparator must be an integer, not '{value_to_compare}'!"
                )
            raise BadArgumentType(
                f"The {key} comparator must be a number, not '{value_to_compare}'!"
            )
        return (value_to_compare, comparator_callback)

    def __build_comparator(self,
                           time: str,
                           size: str,
                           words: str,
                           lines: str) -> dict:
        """The comparator setter

        @type time: str
        @param time: The time to be compared with the RTT
        @type size: str
        @param size: The size to be compared with response body
        @type words: str
        @param words: The number of words to be compared with response body
        @type lines: str
        @param lines: The number of lines to be compared with responde body
        @returns dict: The data comparator
        """
        comparator = {
            'time': None,
            'size': None,
            'words': None,
            'lines': None,
        }
        if time:
            comparator['time'], self._match_time = self.__instance_comparator(
                float, 'time', time
            )
        if size:
            comparator['size'], self._match_size = self.__instance_comparator(
                int, 'size', size
            )
        if words:
            comparator['words'], self._match_words = self.__instance_comparator(
                int, 'words', words
            )
        if lines:
            comparator['lines'], self._match_lines = self.__instance_comparator(
                int, 'lines', lines
            )
        return comparator


================================================
FILE: src/fuzzingtool/core/payloader.py
================================================
# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>
#
# 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.

import re
from typing import List, Tuple

from .bases.base_encoder import BaseEncoder
from .defaults.encoders import ChainEncoder
from ..objects.payload import Payload
from ..exceptions import BadArgumentFormat


class EncodeManager:
    """Class that handle with the encoder management

    Attributes:
        encoders: The encoders used in the program
        regexer: The object to handle with the encoding based on a regex
    """
    def __init__(self):
        self.encoders = []
        self.regexer = None

    def __len__(self) -> int:
        return len(self.encoders)

    def encode(self, ajusted_payloads: List[Payload]) -> List[Payload]:
        """The encode callback for the payloads

        @type ajusted_payloads: List[Payload]
        @param ajusted_payloads: The payload list ajusted previously
        @returns List[Payload]: The encoded payloads list
        """
        return ajusted_payloads

    def set_regex(self, regex: str = '') -> None:
        """The regexer setter

        @type regex: str
        @param regex: The regular expression to set
        """
        try:
            self.regexer = re.compile(regex, re.IGNORECASE)
        except re.error:
            raise BadArgumentFormat(f"Invalid regex format {regex}")

    def set_encoders(self,
                     encoders: Tuple[
                         List[BaseEncoder], List[List[BaseEncoder]]
                     ]) -> None:
        """The encoders setter

        @type encoders: Tuple[list, list]
        @param encoders: The encoders used in the payloads
        """
        def encode(ajusted_payloads: List[Payload]) -> List[Payload]:
            return [
                Payload().update(payload).with_encoder(self._encode(encoder, payload.final), str(encoder))
                for encoder in self.encoders
                for payload in ajusted_payloads
            ]

        encoders_default, encoders_chain = encoders
        self.encoders = encoders_default+[ChainEncoder(encoders)
                                          for encoders in encoders_chain]
        self.encode = encode

    def _encode(self, encoder: BaseEncoder, payload: str) -> str:
        """Encode a payload into an specific encoding type

        @type encoder: BaseEncoder
        @param encoder: The encoder used to encode the payload
        @type payload: str
        @param payload: The payload used in the request
        @returns str: The encoded payload
        """
        def encode_substring(
            encoder: BaseEncoder,
            payload: str,
            i: int,
            m_strings: set
        ) -> Tuple[int, str]:
            """Encode a substring using the actual encoder

            @type encoder: BaseEncoder
            @param encoder: The encoder used to encode the payload
            @type payload: str
            @param payload: The payload used in the request
            @type i: int
            @param i: The index of the actual char of the payload
            @type m_strings: set
            @param m_strings: The matched strings list from the regexer
            @returns Tuple[int, str]: The encoded substring if match
                                      the regex, else return the actual char
            """
            for string in m_strings:
                last_index = i+len(string)
                to_check = payload[i:last_index]
                if to_check == string:
                    return (last_index, encoder.encode(to_check))
            return ((i+1), payload[i])

        if not self.regexer:
            return encoder.encode(payload)
        m_strings = set([match.group()
                         for match in self.regexer.finditer(payload)])
        if not m_strings:
            return payload
        encoded = ''
        i = 0
        while i < len(payload):
            i, char = encode_substring(encoder, payload, i, m_strings)
            encoded += char
        return encoded


class Payloader:
    """Class that handle with the payload options

    Attributes:
        prefix: The prefix used in the payload
        suffix: The suffix used in the payload
        encoder: The encoder used in the payload
    """
    prefix = []
    suffix = []
    encoder = EncodeManager()

    @staticmethod
    def case(ajusted_payloads: List[Payload]) -> List[Payload]:
        """Update the case letter

        @type ajusted_payloads: List[Payload]
        @param ajusted_payloads: The payload list ajusted previously
        @returns List[Payload]: The new payloads list
        """
        return ajusted_payloads

    @staticmethod
    def set_prefix(prefix: List[str]) -> None:
        """The prefix setter

        @type prefix: List[str]
        @param prefix: The prefix used in the payload
        """
        Payloader.prefix = prefix

    @staticmethod
    def set_suffix(suffix: List[str]) -> None:
        """The suffix setter

        @type suffix: List[str]
        @param suffix: The suffix used in the payload
        """
        Payloader.suffix = suffix

    @staticmethod
    def set_uppercase() -> None:
        """The uppercase setter"""
        def case(ajusted_payloads: List[Payload]) -> List[Payload]:
            return [
                Payload().update(payload).with_case(str.upper, "Upper")
                for payload in ajusted_payloads
            ]

        Payloader.case = case

    @staticmethod
    def set_lowercase() -> None:
        """The lowercase setter"""
        def case(ajusted_payloads: List[Payload]) -> List[Payload]:
            return [
                Payload().update(payload).with_case(str.lower, "Lower")
                for payload in ajusted_payloads
            ]

        Payloader.case = case

    @staticmethod
    def set_capitalize() -> None:
        """The capitalize setter"""
        def case(ajusted_payloads: List[Payload]) -> List[Payload]:
            return [
                Payload().update(payload).with_case(str.capitalize, "Capitalize")
                for payload in ajusted_payloads
            ]

        Payloader.case = case

    @staticmethod
    def get_customized_payload(payload: Payload) -> List[Payload]:
        """Gets the payload list ajusted with the console options

        @type payload: Payload
        @param payload: The payload object gived by the payloads queue
        @returns List[Payload]: The payloads used in the request
        """
        ajusted_payloads = [payload]
        if Payloader.prefix:
            ajusted_payloads = [Payload().update(payload).with_prefix(prefix)
                                for prefix in Payloader.prefix
                                for payload in ajusted_payloads]
        if Payloader.suffix:
            ajusted_payloads = [Payload().update(payload).with_suffix(suffix)
                                for suffix in Payloader.suffix
                                for payload in ajusted_payloads]
        return Payloader.case(Payloader.encoder.encode(ajusted_payloads))


================================================
FILE: src/fuzzingtool/core/plugins/__init__.py
================================================
# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>
#
# 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.

from .encoders import *
from .scanners import *
from .wordlists import *

================================================
FILE: src/fuzzingtool/core/plugins/encoders/__init__.py
================================================
# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>
#
# 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.

from .base64 import Base64
from .hex import Hex
from .html import Html
from .html_dec import HtmlDec
from .html_hex import HtmlHex
from .plain import Plain
from .url import Url

================================================
FILE: src/fuzzingtool/core/plugins/encoders/base64.py
================================================
# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>
#
# 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.

import base64

from ...bases.base_plugin import Plugin
from ...bases.base_encoder import BaseEncoder
from ....decorators.plugin_meta import plugin_meta


@plugin_meta
class Base64(BaseEncoder, Plugin):
    __author__ = ("Vitor Oriel",)
    __params__ = {}
    __desc__ = "Encode payload using Base64 encoder"
    __type__ = None
    __version__ = "0.1"

    def encode(self, payload: str) -> str:
        return base64.b64encode(payload.encode(BaseEncoder.charset)).decode(BaseEncoder.charset)

    def decode(self, payload: str) -> str:
        return base64.b64decode(payload).decode(BaseEncoder.charset)


================================================
FILE: src/fuzzingtool/core/plugins/encoders/hex.py
================================================
# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>
#
# 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.

from ...bases.base_plugin import Plugin
from ...bases.base_encoder import BaseEncoder
from ....decorators.plugin_meta import plugin_meta


@plugin_meta
class Hex(BaseEncoder, Plugin):
    __author__ = ("Vitor Oriel",)
    __params__ = {}
    __desc__ = "Encode payload to hexadecimal"
    __type__ = None
    __version__ = "0.2"

    def encode(self, payload: str) -> str:
        return payload.encode(BaseEncoder.charset).hex()

    def decode(self, payload: str) -> str:
        return bytes.fromhex(payload).decode(BaseEncoder.charset)


================================================
FILE: src/fuzzingtool/core/plugins/encoders/html.py
================================================
# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>
#
# 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.

import html

from ...bases.base_plugin import Plugin
from ...bases.base_encoder import BaseEncoder
from ....decorators.plugin_meta import plugin_meta


@plugin_meta
class Html(BaseEncoder, Plugin):
    __author__ = ("Vitor Oriel",)
    __params__ = {}
    __desc__ = "Encode payload using HTML entities encoder"
    __type__ = None
    __version__ = "0.1"

    def encode(self, payload: str) -> str:
        return html.escape(payload)

    def decode(self, payload: str) -> str:
        return html.unescape(payload)


================================================
FILE: src/fuzzingtool/core/plugins/encoders/html_dec.py
================================================
# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>
#
# 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.

from ...bases.base_plugin import Plugin
from ...bases.base_encoder import BaseEncoder
from ....decorators.plugin_meta import plugin_meta


@plugin_meta
class HtmlDec(BaseEncoder, Plugin):
    __author__ = ("Vitor Oriel",)
    __params__ = {}
    __desc__ = "Encode payload to html decimal format"
    __type__ = None
    __version__ = "0.1"

    def encode(self, payload: str) -> str:
        encoded = ''
        for c in payload:
            encoded += f"&#{ord(c)};"
        return encoded


================================================
FILE: src/fuzzingtool/core/plugins/encoders/html_hex.py
================================================
# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>
#
# 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.

from ...bases.base_plugin import Plugin
from ...bases.base_encoder import BaseEncoder
from ....decorators.plugin_meta import plugin_meta


@plugin_meta
class HtmlHex(BaseEncoder, Plugin):
    __author__ = ("Vitor Oriel",)
    __params__ = {}
    __desc__ = "Encode payload to html hexadecimal format"
    __type__ = None
    __version__ = "0.1"

    def encode(self, payload: str) -> str:
        encoded = ''
        for c in payload:
            encoded += f"&#x{ord(c):02x};"
        return encoded


================================================
FILE: src/fuzzingtool/core/plugins/encoders/plain.py
================================================
# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>
#
# 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.

from ...bases.base_plugin import Plugin
from ...bases.base_encoder import BaseEncoder
from ....decorators.plugin_meta import plugin_meta


@plugin_meta
class Plain(BaseEncoder, Plugin):
    __author__ = ("Vitor Oriel",)
    __params__ = {}
    __desc__ = "Do not encode the payload"
    __type__ = None
    __version__ = "0.2"

    def encode(self, payload: str) -> str:
        return payload


================================================
FILE: src/fuzzingtool/core/plugins/encoders/url.py
================================================
# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>
#
# 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.

from urllib.parse import quote, unquote

from ...bases.base_plugin import Plugin
from ...bases.base_encoder import BaseEncoder
from ....decorators.plugin_meta import plugin_meta
from ....exceptions import BadArgumentFormat


@plugin_meta
class Url(BaseEncoder, Plugin):
    __author__ = ("Vitor Oriel",)
    __params__ = {
        'metavar': "ENCODE_LEVEL",
        'type': str,
    }
    __desc__ = "Replace special characters in string using the %xx escape. Letters, digits, and the characters '_.-~' are never quoted."
    __type__ = None
    __version__ = "0.2"

    def __init__(self, encode_level: int):
        if not encode_level:
            encode_level = 1
        else:
            try:
                encode_level = int(encode_level)
            except ValueError:
                raise BadArgumentFormat("the encoding level must be an integer")
        self.encode_level = encode_level

    def encode(self, payload: str) -> str:
        encoded = payload
        for _ in range(self.encode_level):
            encoded = quote(encoded)
        return encoded

    def decode(self, payload: str) -> str:
        decoded = payload
        for _ in range(self.encode_level):
            decoded = unquote(decoded)
        return decoded


================================================
FILE: src/fuzzingtool/core/plugins/scanners/__init__.py
================================================
# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>
#
# 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.

from .backups import Backups
from .reflected import Reflected
from .grep import Grep
from .wappalyzer import Wappalyzer

================================================
FILE: src/fuzzingtool/core/plugins/scanners/backups.py
================================================
# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>
#
# 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.

from ...bases.base_plugin import Plugin
from ...bases.base_scanner import BaseScanner
from ....objects.result import Result
from ....decorators.plugin_meta import plugin_meta
from ....utils.consts import FuzzType

DEFAULT_EXTENSIONS = ".bak,.tgz,.zip,.tar.gz,~,.rar,.old,.swp"


@plugin_meta
class Backups(BaseScanner, Plugin):
    __author__ = ("Vitor Oriel",)
    __params__ = {
        'metavar': "EXTENSION",
        'type': list,
        'cli_list_separator': ',',
    }
    __desc__ = ("Look for backups extension on matched responses. "
                f"Default extensions: {DEFAULT_EXTENSIONS}")
    __type__ = FuzzType.PATH_FUZZING
    __version__ = "0.1"

    """
    Attributes:
        extensions: The extensions to look for
    """
    def __init__(self, extensions: list):
        self.extensions = extensions if extensions else DEFAULT_EXTENSIONS.split(',')
        BaseScanner.__init__(self)

    def scan(self, result: Result) -> bool:
        return True

    def _process(self, result: Result) -> None:
        if result.history.parsed_url.file_ext not in self.extensions:
            for ext in self.extensions:
                parsed_url = result.history.parsed_url
                self.enqueue_payload(result, f"{parsed_url.file_name}{ext}")
                self.enqueue_payload(result, f"{parsed_url.file}{ext}")


================================================
FILE: src/fuzzingtool/core/plugins/scanners/grep.py
================================================
# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>
#
# 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.

import re

from ...bases.base_plugin import Plugin
from ...bases.base_scanner import BaseScanner
from ....objects.result import Result
from ....utils.utils import stringfy_list
from ....decorators.plugin_meta import plugin_meta
from ....exceptions import MissingParameter, BadArgumentFormat


PREPARED_REGEXES = {
    'email': r"([a-zA-Z0-9._-]+@[a-zA-Z0-9._-]+\.[a-zA-Z0-9_-]+)",
    'links': r"(http|https)://([\w-]+(\.[\w-]+))([\w.,@?^=%&:/~+#-]*[\w@?^=%&/~+#-])?",
}


@plugin_meta
class Grep(BaseScanner, Plugin):
    __author__ = ("Vitor Oriel",)
    __params__ = {
        'metavar': "REGEX",
        'type': list,
        'cli_list_separator': ';',
    }
    __desc__ = ("Grep content based on a regex match into the response body. "
                "You can use these prepared regexes: "
                + stringfy_list(list(PREPARED_REGEXES.keys())))
    __type__ = None
    __version__ = "0.2"

    """
    Attributes:
        regexers: The regexes objects to grep the content into the response body
    """
    def __init__(self, regexes: list):
        if not regexes:
            raise MissingParameter("regex")
        self.__regexers = []
        for regex in regexes:
            if regex.lower() in PREPARED_REGEXES.keys():
                regex = PREPARED_REGEXES[regex.lower()]
            try:
                self.__regexers.append(re.compile(regex))
            except re.error:
                raise BadArgumentFormat(f"invalid regex: {regex}")
        BaseScanner.__init__(self)

    def scan(self, result: Result) -> bool:
        return True

    def _process(self, result: Result) -> None:
        self.get_self_res(result).data['found'] = 0
        for i, regexer in enumerate(self.__regexers):
            this_greped = list(set([
                r.group() for r in regexer.finditer(result.history.response.text)
            ]))
            self.get_self_res(result).data['found'] += len(this_greped)
            self.get_self_res(result).data[f'greped_regex_{i}'] = this_greped


================================================
FILE: src/fuzzingtool/core/plugins/scanners/reflected.py
================================================
# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>
#
# 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.

from ...bases.base_plugin import Plugin
from ...bases.base_scanner import BaseScanner
from ....objects.result import Result
from ....decorators.plugin_meta import plugin_meta


@plugin_meta
class Reflected(BaseScanner, Plugin):
    __author__ = ("Vitor Oriel",)
    __params__ = {}
    __desc__ = "Lookup if the payload was reflected in the response body"
    __type__ = None
    __version__ = "0.1"

    def scan(self, result: Result) -> bool:
        return result.payload in result.history.response.text


================================================
FILE: src/fuzzingtool/core/plugins/scanners/wappalyzer.py
================================================
# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>
#
# 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.

import warnings

import Wappalyzer as WP

from ...bases.base_plugin import Plugin
from ...bases.base_scanner import BaseScanner
from ....objects.result import Result
from ....decorators.plugin_meta import plugin_meta


@plugin_meta
class Wappalyzer(BaseScanner, Plugin):
    __author__ = ("Vitor Oriel",)
    __params__ = {}
    __desc__ = "Lookup for technologies on a web page during discovery scan"
    __type__ = None
    __version__ = "0.1"

    def __init__(self):
        warnings.filterwarnings("ignore", category=UserWarning)
        BaseScanner.__init__(self)

    def scan(self, result: Result) -> bool:
        return True

    def _process(self, result: Result) -> None:
        wp_technologies_dict = WP.Wappalyzer.latest().analyze_with_versions_and_categories(
            webpage=WP.WebPage.new_from_response(result.history.response)
        )
        technologies = []
        for key, value in wp_technologies_dict.items():
            version = ''
            if value['versions']:
                version = ' v' + ' | v'.join(value['versions'])
            technologies.append(f"{key}{version}")
        self.get_self_res(result).data['technologies'] = technologies


================================================
FILE: src/fuzzingtool/core/plugins/wordlists/__init__.py
================================================
# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>
#
# 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.

from .crt_sh import CrtSh
from .dns_dumpster import DnsDumpster
from .dns_zone import DnsZone
from .overflow import Overflow
from .robots import Robots

================================================
FILE: src/fuzzingtool/core/plugins/wordlists/crt_sh.py
================================================
# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>
#
# 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.

import re
from typing import List

from ...bases.base_plugin import Plugin
from ...bases.base_wordlist import BaseWordlist
from ....conn.requesters.requester import Requester
from ....exceptions.request_exceptions import RequestException
from ....decorators.plugin_meta import plugin_meta
from ....utils.consts import FuzzType
from ....exceptions import MissingParameter, BuildWordlistFails

CRTSH_HTTP_HEADER = {
    'Host': "crt.sh",
    'User-Agent': "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:87.0) Gecko/20100101 Firefox/87.0",
    'Accept': "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
    'Accept-Language': "en-US,en;q=0.5",
    'Accept-Encoding': "gzip, deflate",
    'Connection': "keep-alive",
    'Referer': "https://crt.sh/",
    'Upgrade-Insecure-Requests': "1",
    'TE': "Trailers",
}


@plugin_meta
class CrtSh(BaseWordlist, Plugin):
    __author__ = ("Vitor Oriel",)
    __params__ = {
        'metavar': "TARGET_HOST",
        'type': str,
    }
    __desc__ = "Build the wordlist based on the content of the site crt.sh"
    __type__ = FuzzType.SUBDOMAIN_FUZZING
    __version__ = "0.2"

    def __init__(self, host: str):
        if not host:
            raise MissingParameter("target host")
        self.host = host
        BaseWordlist.__init__(self)

    def _build(self) -> List[str]:
        response_json = self.__get_response_json()
        if not response_json:
            raise BuildWordlistFails(f"No certified domains was found for '{self.host}'")
        domain_list = self.__get_domain_list(response_json)
        return [domain.split(f'.{self.host}')[0]
                for domain in domain_list]

    def __get_response_json(self) -> List[dict]:
        """Get the json response from CrtSh API

        @returns List[dict]: The json response
        """
        global CRTSH_HTTP_HEADER
        requester = Requester(
            url=f"https://crt.sh/?q={self.host}&output=json",
            method='GET',
            headers=CRTSH_HTTP_HEADER,
        )
        try:
            response, *_ = requester.request()
        except RequestException as e:
            raise BuildWordlistFails(str(e))
        return response.json()

    def __get_domain_list(self, response_json: List[dict]) -> List[str]:
        """Get the domain list from the CrtSh API json response

        @type response_json: List[dict]
        @param response_json: The CrtSh API json response
        @returns List[str]: The filtered domain list
        """
        content_list = list(set([element['common_name']
                                 for element in response_json]))
        regex = r"([a-zA-Z0-9]+\.)*[a-zA-Z0-9]+"
        for splited in self.host.split('.'):
            regex += r"\." + splited
        regexer = re.compile(regex)
        return [element
                for element in content_list
                if regexer.match(str(element))]


================================================
FILE: src/fuzzingtool/core/plugins/wordlists/dns_dumpster.py
================================================
# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>
#
# 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.

import re
from typing import List

from bs4 import BeautifulSoup as bs

from ...bases.base_plugin import Plugin
from ...bases.base_wordlist import BaseWordlist
from ....conn.requesters.requester import Requester
from ....exceptions.request_exceptions import RequestException
from ....decorators.plugin_meta import plugin_meta
from ....utils.consts import FuzzType
from ....exceptions import MissingParameter, BuildWordlistFails

DNSDUMPSTER_HTTP_HEADER = {
    'Host': "dnsdumpster.com",
    'User-Agent': "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:87.0) Gecko/20100101 Firefox/87.0",
    'Accept': "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
    'Accept-Language': "en-US,en;q=0.5",
    'Accept-Encoding': "gzip, deflate",
    'Connection': "keep-alive",
    'Referer': "https://dnsdumpster.com/",
    'Upgrade-Insecure-Requests': "1",
}


@plugin_meta
class DnsDumpster(BaseWordlist, Plugin):
    __author__ = ("Vitor Oriel",)
    __params__ = {
        'metavar': "TARGET_HOST",
        'type': str,
    }
    __desc__ = "Build the wordlist based on the content of the site dnsdumpster.com"
    __type__ = FuzzType.SUBDOMAIN_FUZZING
    __version__ = "0.1"

    def __init__(self, host: str):
        if not host:
            raise MissingParameter("target host")
        self.host = host
        BaseWordlist.__init__(self)

    def _build(self) -> List[str]:
        global DNSDUMPSTER_HTTP_HEADER
        requester = Requester(
            url="https://dnsdumpster.com/",
            method='GET',
            headers=DNSDUMPSTER_HTTP_HEADER,
            is_session=True,
        )
        try:
            response, *_ = requester.request()
        except RequestException as e:
            raise BuildWordlistFails(str(e))
        token = response.cookies['csrftoken']
        requester.set_method('POST')
        requester.set_body(
            f"csrfmiddlewaretoken={token}&targetip={self.host}&user=free"
        )
        try:
            response, *_ = requester.request()
        except RequestException as e:
            raise BuildWordlistFails(str(e))
        if 'There was an error getting results' in response.text:
            raise BuildWordlistFails(f"No domains was found for '{self.host}'")
        content_list = [element.text
                        for element in
                        bs(response.text, "html.parser").find_all('td', class_='col-md-4')]
        regex = r"([a-zA-Z0-9]+\.)*[a-zA-Z0-9]+"
        for splited in self.host.split('.'):
            regex += r"\."+splited
        regexer = re.compile(regex)
        domain_list = sorted(set([element
                                  for element in content_list
                                  if regexer.match(str(element))]))
        return [domain.split(f'.{self.host}')[0]
                for domain in domain_list]


================================================
FILE: src/fuzzingtool/core/plugins/wordlists/dns_zone.py
================================================
# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>
#
# 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.

from typing import List
from socket import gethostbyname, gaierror

from dns import resolver, query, zone

from ...bases.base_plugin import Plugin
from ...bases.base_wordlist import BaseWordlist
from ....decorators.plugin_meta import plugin_meta
from ....utils.consts import FuzzType
from ....exceptions import MissingParameter, BuildWordlistFails


@plugin_meta
class DnsZone(BaseWordlist, Plugin):
    __author__ = ("Vitor Oriel",)
    __params__ = {
        'metavar': "TARGET_HOST",
        'type': str,
    }
    __desc__ = "Build the wordlist based on a DNS zone transfer request"
    __type__ = FuzzType.SUBDOMAIN_FUZZING
    __version__ = "0.2"

    def __init__(self, host: str):
        if not host:
            raise MissingParameter("target host")
        self.host = host
        BaseWordlist.__init__(self)

    def _build(self) -> List[str]:
        try:
            gethostbyname(self.host)
        except gaierror:
            raise BuildWordlistFails(f"Couldn't resolve hostname {self.host}")
        name_servers = resolver.resolve(self.host, 'NS')
        name_servers_ips = []
        for ns in name_servers:
            records = resolver.resolve(str(ns), 'A')
            for record in records:
                name_servers_ips.append(str(record))
        if not name_servers_ips:
            raise BuildWordlistFails("Couldn't find any name servers")
        transfered_subdomains = []
        for ip in name_servers_ips:
            transfered_subdomains.extend(self.__do_dns_transfer(ip))
        if not transfered_subdomains:
            raise BuildWordlistFails("Couldn't make the zone transfer for any of the "
                                     f"{len(name_servers_ips)} name servers")
        if '@' in transfered_subdomains:
            transfered_subdomains.remove('@')
        return list(set(transfered_subdomains))

    def __do_dns_transfer(self, ip: str) -> List[str]:
        """Do the DNS Zone Transfer, returning the subdomains

        @type ip: str
        @param ip: The IP from the name server
        @returns List[str]: The list with the subdomains
        """
        try:
            zones = zone.from_xfr(query.xfr(ip.rstrip('.'), self.host))
        except query.TransferError:
            return []
        else:
            return [str(subdomain) for subdomain in zones]


================================================
FILE: src/fuzzingtool/core/plugins/wordlists/overflow.py
================================================
# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>
#
# 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.

from typing import List

from ...bases.base_plugin import Plugin
from ...bases.base_wordlist import BaseWordlist
from ....decorators.plugin_meta import plugin_meta
from ....exceptions import MissingParameter, BadArgumentFormat, BadArgumentType


@plugin_meta
class Overflow(BaseWordlist, Plugin):
    __author__ = ("Vitor Oriel",)
    __params__ = {
        'metavar': "QUANTITY_OF_PAYLOADS,INIT_PAYLOAD:PAYLOAD:END_PAYLOAD",
        'type': str,
    }
    __desc__ = "Build the wordlist for stress and buffer overflow purposes"
    __type__ = None
    __version__ = "0.1"

    def __init__(self, source_param: str):
        if not source_param:
            raise MissingParameter("quantity of payloads")
        if ',' in source_param:
            quantity_of_payloads, payload = source_param.split(',', 1)
            if ':' in payload:
                try:
                    init_payload, payload, end_payload = payload.split(':', 3)
                except ValueError:
                    raise BadArgumentFormat(
                        "invalid quantity of values to unpack "
                        "(expected init_payload:payload:end_payload)"
                    )
            else:
                init_payload, end_payload = '', ''
        else:
            quantity_of_payloads = source_param
            init_payload, payload, end_payload = '', '', ''
        try:
            quantity_of_payloads = int(quantity_of_payloads)
        except ValueError:
            raise BadArgumentType("the quantity of payloads must be integer")
        self.quantity_of_payloads = quantity_of_payloads
        self.init_payload = init_payload
        self.payload = payload
        self.end_payload = end_payload
        BaseWordlist.__init__(self)

    def _build(self) -> List[str]:
        return [
            f"{self.init_payload}{self.payload*i}{self.end_payload}"
            for i in range(self.quantity_of_payloads)
        ]


================================================
FILE: src/fuzzingtool/core/plugins/wordlists/robots.py
================================================
# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>
#
# 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.

from typing import List

from requests.exceptions import HTTPError

from ...bases.base_plugin import Plugin
from ...bases.base_wordlist import BaseWordlist
from ....utils.http_utils import get_parsed_url
from ....conn.requesters.requester import Requester
from ....decorators.plugin_meta import plugin_meta
from ....utils.consts import FuzzType
from ....exceptions.request_exceptions import RequestException
from ....exceptions import MissingParameter, BuildWordlistFails

ROBOTS_HTTP_HEADER = {
    'User-Agent': "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:87.0) Gecko/20100101 Firefox/87.0",
    'Referer': "https://google.com/",
}


@plugin_meta
class Robots(BaseWordlist, Plugin):
    __author__ = ("Vitor Oriel",)
    __params__ = {
        'metavar': "TARGET_URL",
        'type': str,
    }
    __desc__ = "Build the wordlist using the target robots.txt"
    __type__ = FuzzType.PATH_FUZZING
    __version__ = "0.1"

    def __init__(self, url: str):
        if not url:
            raise MissingParameter("target url")
        if not url.endswith('/'):
            url += '/'
        self.url = url
        BaseWordlist.__init__(self)

    def _build(self) -> List[str]:
        global ROBOTS_HTTP_HEADER
        requester = Requester(
            url=f"{self.url}robots.txt",
            method='GET',
            headers=ROBOTS_HTTP_HEADER,
            timeout=5,
        )
        try:
            response, *_ = requester.request()
            response.raise_for_status()
        except (RequestException, HTTPError) as e:
            raise BuildWordlistFails(str(e))
        paths = []
        for line in response.text.split('\n'):
            if (line and not line.startswith('#') and (
                "allow" in line.lower() or
                "disallow" in line.lower() or
                "sitemap" in line.lower()
            )):
                _, path = line.split(': ', 1)
                if '://' in path:
                    path = get_parsed_url(path).path
                paths.append(path[1:])
        return paths


================================================
FILE: src/fuzzingtool/core/recursion_manager.py
================================================
# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>
#
# 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.

from queue import Queue
from typing import List

from .bases.job_provider import JobProvider
from ..objects import Payload, Result


class RecursionManager(JobProvider):
    """Class responsible to manage the directory recursion

    Attributes:
        max_rlevel: The maximum jobs recursion level
        wordlist: The wordlist with base payloads
        directories_queue: The control queue for directories found
        payloads_queue: The jobs queue for the job manager
    """
    def __init__(self, max_rlevel: int, wordlist: List[str]):
        """Class constructor

        @type max_rlevel: int
        @param max_rlevel: The maximum jobs recursion level
        @type wordlist: List[str]
        @param wordlist: The wordlist with base payloads
        """
        self.max_rlevel = max_rlevel
        self.wordlist = wordlist
        self.directories_queue = Queue()
        self.payloads_queue = Queue()
        super().__init__()

    def notify(self, result: Result, path: str) -> None:
        """Notify the observer with the new job

        @type result: Result
        @param result: The FuzzingTool result object
        @type path: str
        @param path: The path that enqueued the job
        """
        self._observer.update(f"directory recursion on path {path}", result)

    def has_recursive_job(self) -> bool:
        """Check if has pending recursive job

        @returns bool: A flag to say if has recursive job
        """
        return not self.directories_queue.empty()

    def check_for_recursion(self, result: Result) -> None:
        """Check if a result is eligible for recursion, and enqueue it into the directories queue

        @type result: Result
        @param result: THe FuzzingTool result object
        """
        payload = result._payload
        if result.history.is_path and payload.rlevel < self.max_rlevel:
            path = result.history.parsed_url.path
            self.directories_queue.put(
                Payload().update(payload).with_recursion(path[1:])
            )
            self.notify(result, path)

    def fill_payloads_queue(self) -> None:
        """Fill the payloads queue with recursive directory payloads"""
        recursive_directory = self.directories_queue.get()
        for wordlist_payload in self.wordlist:
            new_payload = Payload().update(recursive_directory)
            new_payload.final += wordlist_payload
            self.payloads_queue.put(new_payload)


================================================
FILE: src/fuzzingtool/core/summary.py
================================================
# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>
#
# 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.

import time


class Summary:
    """Class to store the summary information of the controller

    Attributes:
        results: The list of the found results
        elapsed_time: The elapsed time of the fuzzing test
        time_before: A buffer to handle with the pause and resume timer
    """
    def __init__(self):
        self.results = []
        self.elapsed_time = 0
        self.__time_before = 0

    def start_timer(self) -> None:
        """Starts the timer"""
        self.elapsed_time = time.time()

    def stop_timer(self) -> None:
        """Stops the timer"""
        if self.__time_before:
            self.resume_timer()
        self.elapsed_time = time.time() - self.elapsed_time

    def pause_timer(self) -> None:
        """Pauses the timer"""
        self.__time_before = time.time()

    def resume_timer(self) -> None:
        """Resumes the timer"""
        self.elapsed_time += (time.time() - self.__time_before)
        self.__time_before = 0


================================================
FILE: src/fuzzingtool/decorators/__init__.py
================================================
# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>
#
# 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/fuzzingtool/decorators/plugin_meta.py
================================================
# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>
#
# 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.

from ..core.bases.base_plugin import Plugin
from ..utils.consts import FuzzType
from ..exceptions import MetadataException


def plugin_meta(cls: Plugin) -> Plugin:
    """Decorator to check for plugin metadata on a plugin class

    @type cls: Plugin
    @param cls: The class that call this decorator
    """
    _check_mandatory_meta(cls)
    if not cls.__author__:
        raise MetadataException(f"Author cannot be empty on plugin {cls.__name__}")
    if cls.__params__:
        _check_params_meta(cls)
    if not cls.__desc__:
        raise MetadataException(
            f"Description cannot be blank on plugin {cls.__name__}"
        )
    if cls.__type__ is not None and cls.__type__ not in [
        value for key, value in vars(FuzzType).items() if not key.startswith("__")
    ]:
        raise MetadataException(
            f"Plugin type should be None or a valid FuzzType on plugin {cls.__name__}"
        )
    if not cls.__version__:
        raise MetadataException(f"Version cannot be blank on plugin {cls.__name__}")
    return cls


def _check_mandatory_meta(cls: Plugin) -> None:
    """Checks the mandatory metadata into the plugin decorator

    @type cls: Plugin
    @param cls: The class with the plugin metadata
    """
    metadata = ['__author__', '__params__',
                '__desc__', '__type__', '__version__']
    class_attr = vars(cls)
    for meta in metadata:
        if meta not in class_attr:
            raise MetadataException(
                f"Metadata {meta} not specified on plugin {cls.__name__}"
            )


def _check_params_meta(cls: Plugin) -> None:
    """Checks the parameter metadata into the plugin decorator

    @type cls: Plugin
    @param cls: The class with the plugin metadata
    """
    if (type(cls.__params__) is not dict):
        raise MetadataException("The parameters must be a "
                                f"dictionary on plugin {cls.__name__}")
    param_dict_keys = cls.__params__.keys()
    for key in ['metavar', 'type']:
        if key not in param_dict_keys:
            raise MetadataException(f"Key {key} must be in parameters "
                                    f"dict on plugin {cls.__name__}")
        if not cls.__params__[key]:
            raise MetadataException(f"Value of {key} cannot be empty in "
                                    f"parameters dict on plugin {cls.__name__}")
    if cls.__params__['type'] is list:
        if 'cli_list_separator' not in param_dict_keys:
            raise MetadataException("The key 'cli_list_separator' must be present "
                                    "when parameter type is list "
                                    f"on plugin {cls.__name__}")
        if not cls.__params__['cli_list_separator']:
            raise MetadataException("Value of 'cli_list_separator' "
                                    f"cannot be blank on {cls.__name__}")


================================================
FILE: src/fuzzingtool/decorators/report_meta.py
================================================
# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>
#
# 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.

from ..persistence.base_report import BaseReport
from ..exceptions import MetadataException


def report_meta(cls: BaseReport) -> BaseReport:
    """Decorator to check for BaseReport metadata

    @type cls: BaseReport
    @param cls: The class that call this decorator
    """
    metadata = ['__author__', '__version__', 'file_extension']
    class_attr = vars(cls)
    for meta in metadata:
        if meta not in class_attr:
            raise MetadataException(
                f"Metadata {meta} not specified on report {cls.__name__}"
            )
    if not cls.__author__:
        raise MetadataException(f"Author cannot be empty on report {cls.__name__}")
    if not cls.__version__:
        raise MetadataException(f"Version cannot be blank on report {cls.__name__}")
    return cls


================================================
FILE: src/fuzzingtool/exceptions/__init__.py
================================================
# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>
#
# 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.

from .main_exceptions import *
from .param_exceptions import *
from .request_exceptions import *


================================================
FILE: src/fuzzingtool/exceptions/base_exceptions.py
================================================
# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>
#
# 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.

class FuzzingToolException(Exception):
    pass


================================================
FILE: src/fuzzingtool/exceptions/main_exceptions.py
================================================
# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>
#
# 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.

from .base_exceptions import FuzzingToolException


class FuzzLibException(FuzzingToolException):
    pass


class StopActionInterrupt(FuzzingToolException):
    pass


class BuildWordlistFails(FuzzingToolException):
    pass


class WordlistCreationError(FuzzingToolException):
    pass


class MetadataException(FuzzingToolException):
    pass


================================================
FILE: src/fuzzingtool/exceptions/param_exceptions.py
================================================
# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>
#
# 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.

from .base_exceptions import FuzzingToolException


class MissingParameter(FuzzingToolException):
    pass


class BadArgumentFormat(FuzzingToolException):
    pass


class BadArgumentType(FuzzingToolException):
    pass


class InvalidArgument(FuzzingToolException):
    pass


================================================
FILE: src/fuzzingtool/exceptions/plugin_exceptions.py
================================================
# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>
#
# 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.

from .base_exceptions import FuzzingToolException


class InvalidPluginCategory(FuzzingToolException):
    pass


class InvalidPlugin(FuzzingToolException):
    pass


class PluginCreationError(FuzzingToolException):
    pass


================================================
FILE: src/fuzzingtool/exceptions/request_exceptions.py
================================================
# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>
#
# 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.

from .base_exceptions import FuzzingToolException


class RequestException(FuzzingToolException):
    pass


class InvalidHostname(FuzzingToolException):
    pass


================================================
FILE: src/fuzzingtool/factories/__init__.py
================================================
# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>
#
# 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.

from .plugin_factory import PluginFactory
from .wordlist_factory import WordlistFactory

================================================
FILE: src/fuzzingtool/factories/base_factories.py
================================================
# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>
#
# 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.

from abc import ABC, abstractmethod


class BasePluginFactory(ABC):
    @staticmethod
    @abstractmethod
    def get_plugins_from_category(category: str):
        """Gets the plugin instanaces from a category

        @type category: str
        @param category: The category of the plugins
        @returns List[Type[Plugin]]: The list with the plugin instances from category
        """
        pass

    @staticmethod
    @abstractmethod
    def class_creator(name: str, category: str):
        """Get the import for the plugin

        @type name: str
        @param name: The plugin to be searched for
        @type category: str
        @param category: The category of the searched plugin
        @returns Type[Plugin]: The import of the searched plugin
        """
        pass

    @staticmethod
    @abstractmethod
    def object_creator(name: str, category: str, params):
        """Build the plugins based on their categories

        @type name: str
        @param name: The plugin name
        @type category: str
        @param category: The plugin category
        @type params: mixed
        @param params: The plugin parameters (if it has)
        @returns Plugin: The selected plugin object
        """
        pass


class BaseWordlistFactory(ABC):
    @staticmethod
    @abstractmethod
    def creator(name: str, params: str, requester):
        """Generates the wordlist

        @type name: str
        @param name: The word
Download .txt
gitextract_qgtvmx_a/

├── .github/
│   ├── CODE_OF_CONDUCT.md
│   ├── CONTRIBUTING.md
│   ├── ISSUE_TEMPLATE/
│   │   ├── BUG_REPORT.md
│   │   └── FEATURE_REQUEST.md
│   └── workflows/
│       ├── cd.yml
│       ├── ci.yml
│       ├── quality.yml
│       ├── sast.yml
│       └── sca.yml
├── .gitignore
├── CONTRIBUTORS.md
├── LICENSE
├── README.md
├── requirements.txt
├── setup.py
├── src/
│   ├── fuzzingtool/
│   │   ├── __init__.py
│   │   ├── api.py
│   │   ├── conn/
│   │   │   ├── __init__.py
│   │   │   ├── request_parser.py
│   │   │   └── requesters/
│   │   │       ├── __init__.py
│   │   │       ├── requester.py
│   │   │       └── subdomain_requester.py
│   │   ├── core/
│   │   │   ├── __init__.py
│   │   │   ├── bases/
│   │   │   │   ├── __init__.py
│   │   │   │   ├── base_encoder.py
│   │   │   │   ├── base_observer.py
│   │   │   │   ├── base_plugin.py
│   │   │   │   ├── base_scanner.py
│   │   │   │   ├── base_validator.py
│   │   │   │   ├── base_wordlist.py
│   │   │   │   └── job_provider.py
│   │   │   ├── blacklist_status.py
│   │   │   ├── defaults/
│   │   │   │   ├── __init__.py
│   │   │   │   ├── encoders/
│   │   │   │   │   ├── __init__.py
│   │   │   │   │   └── chain_encoder.py
│   │   │   │   ├── scanners/
│   │   │   │   │   ├── __init__.py
│   │   │   │   │   ├── data_scanner.py
│   │   │   │   │   ├── path_scanner.py
│   │   │   │   │   └── subdomain_scanner.py
│   │   │   │   └── wordlists/
│   │   │   │       ├── __init__.py
│   │   │   │       ├── file_wordlist.py
│   │   │   │       └── list_wordlist.py
│   │   │   ├── dictionary.py
│   │   │   ├── filter.py
│   │   │   ├── fuzzer.py
│   │   │   ├── job_manager.py
│   │   │   ├── matcher.py
│   │   │   ├── payloader.py
│   │   │   ├── plugins/
│   │   │   │   ├── __init__.py
│   │   │   │   ├── encoders/
│   │   │   │   │   ├── __init__.py
│   │   │   │   │   ├── base64.py
│   │   │   │   │   ├── hex.py
│   │   │   │   │   ├── html.py
│   │   │   │   │   ├── html_dec.py
│   │   │   │   │   ├── html_hex.py
│   │   │   │   │   ├── plain.py
│   │   │   │   │   └── url.py
│   │   │   │   ├── scanners/
│   │   │   │   │   ├── __init__.py
│   │   │   │   │   ├── backups.py
│   │   │   │   │   ├── grep.py
│   │   │   │   │   ├── reflected.py
│   │   │   │   │   └── wappalyzer.py
│   │   │   │   └── wordlists/
│   │   │   │       ├── __init__.py
│   │   │   │       ├── crt_sh.py
│   │   │   │       ├── dns_dumpster.py
│   │   │   │       ├── dns_zone.py
│   │   │   │       ├── overflow.py
│   │   │   │       └── robots.py
│   │   │   ├── recursion_manager.py
│   │   │   └── summary.py
│   │   ├── decorators/
│   │   │   ├── __init__.py
│   │   │   ├── plugin_meta.py
│   │   │   └── report_meta.py
│   │   ├── exceptions/
│   │   │   ├── __init__.py
│   │   │   ├── base_exceptions.py
│   │   │   ├── main_exceptions.py
│   │   │   ├── param_exceptions.py
│   │   │   ├── plugin_exceptions.py
│   │   │   └── request_exceptions.py
│   │   ├── factories/
│   │   │   ├── __init__.py
│   │   │   ├── base_factories.py
│   │   │   ├── plugin_factory.py
│   │   │   └── wordlist_factory.py
│   │   ├── fuzz_lib.py
│   │   ├── fuzzingtool.py
│   │   ├── interfaces/
│   │   │   ├── __init__.py
│   │   │   └── cli/
│   │   │       ├── __init__.py
│   │   │       ├── cli_arguments.py
│   │   │       ├── cli_controller.py
│   │   │       └── cli_output.py
│   │   ├── objects/
│   │   │   ├── __init__.py
│   │   │   ├── base_objects.py
│   │   │   ├── error.py
│   │   │   ├── fuzz_word.py
│   │   │   ├── http_history.py
│   │   │   ├── payload.py
│   │   │   ├── result.py
│   │   │   └── scanner_result.py
│   │   ├── persistence/
│   │   │   ├── __init__.py
│   │   │   ├── base_report.py
│   │   │   ├── logger.py
│   │   │   ├── report.py
│   │   │   └── reports/
│   │   │       ├── __init__.py
│   │   │       ├── csv_report.py
│   │   │       ├── json_report.py
│   │   │       └── txt_report.py
│   │   └── utils/
│   │       ├── __init__.py
│   │       ├── argument_utils.py
│   │       ├── consts.py
│   │       ├── file_utils.py
│   │       ├── http_utils.py
│   │       ├── result_utils.py
│   │       └── utils.py
│   └── fuzzingtool.py
├── tests/
│   ├── __init__.py
│   ├── conn/
│   │   ├── __init__.py
│   │   ├── requesters/
│   │   │   ├── __init__.py
│   │   │   ├── test_requester.py
│   │   │   └── test_subdomain_requester.py
│   │   └── test_request_parser.py
│   ├── core/
│   │   ├── __init__.py
│   │   ├── test_blacklist_status.py
│   │   ├── test_filter.py
│   │   ├── test_job_manager.py
│   │   ├── test_matcher.py
│   │   ├── test_payloader.py
│   │   └── test_recursion_manager.py
│   ├── decorators/
│   │   └── test_plugin_meta.py
│   ├── factories/
│   │   ├── test_plugin_factory.py
│   │   └── test_wordlist_factory.py
│   ├── interfaces/
│   │   ├── __init__.py
│   │   └── cli/
│   │       ├── __init__.py
│   │       ├── test_cli_arguments.py
│   │       └── test_cli_output.py
│   ├── mock_utils/
│   │   ├── __init__.py
│   │   ├── args_decorator.py
│   │   ├── response_mock.py
│   │   └── wordlist_mock.py
│   ├── objects/
│   │   ├── __init__.py
│   │   ├── test_error.py
│   │   ├── test_fuzz_word.py
│   │   ├── test_http_history.py
│   │   ├── test_payload.py
│   │   └── test_result.py
│   ├── persistence/
│   │   ├── test_logger.py
│   │   └── test_report.py
│   ├── test_fuzz_lib.py
│   └── utils/
│       ├── __init__.py
│       ├── test_argument_utils.py
│       ├── test_file_utils.py
│       ├── test_http_utils.py
│       ├── test_result_utils.py
│       └── test_utils.py
└── wordlists/
    ├── enumeration/
    │   ├── paths.txt
    │   └── subdomains.txt
    └── injection/
        ├── sqli.txt
        └── xss.txt
Download .txt
SYMBOL INDEX (761 symbols across 107 files)

FILE: setup.py
  function read (line 7) | def read(fname):

FILE: src/fuzzingtool/api.py
  function fuzz (line 25) | def fuzz(**kwargs) -> None:
  function fuzz_cli (line 29) | def fuzz_cli(args: str, **kwargs) -> None:

FILE: src/fuzzingtool/conn/request_parser.py
  function check_is_subdomain_fuzzing (line 26) | def check_is_subdomain_fuzzing(url: str) -> bool:
  function check_is_url_discovery (line 37) | def check_is_url_discovery(url: FuzzWord) -> bool:
  function check_is_data_fuzzing (line 47) | def check_is_data_fuzzing(
  class RequestParser (line 74) | class RequestParser:
    method __init__ (line 80) | def __init__(self):
    method get_method (line 83) | def get_method(self, method: FuzzWord) -> str:
    method get_url (line 92) | def get_url(self, url: FuzzWord) -> str:
    method get_header (line 101) | def get_header(self, header: dict) -> dict:
    method get_data (line 111) | def get_data(self, data: Dict[FuzzWord, FuzzWord]) -> dict:
    method set_payload (line 125) | def set_payload(self, payload: str) -> None:

FILE: src/fuzzingtool/conn/requesters/requester.py
  class Requester (line 37) | class Requester:
    method __init__ (line 52) | def __init__(self,
    method get_url (line 115) | def get_url(self) -> str:
    method get_method (line 122) | def get_method(self) -> str:
    method is_method_fuzzing (line 129) | def is_method_fuzzing(self) -> bool:
    method is_data_fuzzing (line 136) | def is_data_fuzzing(self) -> bool:
    method is_url_discovery (line 143) | def is_url_discovery(self) -> bool:
    method is_path_fuzzing (line 150) | def is_path_fuzzing(self) -> bool:
    method get_fuzzing_type (line 157) | def get_fuzzing_type(self) -> int:
    method set_method (line 164) | def set_method(self, method: str) -> None:
    method set_body (line 172) | def set_body(self, body: str) -> None:
    method test_connection (line 180) | def test_connection(self) -> None:
    method request (line 208) | def request(self,
    method _request (line 257) | def _request(self,
    method _set_fuzzing_type (line 291) | def _set_fuzzing_type(self) -> int:
    method __setup_url (line 304) | def __setup_url(self, url: str) -> Tuple[FuzzWord, str]:
    method __build_data_dict (line 321) | def __build_data_dict(self, data: str) -> Dict[FuzzWord, FuzzWord]:
    method __setup_header (line 338) | def __setup_header(self, header: dict) -> dict:
    method __setup_proxy (line 356) | def __setup_proxy(self, proxy: str) -> Dict[str, str]:
    method __get_request_parameters (line 368) | def __get_request_parameters(self, payload: str) -> Tuple[
    method __session_request (line 387) | def __session_request(self,

FILE: src/fuzzingtool/conn/requesters/subdomain_requester.py
  class SubdomainRequester (line 33) | class SubdomainRequester(Requester):
    method resolve_hostname (line 35) | def resolve_hostname(self, hostname: str) -> str:
    method request (line 47) | def request(self,
    method _set_fuzzing_type (line 56) | def _set_fuzzing_type(self) -> int:

FILE: src/fuzzingtool/core/bases/base_encoder.py
  class BaseEncoder (line 24) | class BaseEncoder(ABC):
    method __str__ (line 27) | def __str__(self) -> str:
    method encode (line 31) | def encode(self, payload: str) -> str:

FILE: src/fuzzingtool/core/bases/base_observer.py
  class BaseObserver (line 26) | class BaseObserver(ABC):
    method update (line 29) | def update(self, subject_name: str, result: Result) -> None:

FILE: src/fuzzingtool/core/bases/base_plugin.py
  class Plugin (line 24) | class Plugin(ABC):

FILE: src/fuzzingtool/core/bases/base_scanner.py
  class BaseScanner (line 28) | class BaseScanner(JobProvider):
    method __init__ (line 34) | def __init__(self):
    method __str__ (line 38) | def __str__(self) -> str:
    method notify (line 41) | def notify(self, result: Result) -> None:
    method scan (line 50) | def scan(self, result: Result) -> bool:
    method process (line 59) | def process(self, result: Result) -> None:
    method get_self_res (line 70) | def get_self_res(self, result: Result) -> ScannerResult:
    method enqueue_payload (line 79) | def enqueue_payload(self, result: Result, payload: str) -> None:
    method _process (line 93) | def _process(self, result: Result) -> None:

FILE: src/fuzzingtool/core/bases/base_validator.py
  class BaseValidator (line 28) | class BaseValidator(ABC):
    method __init__ (line 34) | def __init__(self, regex: str):
    method __build_regexer (line 42) | def __build_regexer(self, regex: str) -> Pattern[str]:

FILE: src/fuzzingtool/core/bases/base_wordlist.py
  class BaseWordlist (line 25) | class BaseWordlist(ABC):
    method __init__ (line 31) | def __init__(self):
    method __len__ (line 34) | def __len__(self) -> int:
    method get (line 37) | def get(self) -> List[str]:
    method build (line 44) | def build(self) -> None:
    method _build (line 49) | def _build(self) -> List[str]:

FILE: src/fuzzingtool/core/bases/job_provider.py
  class JobProvider (line 26) | class JobProvider(ABC):
    method __init__ (line 32) | def __init__(self):
    method set_observer (line 35) | def set_observer(self, observer: BaseObserver) -> None:
    method notify (line 44) | def notify(self) -> None:

FILE: src/fuzzingtool/core/blacklist_status.py
  class BlacklistStatus (line 27) | class BlacklistStatus:
    method __init__ (line 34) | def __init__(self,
    method do_action (line 56) | def do_action(self, status: int) -> None:
    method build_status_list (line 64) | def build_status_list(self, status: str) -> List[int]:
    method set_action_callback (line 76) | def set_action_callback(self,

FILE: src/fuzzingtool/core/defaults/encoders/chain_encoder.py
  class ChainEncoder (line 26) | class ChainEncoder(BaseEncoder):
    method __init__ (line 32) | def __init__(self, encoders: List[BaseEncoder]):
    method __str__ (line 41) | def __str__(self) -> str:
    method getEncoders (line 44) | def getEncoders(self) -> List[BaseEncoder]:
    method encode (line 51) | def encode(self, payload: str) -> str:

FILE: src/fuzzingtool/core/defaults/scanners/data_scanner.py
  class DataScanner (line 25) | class DataScanner(BaseScanner):
    method scan (line 28) | def scan(self, result: Result) -> bool:
    method _process (line 31) | def _process(self, result: Result) -> None:

FILE: src/fuzzingtool/core/defaults/scanners/path_scanner.py
  class PathScanner (line 25) | class PathScanner(BaseScanner):
    method scan (line 28) | def scan(self, result: Result) -> bool:
    method _process (line 31) | def _process(self, result: Result) -> None:

FILE: src/fuzzingtool/core/defaults/scanners/subdomain_scanner.py
  class SubdomainScanner (line 25) | class SubdomainScanner(BaseScanner):
    method scan (line 28) | def scan(self, result: Result) -> bool:

FILE: src/fuzzingtool/core/defaults/wordlists/file_wordlist.py
  class FileWordlist (line 28) | class FileWordlist(BaseWordlist):
    method __init__ (line 31) | def __init__(self, file_path: str):
    method _build (line 35) | def _build(self) -> List[str]:

FILE: src/fuzzingtool/core/defaults/wordlists/list_wordlist.py
  class ListWordlist (line 27) | class ListWordlist(BaseWordlist):
    method __init__ (line 30) | def __init__(self, payload_list: str):
    method _build (line 35) | def _build(self) -> List[str]:

FILE: src/fuzzingtool/core/dictionary.py
  class Dictionary (line 28) | class Dictionary:
    method __init__ (line 36) | def __init__(self, wordlist: list):
    method __next__ (line 46) | def __next__(self) -> List[Payload]:
    method __len__ (line 54) | def __len__(self) -> int:
    method is_empty (line 73) | def is_empty(self) -> bool:
    method reload (line 80) | def reload(self) -> None:
    method fill_from_queue (line 86) | def fill_from_queue(self, payloads_queue: Queue, clear: bool = False) ...

FILE: src/fuzzingtool/core/filter.py
  class Filter (line 28) | class Filter(BaseValidator):
    method __init__ (line 35) | def __init__(self, status_code: str = None, regex: str = None):
    method check (line 46) | def check(self, result: Result) -> bool:
    method __build_status_codes (line 60) | def __build_status_codes(self, status_code: str) -> List[int]:

FILE: src/fuzzingtool/core/fuzzer.py
  class Fuzzer (line 33) | class Fuzzer:
    method __init__ (line 42) | def __init__(self,
    method setup_threads (line 74) | def setup_threads(self, number_of_threads: int) -> None:
    method is_running (line 94) | def is_running(self) -> bool:
    method is_paused (line 101) | def is_paused(self) -> bool:
    method run (line 108) | def run(self) -> None:
    method join (line 126) | def join(self) -> bool:
    method start (line 137) | def start(self) -> None:
    method pause (line 143) | def pause(self) -> None:
    method stop (line 147) | def stop(self) -> None:
    method resume (line 153) | def resume(self) -> None:
    method wait_until_pause (line 158) | def wait_until_pause(self) -> None:

FILE: src/fuzzingtool/core/job_manager.py
  class JobManager (line 29) | class JobManager(BaseObserver):
    method __init__ (line 42) | def __init__(self,
    method update (line 66) | def update(self, provider: str, result: Result) -> None:
    method get_job (line 77) | def get_job(self) -> None:
    method has_pending_jobs (line 84) | def has_pending_jobs(self) -> bool:
    method has_pending_jobs_from_providers (line 91) | def has_pending_jobs_from_providers(self) -> bool:
    method check_for_new_jobs (line 101) | def check_for_new_jobs(self) -> None:

FILE: src/fuzzingtool/core/matcher.py
  function get_status_code (line 30) | def get_status_code(status: str,
  class Matcher (line 56) | class Matcher(BaseValidator):
    method __init__ (line 65) | def __init__(self,
    method status_code_is_default (line 91) | def status_code_is_default(self) -> bool:
    method comparator_is_set (line 98) | def comparator_is_set(self) -> bool:
    method set_status_code (line 109) | def set_status_code(self, status_code: str) -> None:
    method set_comparator (line 117) | def set_comparator(self,
    method match (line 135) | def match(self, result: Result) -> bool:
    method _match_status (line 162) | def _match_status(self, status: int) -> bool:
    method _match_time (line 174) | def _match_time(self, time: float, comparator_time: float) -> bool:
    method _match_size (line 185) | def _match_size(self, size: int, comparator_size: int) -> bool:
    method _match_words (line 196) | def _match_words(self, words: float, comparator_words: float) -> bool:
    method _match_lines (line 207) | def _match_lines(self, lines: float, comparator_lines: float) -> bool:
    method __build_status_code (line 218) | def __build_status_code(self, status_code: str) -> dict:
    method __get_comparator_and_callback (line 241) | def __get_comparator_and_callback(self,
    method __instance_comparator (line 281) | def __instance_comparator(
    method __build_comparator (line 310) | def __build_comparator(self,

FILE: src/fuzzingtool/core/payloader.py
  class EncodeManager (line 30) | class EncodeManager:
    method __init__ (line 37) | def __init__(self):
    method __len__ (line 41) | def __len__(self) -> int:
    method encode (line 44) | def encode(self, ajusted_payloads: List[Payload]) -> List[Payload]:
    method set_regex (line 53) | def set_regex(self, regex: str = '') -> None:
    method set_encoders (line 64) | def set_encoders(self,
    method _encode (line 85) | def _encode(self, encoder: BaseEncoder, payload: str) -> str:
  class Payloader (line 134) | class Payloader:
    method case (line 147) | def case(ajusted_payloads: List[Payload]) -> List[Payload]:
    method set_prefix (line 157) | def set_prefix(prefix: List[str]) -> None:
    method set_suffix (line 166) | def set_suffix(suffix: List[str]) -> None:
    method set_uppercase (line 175) | def set_uppercase() -> None:
    method set_lowercase (line 186) | def set_lowercase() -> None:
    method set_capitalize (line 197) | def set_capitalize() -> None:
    method get_customized_payload (line 208) | def get_customized_payload(payload: Payload) -> List[Payload]:

FILE: src/fuzzingtool/core/plugins/encoders/base64.py
  class Base64 (line 29) | class Base64(BaseEncoder, Plugin):
    method encode (line 36) | def encode(self, payload: str) -> str:
    method decode (line 39) | def decode(self, payload: str) -> str:

FILE: src/fuzzingtool/core/plugins/encoders/hex.py
  class Hex (line 27) | class Hex(BaseEncoder, Plugin):
    method encode (line 34) | def encode(self, payload: str) -> str:
    method decode (line 37) | def decode(self, payload: str) -> str:

FILE: src/fuzzingtool/core/plugins/encoders/html.py
  class Html (line 29) | class Html(BaseEncoder, Plugin):
    method encode (line 36) | def encode(self, payload: str) -> str:
    method decode (line 39) | def decode(self, payload: str) -> str:

FILE: src/fuzzingtool/core/plugins/encoders/html_dec.py
  class HtmlDec (line 27) | class HtmlDec(BaseEncoder, Plugin):
    method encode (line 34) | def encode(self, payload: str) -> str:

FILE: src/fuzzingtool/core/plugins/encoders/html_hex.py
  class HtmlHex (line 27) | class HtmlHex(BaseEncoder, Plugin):
    method encode (line 34) | def encode(self, payload: str) -> str:

FILE: src/fuzzingtool/core/plugins/encoders/plain.py
  class Plain (line 27) | class Plain(BaseEncoder, Plugin):
    method encode (line 34) | def encode(self, payload: str) -> str:

FILE: src/fuzzingtool/core/plugins/encoders/url.py
  class Url (line 30) | class Url(BaseEncoder, Plugin):
    method __init__ (line 40) | def __init__(self, encode_level: int):
    method encode (line 50) | def encode(self, payload: str) -> str:
    method decode (line 56) | def decode(self, payload: str) -> str:

FILE: src/fuzzingtool/core/plugins/scanners/backups.py
  class Backups (line 31) | class Backups(BaseScanner, Plugin):
    method __init__ (line 47) | def __init__(self, extensions: list):
    method scan (line 51) | def scan(self, result: Result) -> bool:
    method _process (line 54) | def _process(self, result: Result) -> None:

FILE: src/fuzzingtool/core/plugins/scanners/grep.py
  class Grep (line 38) | class Grep(BaseScanner, Plugin):
    method __init__ (line 55) | def __init__(self, regexes: list):
    method scan (line 68) | def scan(self, result: Result) -> bool:
    method _process (line 71) | def _process(self, result: Result) -> None:

FILE: src/fuzzingtool/core/plugins/scanners/reflected.py
  class Reflected (line 28) | class Reflected(BaseScanner, Plugin):
    method scan (line 35) | def scan(self, result: Result) -> bool:

FILE: src/fuzzingtool/core/plugins/scanners/wappalyzer.py
  class Wappalyzer (line 32) | class Wappalyzer(BaseScanner, Plugin):
    method __init__ (line 39) | def __init__(self):
    method scan (line 43) | def scan(self, result: Result) -> bool:
    method _process (line 46) | def _process(self, result: Result) -> None:

FILE: src/fuzzingtool/core/plugins/wordlists/crt_sh.py
  class CrtSh (line 46) | class CrtSh(BaseWordlist, Plugin):
    method __init__ (line 56) | def __init__(self, host: str):
    method _build (line 62) | def _build(self) -> List[str]:
    method __get_response_json (line 70) | def __get_response_json(self) -> List[dict]:
    method __get_domain_list (line 87) | def __get_domain_list(self, response_json: List[dict]) -> List[str]:

FILE: src/fuzzingtool/core/plugins/wordlists/dns_dumpster.py
  class DnsDumpster (line 47) | class DnsDumpster(BaseWordlist, Plugin):
    method __init__ (line 57) | def __init__(self, host: str):
    method _build (line 63) | def _build(self) -> List[str]:

FILE: src/fuzzingtool/core/plugins/wordlists/dns_zone.py
  class DnsZone (line 34) | class DnsZone(BaseWordlist, Plugin):
    method __init__ (line 44) | def __init__(self, host: str):
    method _build (line 50) | def _build(self) -> List[str]:
    method __do_dns_transfer (line 73) | def __do_dns_transfer(self, ip: str) -> List[str]:

FILE: src/fuzzingtool/core/plugins/wordlists/overflow.py
  class Overflow (line 30) | class Overflow(BaseWordlist, Plugin):
    method __init__ (line 40) | def __init__(self, source_param: str):
    method _build (line 68) | def _build(self) -> List[str]:

FILE: src/fuzzingtool/core/plugins/wordlists/robots.py
  class Robots (line 41) | class Robots(BaseWordlist, Plugin):
    method __init__ (line 51) | def __init__(self, url: str):
    method _build (line 59) | def _build(self) -> List[str]:

FILE: src/fuzzingtool/core/recursion_manager.py
  class RecursionManager (line 28) | class RecursionManager(JobProvider):
    method __init__ (line 37) | def __init__(self, max_rlevel: int, wordlist: List[str]):
    method notify (line 51) | def notify(self, result: Result, path: str) -> None:
    method has_recursive_job (line 61) | def has_recursive_job(self) -> bool:
    method check_for_recursion (line 68) | def check_for_recursion(self, result: Result) -> None:
    method fill_payloads_queue (line 82) | def fill_payloads_queue(self) -> None:

FILE: src/fuzzingtool/core/summary.py
  class Summary (line 24) | class Summary:
    method __init__ (line 32) | def __init__(self):
    method start_timer (line 37) | def start_timer(self) -> None:
    method stop_timer (line 41) | def stop_timer(self) -> None:
    method pause_timer (line 47) | def pause_timer(self) -> None:
    method resume_timer (line 51) | def resume_timer(self) -> None:

FILE: src/fuzzingtool/decorators/plugin_meta.py
  function plugin_meta (line 26) | def plugin_meta(cls: Plugin) -> Plugin:
  function _check_mandatory_meta (line 52) | def _check_mandatory_meta(cls: Plugin) -> None:
  function _check_params_meta (line 68) | def _check_params_meta(cls: Plugin) -> None:

FILE: src/fuzzingtool/decorators/report_meta.py
  function report_meta (line 25) | def report_meta(cls: BaseReport) -> BaseReport:

FILE: src/fuzzingtool/exceptions/base_exceptions.py
  class FuzzingToolException (line 21) | class FuzzingToolException(Exception):

FILE: src/fuzzingtool/exceptions/main_exceptions.py
  class FuzzLibException (line 24) | class FuzzLibException(FuzzingToolException):
  class StopActionInterrupt (line 28) | class StopActionInterrupt(FuzzingToolException):
  class BuildWordlistFails (line 32) | class BuildWordlistFails(FuzzingToolException):
  class WordlistCreationError (line 36) | class WordlistCreationError(FuzzingToolException):
  class MetadataException (line 40) | class MetadataException(FuzzingToolException):

FILE: src/fuzzingtool/exceptions/param_exceptions.py
  class MissingParameter (line 24) | class MissingParameter(FuzzingToolException):
  class BadArgumentFormat (line 28) | class BadArgumentFormat(FuzzingToolException):
  class BadArgumentType (line 32) | class BadArgumentType(FuzzingToolException):
  class InvalidArgument (line 36) | class InvalidArgument(FuzzingToolException):

FILE: src/fuzzingtool/exceptions/plugin_exceptions.py
  class InvalidPluginCategory (line 24) | class InvalidPluginCategory(FuzzingToolException):
  class InvalidPlugin (line 28) | class InvalidPlugin(FuzzingToolException):
  class PluginCreationError (line 32) | class PluginCreationError(FuzzingToolException):

FILE: src/fuzzingtool/exceptions/request_exceptions.py
  class RequestException (line 24) | class RequestException(FuzzingToolException):
  class InvalidHostname (line 28) | class InvalidHostname(FuzzingToolException):

FILE: src/fuzzingtool/factories/base_factories.py
  class BasePluginFactory (line 24) | class BasePluginFactory(ABC):
    method get_plugins_from_category (line 27) | def get_plugins_from_category(category: str):
    method class_creator (line 38) | def class_creator(name: str, category: str):
    method object_creator (line 51) | def object_creator(name: str, category: str, params):
  class BaseWordlistFactory (line 65) | class BaseWordlistFactory(ABC):
    method creator (line 68) | def creator(name: str, params: str, requester):

FILE: src/fuzzingtool/factories/plugin_factory.py
  class PluginFactory (line 34) | class PluginFactory(BasePluginFactory):
    method get_plugins_from_category (line 43) | def get_plugins_from_category(category: str) -> List[Type[Plugin]]:
    method class_creator (line 57) | def class_creator(category: str, name: str) -> Type[Plugin]:
    method object_creator (line 69) | def object_creator(category: str, name: str, params) -> Plugin:

FILE: src/fuzzingtool/factories/wordlist_factory.py
  class WordlistFactory (line 32) | class WordlistFactory(BaseWordlistFactory):
    method creator (line 34) | def creator(name: str, params: str, requester: Requester) -> BaseWordl...

FILE: src/fuzzingtool/fuzz_lib.py
  class FuzzLib (line 47) | class FuzzLib:
    method __init__ (line 48) | def __init__(self, **kwargs):
    method main (line 64) | def main(self) -> None:
    method init (line 71) | def init(self) -> None:
    method start (line 84) | def start(self) -> None:
    method _stop_callback (line 99) | def _stop_callback(self, status: int) -> None:
    method _wait_callback (line 107) | def _wait_callback(self, status: int) -> None:
    method _result_callback (line 119) | def _result_callback(self, result: Result, valid: bool) -> None:
    method _request_exception_callback (line 129) | def _request_exception_callback(self, error: Error) -> None:
    method _invalid_hostname_callback (line 137) | def _invalid_hostname_callback(self, error: Error) -> None:
    method _init_requester (line 145) | def _init_requester(self) -> None:
    method _init_filter (line 176) | def _init_filter(self) -> None:
    method _init_matcher (line 183) | def _init_matcher(self) -> None:
    method _init_scanners (line 197) | def _init_scanners(self) -> None:
    method _init_other_arguments (line 211) | def _init_other_arguments(self) -> None:
    method _init_dictionary (line 231) | def _init_dictionary(self) -> None:
    method _init_managers (line 247) | def _init_managers(self) -> None:
    method _set_observer (line 262) | def _set_observer(self) -> None:
    method _get_job (line 268) | def _get_job(self) -> None:
    method _join (line 273) | def _join(self) -> None:
    method _check_for_new_jobs (line 280) | def _check_for_new_jobs(self) -> None:
    method __get_default_args (line 286) | def __get_default_args(self) -> dict:
    method __build_encoders (line 339) | def __build_encoders(self) -> Tuple[List[BaseEncoder], List[List[BaseE...
    method __configure_payloader (line 366) | def __configure_payloader(self) -> None:
    method __build_wordlist (line 381) | def __build_wordlist(self,
    method __get_default_scanner (line 415) | def __get_default_scanner(self) -> BaseScanner:
    method __fuzz (line 426) | def __fuzz(self) -> None:
    method __handle_response (line 442) | def __handle_response(self,
    method __is_valid (line 464) | def __is_valid(self, result: Result) -> bool:
    method __handle_result (line 478) | def __handle_result(self, result: Result) -> bool:

FILE: src/fuzzingtool/fuzzingtool.py
  function main_cli (line 27) | def main_cli() -> None:

FILE: src/fuzzingtool/interfaces/cli/cli_arguments.py
  class CliArguments (line 34) | class CliArguments(argparse.ArgumentParser):
    method __init__ (line 39) | def __init__(self, args: List[str] = None):
    method error (line 75) | def error(self, message: str) -> None:
    method get_arguments (line 78) | def get_arguments(self) -> argparse.Namespace:
    method _show_wordlists_help (line 85) | def _show_wordlists_help(self) -> None:
    method _show_encoders_help (line 96) | def _show_encoders_help(self) -> None:
    method _show_scanners_help (line 103) | def _show_scanners_help(self) -> None:
    method __show_plugins_help_from_category (line 115) | def __show_plugins_help_from_category(self, category: str) -> None:
    method __build_options (line 137) | def __build_options(self) -> None:
    method __build_target_opts (line 152) | def __build_target_opts(self) -> None:
    method __build_request_opts (line 170) | def __build_request_opts(self) -> None:
    method __build_dictionary_opts (line 232) | def __build_dictionary_opts(self) -> None:
    method __build_match_opts (line 301) | def __build_match_opts(self) -> None:
    method __build_display_opts (line 369) | def __build_display_opts(self) -> None:
    method __build_report_opts (line 401) | def __build_report_opts(self) -> None:
    method __build_more_opts (line 434) | def __build_more_opts(self) -> None:

FILE: src/fuzzingtool/interfaces/cli/cli_controller.py
  function banner (line 37) | def banner() -> str:
  class CliController (line 53) | class CliController(FuzzLib):
    method __init__ (line 61) | def __init__(self, arguments: Namespace):
    method is_verbose_mode (line 67) | def is_verbose_mode(self) -> bool:
    method main (line 74) | def main(self) -> None:
    method init (line 98) | def init(self) -> None:
    method print_configs (line 109) | def print_configs(self) -> None:
    method check_connection (line 122) | def check_connection(self) -> None:
    method start (line 139) | def start(self) -> None:
    method prepare (line 150) | def prepare(self) -> None:
    method check_ignore_errors (line 162) | def check_ignore_errors(self) -> None:
    method show_footer (line 176) | def show_footer(self) -> None:
    method _wait_callback (line 192) | def _wait_callback(self, status: int) -> None:
    method _result_callback (line 206) | def _result_callback(self, result: Result, valid: bool) -> None:
    method _request_exception_callback (line 219) | def _request_exception_callback(self, error: Error) -> None:
    method _invalid_hostname_callback (line 233) | def _invalid_hostname_callback(self, error: Error) -> None:
    method _init_dictionary (line 242) | def _init_dictionary(self) -> None:
    method _get_job (line 250) | def _get_job(self) -> None:
    method _join (line 254) | def _join(self) -> None:
    method _handle_pause (line 263) | def _handle_pause(self) -> None:
    method _handle_quit (line 288) | def _handle_quit(self) -> None:
    method _handle_progress (line 292) | def _handle_progress(self) -> None:
    method _handle_continue (line 299) | def _handle_continue(self) -> None:
    method _handle_skip (line 304) | def _handle_skip(self) -> None:
    method __init_report (line 309) | def __init_report(self) -> None:
    method __get_comparator_value (line 316) | def __get_comparator_value(self,
    method __get_data_comparator (line 336) | def __get_data_comparator(self) -> tuple:
    method __print_progress (line 371) | def __print_progress(self, index: int, payload: str) -> None:
    method __handle_valid_results (line 386) | def __handle_valid_results(self,

FILE: src/fuzzingtool/interfaces/cli/cli_output.py
  class Colors (line 35) | class Colors:
    method disable (line 52) | def disable() -> None:
  class CliOutput (line 69) | class CliOutput:
    method print (line 84) | def print(msg: str) -> None:
    method help_title (line 93) | def help_title(num_spaces: int, title: str) -> None:
    method help_content (line 104) | def help_content(num_spaces: int, command: str, desc: str) -> None:
    method __init__ (line 128) | def __init__(self):
    method set_simple_output_mode (line 138) | def set_simple_output_mode(self) -> None:
    method set_new_job (line 151) | def set_new_job(self, total_requests: int) -> None:
    method info_box (line 163) | def info_box(self, msg: str) -> None:
    method error_box (line 171) | def error_box(self, msg: str) -> None:
    method warning_box (line 179) | def warning_box(self, msg: str) -> None:
    method abort_box (line 189) | def abort_box(self, msg: str) -> None:
    method worked_box (line 199) | def worked_box(self, msg: str) -> None:
    method not_worked_box (line 207) | def not_worked_box(self, msg: str) -> None:
    method ask_yes_no (line 216) | def ask_yes_no(self, ask_type: str, msg: str) -> bool:
    method ask_data (line 235) | def ask_data(self, msg: str) -> str:
    method print_config (line 245) | def print_config(self, key: str, value: str = '', spaces: int = 0) -> ...
    method print_configs (line 258) | def print_configs(self,
    method get_percentage (line 284) | def get_percentage(self, item_index: int) -> str:
    method progress_status (line 293) | def progress_status(self,
    method print_result (line 325) | def print_result(self, result: Result, vuln_validator: bool) -> None:
    method _get_break (line 343) | def _get_break(self) -> str:
    method _get_percentage_value (line 353) | def _get_percentage_value(self, item_index: int, total_requests: int) ...
    method _get_progress_bar (line 364) | def _get_progress_bar(self, percentage_value: int) -> str:
    method __get_time (line 377) | def __get_time(self) -> str:
    method __get_info (line 386) | def __get_info(self, msg: str) -> str:
    method __get_warning (line 395) | def __get_warning(self, msg: str) -> str:
    method __get_error (line 404) | def __get_error(self, msg: str) -> str:
    method __get_abort (line 413) | def __get_abort(self, msg: str) -> str:
    method __get_worked (line 422) | def __get_worked(self, msg: str) -> str:
    method __get_not_worked (line 431) | def __get_not_worked(self, msg: str) -> str:
    method __erase_line (line 440) | def __erase_line(self) -> None:
    method __get_formatted_payload (line 447) | def __get_formatted_payload(self, result: Result) -> str:
    method __get_formatted_status (line 463) | def __get_formatted_status(self, status: int) -> str:
    method __get_formatted_result_items (line 486) | def __get_formatted_result_items(self, result: Result) -> Tuple[
    method __get_formatted_result (line 501) | def __get_formatted_result(self, result: Result) -> str:

FILE: src/fuzzingtool/objects/base_objects.py
  class BaseItem (line 25) | class BaseItem(ABC):
    method reset_index (line 35) | def reset_index() -> None:
    method __init__ (line 40) | def __init__(self):

FILE: src/fuzzingtool/objects/error.py
  class Error (line 26) | class Error(BaseItem):
    method __init__ (line 33) | def __init__(self, e: FuzzingToolException, payload: Payload):
    method __str__ (line 45) | def __str__(self) -> str:

FILE: src/fuzzingtool/objects/fuzz_word.py
  class FuzzWord (line 25) | class FuzzWord:
    method __init__ (line 33) | def __init__(self, word: str = FUZZING_MARK):
    method __hash__ (line 43) | def __hash__(self) -> int:
    method __eq__ (line 46) | def __eq__(self, other: object) -> bool:
    method get_payloaded_word (line 49) | def get_payloaded_word(self, payload: str) -> str:

FILE: src/fuzzingtool/objects/http_history.py
  class HttpHistory (line 26) | class HttpHistory:
    method __init__ (line 38) | def __init__(self, response: Response, rtt: float = 0.0, *ip):
    method parsed_url (line 55) | def parsed_url(self) -> UrlParse:
    method is_path (line 59) | def is_path(self) -> bool:
    method raw_headers (line 67) | def raw_headers(self) -> str:
    method headers_length (line 71) | def headers_length(self) -> int:
    method response_time (line 75) | def response_time(self) -> float:
    method request_time (line 79) | def request_time(self) -> float:
    method request (line 83) | def request(self) -> PreparedRequest:
    method response (line 91) | def response(self) -> Response:

FILE: src/fuzzingtool/objects/payload.py
  class Payload (line 24) | class Payload:
    method __init__ (line 33) | def __init__(self, payload: str = ''):
    method __str__ (line 44) | def __str__(self) -> str:
    method update (line 47) | def update(self, other: 'Payload') -> 'Payload':
    method with_prefix (line 60) | def with_prefix(self, prefix: str) -> 'Payload':
    method with_suffix (line 71) | def with_suffix(self, suffix: str) -> 'Payload':
    method with_case (line 82) | def with_case(self, case_callback: Callable, case_method: str) -> 'Pay...
    method with_encoder (line 95) | def with_encoder(self, encoded: str, encoder: str) -> 'Payload':
    method with_recursion (line 108) | def with_recursion(self, payload: str) -> 'Payload':

FILE: src/fuzzingtool/objects/result.py
  class Result (line 30) | class Result(BaseItem):
    method __init__ (line 45) | def __init__(self,
    method __str__ (line 69) | def __str__(self) -> str:
    method __iter__ (line 85) | def __iter__(self) -> Iterator[Tuple]:
    method get_description (line 112) | def get_description(self) -> str:

FILE: src/fuzzingtool/objects/scanner_result.py
  class ScannerResult (line 21) | class ScannerResult:
    method __init__ (line 29) | def __init__(self, scanner_name: str):

FILE: src/fuzzingtool/persistence/base_report.py
  class BaseReport (line 29) | class BaseReport(ABC):
    method __init__ (line 36) | def __init__(self, filename: str = ''):
    method open (line 45) | def open(self, host: str) -> str:
    method write (line 63) | def write(self, results: List[Result]) -> None:
    method file_extension (line 77) | def file_extension(self) -> str:
    method _header (line 82) | def _header(self) -> None:
    method _results (line 87) | def _results(self, results: List[Result]) -> None:
    method _footer (line 96) | def _footer(self) -> None:

FILE: src/fuzzingtool/persistence/logger.py
  class Logger (line 27) | class Logger:
    method __init__ (line 33) | def __init__(self):
    method setup (line 36) | def setup(self, host: str) -> str:
    method write (line 58) | def write(self, exception: str, payload: str) -> None:

FILE: src/fuzzingtool/persistence/report.py
  function get_report_name_and_type (line 30) | def get_report_name_and_type(name: str) -> Tuple[str, str]:
  class Report (line 44) | class Report:
    method get_available_reports (line 47) | def get_available_reports() -> Dict[str, Type[BaseReport]]:
    method build (line 57) | def build(name: str) -> BaseReport:

FILE: src/fuzzingtool/persistence/reports/csv_report.py
  class CsvReport (line 30) | class CsvReport(BaseReport):
    method _header (line 36) | def _header(self) -> None:
    method _results (line 40) | def _results(self, results: List[Result]) -> None:
    method _footer (line 49) | def _footer(self) -> None:

FILE: src/fuzzingtool/persistence/reports/json_report.py
  class JsonReport (line 30) | class JsonReport(BaseReport):
    method _header (line 36) | def _header(self) -> None:
    method _results (line 40) | def _results(self, results: List[Result]) -> None:
    method _footer (line 43) | def _footer(self) -> None:

FILE: src/fuzzingtool/persistence/reports/txt_report.py
  class TxtReport (line 29) | class TxtReport(BaseReport):
    method _header (line 35) | def _header(self) -> None:
    method _results (line 39) | def _results(self, results: List[Result]) -> None:
    method _footer (line 45) | def _footer(self) -> None:

FILE: src/fuzzingtool/utils/argument_utils.py
  function build_target_from_args (line 30) | def build_target_from_args(url: str, method: str, body: str) -> dict:
  function build_target_from_raw_http (line 54) | def build_target_from_raw_http(raw_http_filename: str, scheme: str) -> d...
  function build_wordlist (line 103) | def build_wordlist(wordlists: str) -> List[Tuple[str, str]]:
  function build_encoder (line 116) | def build_encoder(encoders: str) -> List[List[Tuple[str, str]]]:
  function build_scanner (line 130) | def build_scanner(scanner: str) -> Tuple[str, str]:
  function build_verbose_mode (line 140) | def build_verbose_mode(is_common: bool, is_detailed: bool) -> List[bool]:
  function build_blacklist_status (line 157) | def build_blacklist_status(blacklist_status: str) -> Tuple[str, str, str]:

FILE: src/fuzzingtool/utils/consts.py
  class PluginCategory (line 24) | class PluginCategory:
  class FuzzType (line 30) | class FuzzType:

FILE: src/fuzzingtool/utils/file_utils.py
  function read_file (line 24) | def read_file(file_name: str) -> List[str]:

FILE: src/fuzzingtool/utils/http_utils.py
  function get_url_without_scheme (line 29) | def get_url_without_scheme(url: str) -> str:
  function get_pure_url (line 41) | def get_pure_url(url: str) -> str:
  function build_raw_response_header (line 55) | def build_raw_response_header(response: Response) -> str:
  class UrlParse (line 70) | class UrlParse(ParseResult):
    method file (line 73) | def file(self) -> str:
    method file_name (line 81) | def file_name(self) -> str:
    method file_ext (line 89) | def file_ext(self) -> str:
  function get_parsed_url (line 97) | def get_parsed_url(url: str) -> UrlParse:

FILE: src/fuzzingtool/utils/result_utils.py
  class ResultUtils (line 28) | class ResultUtils:
    method get_formatted_result (line 32) | def get_formatted_result(payload: str,
    method format_custom_field (line 62) | def format_custom_field(custom_field, force_detailed: bool = False) ->...

FILE: src/fuzzingtool/utils/utils.py
  function get_indexes_to_parse (line 26) | def get_indexes_to_parse(content: str,
  function split_str_to_list (line 40) | def split_str_to_list(string: str,
  function stringfy_list (line 75) | def stringfy_list(one_list: list) -> str:
  function parse_option_with_args (line 91) | def parse_option_with_args(option: str) -> Tuple[str, str]:
  function get_human_length (line 105) | def get_human_length(length: int) -> Tuple[Union[int, float], str]:
  function get_formatted_rtt (line 120) | def get_formatted_rtt(rtt: float) -> Tuple[Union[int, float], str]:
  function fix_payload_to_output (line 136) | def fix_payload_to_output(payload: str) -> str:
  function check_range_list (line 150) | def check_range_list(content: str) -> List[Union[int, str]]:
  function _get_letter_range (line 176) | def _get_letter_range(left: str, right: str) -> List[str]:
  function _get_number_range (line 201) | def _get_number_range(left: str, right: str) -> List[int]:

FILE: tests/conn/requesters/test_requester.py
  class TestRequester (line 14) | class TestRequester(unittest.TestCase):
    method test_setup_url (line 15) | def test_setup_url(self):
    method test_setup_url_without_scheme (line 27) | def test_setup_url_without_scheme(self):
    method test_setup_url_without_directory (line 39) | def test_setup_url_without_directory(self):
    method test_setup_url_with_params (line 51) | def test_setup_url_with_params(self):
    method test_build_data_dict_with_blank_data (line 63) | def test_build_data_dict_with_blank_data(self):
    method test_build_data_dict_with_key_and_without_value (line 70) | def test_build_data_dict_with_key_and_without_value(self):
    method test_build_data_dict_with_key_and_value (line 81) | def test_build_data_dict_with_key_and_value(self):
    method test_build_data_dict_with_multiple_key_and_value (line 92) | def test_build_data_dict_with_multiple_key_and_value(self):
    method test_setup_header_with_blank_header (line 105) | def test_setup_header_with_blank_header(self):
    method test_setup_header_with_filled_header (line 117) | def test_setup_header_with_filled_header(self):
    method test_setup_proxy (line 133) | def test_setup_proxy(self):
    method test_get_request_parameters (line 143) | def test_get_request_parameters(self):
    method test_set_fuzzing_type_for_method_fuzzing (line 153) | def test_set_fuzzing_type_for_method_fuzzing(self):
    method test_set_fuzzing_type_for_path_fuzzing (line 163) | def test_set_fuzzing_type_for_path_fuzzing(self):
    method test_set_fuzzing_type_for_data_fuzzing_on_url_params (line 173) | def test_set_fuzzing_type_for_data_fuzzing_on_url_params(self):
    method test_set_fuzzing_type_for_data_fuzzing_on_body (line 183) | def test_set_fuzzing_type_for_data_fuzzing_on_body(self):
    method test_set_fuzzing_type_for_data_fuzzing_on_headers (line 193) | def test_set_fuzzing_type_for_data_fuzzing_on_headers(self):
    method test_set_fuzzing_type_for_unknown_fuzzing (line 205) | def test_set_fuzzing_type_for_unknown_fuzzing(self):
    method test_constructor_with_cookie (line 211) | def test_constructor_with_cookie(self):
    method test_get_url (line 218) | def test_get_url(self):
    method test_get_method (line 225) | def test_get_method(self):
    method test_set_method (line 231) | def test_set_method(self):
    method test_set_body (line 239) | def test_set_body(self):
    method test_test_connection_with_raise_exception (line 251) | def test_test_connection_with_raise_exception(self, mock_get: Mock):
    method test_request (line 282) | def test_request(self, mock_request: Mock, mock_time: Mock, mock_get_p...
    method test_request_with_replay_proxy (line 304) | def test_request_with_replay_proxy(self, mock_request: Mock, mock_get_...
    method test_request_with_raise_exception (line 318) | def test_request_with_raise_exception(self, mock_request: Mock):

FILE: tests/conn/requesters/test_subdomain_requester.py
  class TestRequester (line 12) | class TestRequester(unittest.TestCase):
    method test_resolve_hostname (line 14) | def test_resolve_hostname(self, mock_gethostbyname: Mock):
    method test_resolve_hostname_with_raise_exception (line 23) | def test_resolve_hostname_with_raise_exception(self, mock_gethostbynam...
    method test_request (line 31) | def test_request(self,
    method test_set_fuzzing_type (line 49) | def test_set_fuzzing_type(self):

FILE: tests/conn/test_request_parser.py
  class TestRequestParser (line 8) | class TestRequestParser(unittest.TestCase):
    method test_check_is_subdomain_fuzzing (line 9) | def test_check_is_subdomain_fuzzing(self):
    method test_check_is_url_discovery (line 16) | def test_check_is_url_discovery(self):
    method test_check_is_not_url_discovery (line 23) | def test_check_is_not_url_discovery(self):
    method test_check_is_data_fuzzing_on_url_params (line 30) | def test_check_is_data_fuzzing_on_url_params(self):
    method test_check_is_data_fuzzing_on_body (line 45) | def test_check_is_data_fuzzing_on_body(self):
    method test_check_is_data_fuzzing_on_header (line 60) | def test_check_is_data_fuzzing_on_header(self):
    method test_get_method (line 69) | def test_get_method(self):
    method test_get_url (line 78) | def test_get_url(self):
    method test_get_header (line 87) | def test_get_header(self):
    method test_get_data (line 103) | def test_get_data(self):

FILE: tests/core/test_blacklist_status.py
  class TestBlacklistStatus (line 7) | class TestBlacklistStatus(unittest.TestCase):
    method test_build_status_list (line 8) | def test_build_status_list(self):
    method test_build_status_list_with_invalid_status_type (line 14) | def test_build_status_list_with_invalid_status_type(self):

FILE: tests/core/test_filter.py
  class TestFilter (line 9) | class TestFilter(unittest.TestCase):
    method test_build_status_codes (line 10) | def test_build_status_codes(self):
    method test_build_status_codes_with_invalid_status_type (line 17) | def test_build_status_codes_with_invalid_status_type(self):
    method test_build_regexer_with_invalid_regex (line 23) | def test_build_regexer_with_invalid_regex(self):
    method test_check_with_found_status (line 29) | def test_check_with_found_status(self):
    method test_check_with_found_regex (line 39) | def test_check_with_found_regex(self):
    method test_check_with_not_found (line 48) | def test_check_with_not_found(self):

FILE: tests/core/test_job_manager.py
  class TestJobManager (line 10) | class TestJobManager(unittest.TestCase):
    method test_update (line 11) | def test_update(self):
    method test_get_job (line 23) | def test_get_job(self):
    method test_has_pending_jobs (line 33) | def test_has_pending_jobs(self):
    method test_has_pending_jobs_from_providers_without_job (line 43) | def test_has_pending_jobs_from_providers_without_job(self):
    method test_has_pending_jobs_from_providers_with_job (line 52) | def test_has_pending_jobs_from_providers_with_job(self):
    method test_check_for_new_jobs (line 62) | def test_check_for_new_jobs(self):

FILE: tests/core/test_matcher.py
  class TestMatcher (line 11) | class TestMatcher(unittest.TestCase):
    method test_build_status_code_without_status (line 12) | def test_build_status_code_without_status(self):
    method test_build_status_code_with_list_and_range (line 22) | def test_build_status_code_with_list_and_range(self):
    method test_build_status_code_with_inverted_range (line 32) | def test_build_status_code_with_inverted_range(self):
    method test_build_status_code_with_invalid_status_type (line 42) | def test_build_status_code_with_invalid_status_type(self):
    method test_build_regexer_with_invalid_regex (line 48) | def test_build_regexer_with_invalid_regex(self):
    method test_get_comparator_and_callback_with_operator_ge (line 54) | def test_get_comparator_and_callback_with_operator_ge(self):
    method test_get_comparator_and_callback_with_operator_le (line 60) | def test_get_comparator_and_callback_with_operator_le(self):
    method test_get_comparator_and_callback_with_operator_gt (line 66) | def test_get_comparator_and_callback_with_operator_gt(self):
    method test_get_comparator_and_callback_with_operator_lt (line 72) | def test_get_comparator_and_callback_with_operator_lt(self):
    method test_get_comparator_and_callback_with_operator_eq (line 78) | def test_get_comparator_and_callback_with_operator_eq(self):
    method test_get_comparator_and_callback_with_operator_ne (line 84) | def test_get_comparator_and_callback_with_operator_ne(self):
    method test_get_comparator_and_callback_without_operator (line 90) | def test_get_comparator_and_callback_without_operator(self):
    method test_instance_comparator (line 96) | def test_instance_comparator(self):
    method test_instance_comparator_with_invalid_integer (line 102) | def test_instance_comparator_with_invalid_integer(self):
    method test_instance_comparator_with_invalid_number (line 109) | def test_instance_comparator_with_invalid_number(self):
    method test_build_comparator (line 116) | def test_build_comparator(self):
    method test_comparator_is_set_with_set (line 137) | def test_comparator_is_set_with_set(self):
    method test_comparator_is_set_without_set (line 143) | def test_comparator_is_set_without_set(self):
    method test_set_status_code (line 150) | def test_set_status_code(self, mock_build_status_code: Mock):
    method test_set_comparator (line 156) | def test_set_comparator(self, mock_build_comparator: Mock):
    method test_match_with_match (line 161) | def test_match_with_match(self):
    method test_match_status_without_match (line 170) | def test_match_status_without_match(self):
    method test_match_time_without_match (line 179) | def test_match_time_without_match(self):
    method test_match_size_without_match (line 189) | def test_match_size_without_match(self):
    method test_match_words_without_match (line 199) | def test_match_words_without_match(self):
    method test_match_lines_without_match (line 209) | def test_match_lines_without_match(self):
    method test_match_regex_without_match (line 219) | def test_match_regex_without_match(self):
    method test_not_match_with_two_configs (line 229) | def test_not_match_with_two_configs(self):

FILE: tests/core/test_payloader.py
  function assert_payload_list_is_equal (line 10) | def assert_payload_list_is_equal(payloads: List[Payload], other_payloads...
  class TestEncodeManager (line 20) | class TestEncodeManager(unittest.TestCase):
    method test_set_regex_with_invalid_regex (line 21) | def test_set_regex_with_invalid_regex(self):
    method test_encode_without_regex (line 27) | def test_encode_without_regex(self):
    method test_encode_with_regex_without_regex_match (line 34) | def test_encode_with_regex_without_regex_match(self):
    method test_encode_with_regex_with_regex_match (line 43) | def test_encode_with_regex_with_regex_match(self):
    method test_set_encoder (line 52) | def test_set_encoder(self):
  class TestPayloader (line 62) | class TestPayloader(unittest.TestCase):
    method tearDown (line 63) | def tearDown(self):
    method test_get_customized_payload_without_mutation (line 68) | def test_get_customized_payload_without_mutation(self):
    method test_get_customized_payload_with_prefix (line 75) | def test_get_customized_payload_with_prefix(self):
    method test_get_customized_payload_with_suffix (line 87) | def test_get_customized_payload_with_suffix(self):
    method test_get_customized_payload_with_upper (line 99) | def test_get_customized_payload_with_upper(self):
    method test_get_customized_payload_with_lower (line 107) | def test_get_customized_payload_with_lower(self):
    method test_get_customized_payload_with_capitalize (line 115) | def test_get_customized_payload_with_capitalize(self):

FILE: tests/core/test_recursion_manager.py
  class TestRecursionManager (line 9) | class TestRecursionManager(unittest.TestCase):
    method setUp (line 10) | def setUp(self):
    method test_notify (line 16) | def test_notify(self):
    method test_has_recursive_job (line 25) | def test_has_recursive_job(self):
    method test_check_for_recursion_with_recursion (line 31) | def test_check_for_recursion_with_recursion(self, mock_notify: Mock):
    method test_fill_payloads_queue (line 42) | def test_fill_payloads_queue(self):

FILE: tests/decorators/test_plugin_meta.py
  class TestPluginMeta (line 7) | class TestPluginMeta(unittest.TestCase):
    method test_mandatory_meta_without_any_meta (line 8) | def test_mandatory_meta_without_any_meta(self):
    method test_mandatory_meta_without_version (line 15) | def test_mandatory_meta_without_version(self):
    method test_blank_meta_on_author (line 25) | def test_blank_meta_on_author(self):
    method test_blank_meta_on_desc (line 36) | def test_blank_meta_on_desc(self):
    method test_blank_meta_on_version (line 47) | def test_blank_meta_on_version(self):
    method test_param_meta_is_not_dict (line 58) | def test_param_meta_is_not_dict(self):
    method test_param_meta_without_key_type (line 69) | def test_param_meta_without_key_type(self):
    method test_param_meta_without_value_type (line 82) | def test_param_meta_without_value_type(self):
    method test_param_meta_list_without_separator (line 96) | def test_param_meta_list_without_separator(self):
    method test_param_meta_list_with_blank_separator (line 110) | def test_param_meta_list_with_blank_separator(self):
    method test_invalid_fuzz_type (line 125) | def test_invalid_fuzz_type(self):

FILE: tests/factories/test_plugin_factory.py
  class TestPluginFactory (line 10) | class TestPluginFactory(unittest.TestCase):
    method test_get_plugins_from_category (line 11) | def test_get_plugins_from_category(self):
    method test_get_plugins_from_category_with_invalid_category (line 19) | def test_get_plugins_from_category_with_invalid_category(self):
    method test_class_creator (line 26) | def test_class_creator(self,
    method test_class_creator_with_invalid_plugin (line 45) | def test_class_creator_with_invalid_plugin(self, mock_import_module: M...
    method test_object_creator_with_invalid_plugin (line 53) | def test_object_creator_with_invalid_plugin(self, mock_class_creator: ...
    method test_object_creator_with_params (line 62) | def test_object_creator_with_params(self, mock_class_creator: Mock):
    method test_object_creator_without_params (line 71) | def test_object_creator_without_params(self, mock_class_creator: Mock):
    method test_object_creator_with_blank_params (line 80) | def test_object_creator_with_blank_params(self, mock_class_creator: Mo...
    method test_object_creator_with_invalid_params (line 89) | def test_object_creator_with_invalid_params(self, mock_class_creator: ...

FILE: tests/factories/test_wordlist_factory.py
  class TestWordlistFactory (line 13) | class TestWordlistFactory(unittest.TestCase):
    method test_creator_with_list (line 15) | def test_creator_with_list(self, mock_plugin_class_creator: Mock):
    method test_creator_with_file (line 23) | def test_creator_with_file(self, mock_plugin_class_creator: Mock):
    method test_creator_with_plugin_and_params (line 32) | def test_creator_with_plugin_and_params(
    method test_creator_with_path_fuzzing_plugin_and_requester (line 50) | def test_creator_with_path_fuzzing_plugin_and_requester(
    method test_creator_with_subdomain_fuzzing_plugin_and_requester (line 77) | def test_creator_with_subdomain_fuzzing_plugin_and_requester(
    method test_creator_with_raise_plugin_exception (line 105) | def test_creator_with_raise_plugin_exception(

FILE: tests/interfaces/cli/test_cli_arguments.py
  class TestCliArguments (line 9) | class TestCliArguments(unittest.TestCase):
    method test_invalid_args (line 11) | def test_invalid_args(self):
    method test_help (line 16) | def test_help(self):
    method test_encoders_help (line 20) | def test_encoders_help(self):
    method test_scanners_help (line 25) | def test_scanners_help(self):
    method test_wordlists_help (line 30) | def test_wordlists_help(self):
    method test_invalid_help_type (line 35) | def test_invalid_help_type(self):
    method test_args (line 40) | def test_args(self):

FILE: tests/interfaces/cli/test_cli_output.py
  class TestCliOutput (line 11) | class TestCliOutput(unittest.TestCase):
    method test_get_time (line 13) | def test_get_time(self, mock_datetime: Mock):
    method test_get_info (line 23) | def test_get_info(self):
    method test_get_warning (line 31) | def test_get_warning(self):
    method test_get_error (line 39) | def test_get_error(self):
    method test_get_abort (line 47) | def test_get_abort(self):
    method test_get_worked (line 55) | def test_get_worked(self):
    method test_get_not_worked (line 63) | def test_get_not_worked(self):
    method test_get_formatted_payload (line 71) | def test_get_formatted_payload(self):
    method test_get_formatted_payload_with_path_fuzz (line 80) | def test_get_formatted_payload_with_path_fuzz(self):
    method test_get_formatted_payload_with_path_fuzz_without_directory (line 89) | def test_get_formatted_payload_with_path_fuzz_without_directory(self):
    method test_get_formatted_payload_with_subdomain_fuzz (line 99) | def test_get_formatted_payload_with_subdomain_fuzz(self):
    method test_get_formatted_status_with_status_404 (line 108) | def test_get_formatted_status_with_status_404(self):
    method test_get_formatted_status_with_status_200 (line 116) | def test_get_formatted_status_with_status_200(self):
    method test_get_formatted_status_with_status_300 (line 124) | def test_get_formatted_status_with_status_300(self):
    method test_get_formatted_status_with_status_400 (line 132) | def test_get_formatted_status_with_status_400(self):
    method test_get_formatted_status_with_status_403 (line 140) | def test_get_formatted_status_with_status_403(self):
    method test_get_formatted_status_with_status_500 (line 148) | def test_get_formatted_status_with_status_500(self):
    method test_get_formatted_result_items (line 158) | def test_get_formatted_result_items(self, mock_format_result: Mock, mo...
    method test_get_formatted_result (line 181) | def test_get_formatted_result(self, mock_format_items: Mock):

FILE: tests/mock_utils/args_decorator.py
  function mock_sys_args (line 5) | def mock_sys_args(sys_args):

FILE: tests/mock_utils/response_mock.py
  class ResponseMock (line 8) | class ResponseMock(Mock):
    method __init__ (line 9) | def __init__(self):

FILE: tests/mock_utils/wordlist_mock.py
  class WordlistMock (line 5) | class WordlistMock(BaseWordlist):
    method __init__ (line 6) | def __init__(self, test_arg: str):
    method _build (line 12) | def _build(self):

FILE: tests/objects/test_error.py
  class TestError (line 8) | class TestError(unittest.TestCase):
    method setUp (line 9) | def setUp(self):
    method tearDown (line 12) | def tearDown(self):
    method test_error (line 15) | def test_error(self):

FILE: tests/objects/test_fuzz_word.py
  class TestPayload (line 7) | class TestPayload(unittest.TestCase):
    method test_get_payloaded_word_without_fuzzing (line 8) | def test_get_payloaded_word_without_fuzzing(self):
    method test_get_payloaded_word_with_fuzzing (line 17) | def test_get_payloaded_word_with_fuzzing(self):

FILE: tests/objects/test_http_history.py
  class TestHttpHistory (line 9) | class TestHttpHistory(unittest.TestCase):
    method test_http_history (line 10) | def test_http_history(self):
    method test_http_history_with_ip (line 24) | def test_http_history_with_ip(self):
    method test_headers (line 30) | def test_headers(self, mock_build_raw_response_header: Mock):

FILE: tests/objects/test_payload.py
  class TestPayload (line 6) | class TestPayload(unittest.TestCase):
    method test_str (line 7) | def test_str(self):
    method test_update (line 12) | def test_update(self):
    method test_with_prefix (line 21) | def test_with_prefix(self):
    method test_with_suffix (line 31) | def test_with_suffix(self):
    method test_with_case (line 41) | def test_with_case(self):
    method test_with_encoder (line 54) | def test_with_encoder(self):
    method test_with_recursion (line 67) | def test_with_recursion(self):

FILE: tests/objects/test_result.py
  class TestResult (line 10) | class TestResult(unittest.TestCase):
    method setUp (line 11) | def setUp(self):
    method tearDown (line 14) | def tearDown(self):
    method test_result (line 17) | def test_result(self):
    method test_get_description (line 26) | def test_get_description(self):
    method test_result_str (line 48) | def test_result_str(self):
    method test_result_iter (line 68) | def test_result_iter(self):

FILE: tests/persistence/test_logger.py
  class TestLogger (line 10) | class TestLogger(unittest.TestCase):
    method setUp (line 11) | def setUp(self):
    method test_setup (line 19) | def test_setup(self, mock_file: Mock, mock_date: Mock):
    method test_setup_with_path_mkdir (line 30) | def test_setup_with_path_mkdir(self, mock_date: Mock):
    method test_write (line 42) | def test_write(self, mock_file: Mock, mock_date: Mock):

FILE: tests/persistence/test_report.py
  class TestReport (line 12) | class TestReport(unittest.TestCase):
    method test_get_report_name_and_type_with_full_name (line 13) | def test_get_report_name_and_type_with_full_name(self):
    method test_get_report_name_and_type_with_only_extension (line 21) | def test_get_report_name_and_type_with_only_extension(self, mock_datet...
    method test_get_available_reports (line 30) | def test_get_available_reports(self):
    method test_build (line 38) | def test_build(self, mock_get_available_reports: Mock):
    method test_build_with_invalid_format (line 45) | def test_build_with_invalid_format(self, mock_get_available_reports: M...

FILE: tests/test_fuzz_lib.py
  class TestFuzzController (line 14) | class TestFuzzController(unittest.TestCase):
    method test_init_requester_with_common_requester (line 15) | def test_init_requester_with_common_requester(self):
    method test_init_requester_with_subdomain_requester (line 21) | def test_init_requester_with_subdomain_requester(self):
    method test_init_requester_with_raw_http (line 28) | def test_init_requester_with_raw_http(
    method test_init_requester_with_raise_exception (line 47) | def test_init_requester_with_raise_exception(self):
    method test_init_matcher (line 53) | def test_init_matcher(self, mock_set_status_code: Mock):
    method test_get_default_scanner_with_path_scanner (line 59) | def test_get_default_scanner_with_path_scanner(self):
    method test_get_default_scanner_with_subdomain_scanner (line 65) | def test_get_default_scanner_with_subdomain_scanner(self):
    method test_get_default_scanner_with_data_scanner (line 71) | def test_get_default_scanner_with_data_scanner(self):
    method test_init_scanners_with_plugin_scanner (line 78) | def test_init_scanners_with_plugin_scanner(self, mock_object_creator: ...
    method test_init_scanners_with_default_scanner (line 86) | def test_init_scanners_with_default_scanner(self, mock_get_default_sca...
    method test_build_encoders_with_encoders (line 91) | def test_build_encoders_with_encoders(self, mock_object_creator: Mock):
    method test_build_encoders_with_chain_encoders (line 100) | def test_build_encoders_with_chain_encoders(self, mock_object_creator:...
    method test_build_encoders_with_encode_only (line 110) | def test_build_encoders_with_encode_only(self,
    method test_configure_payloader_with_prefix (line 119) | def test_configure_payloader_with_prefix(self, mock_set_prefix: Mock):
    method test_configure_payloader_with_suffix (line 124) | def test_configure_payloader_with_suffix(self, mock_set_suffix: Mock):
    method test_configure_payloader_with_lowercase (line 129) | def test_configure_payloader_with_lowercase(self, mock_set_lowercase: ...
    method test_configure_payloader_with_uppercase (line 134) | def test_configure_payloader_with_uppercase(self, mock_set_uppercase: ...
    method test_configure_payloader_with_capitalize (line 139) | def test_configure_payloader_with_capitalize(self, mock_set_capitalize...
    method test_configure_payloader_with_encoders (line 145) | def test_configure_payloader_with_encoders(self,
    method test_build_wordlist (line 154) | def test_build_wordlist(self, mock_creator: Mock):
    method test_build_wordlist_with_blank_wordlist (line 165) | def test_build_wordlist_with_blank_wordlist(self, mock_creator: Mock):
    method test_init_dictionary (line 173) | def test_init_dictionary(self, mock_build_wordlist: Mock):

FILE: tests/utils/test_argument_utils.py
  class TestArgumentUtils (line 7) | class TestArgumentUtils(unittest.TestCase):
    method test_build_target_from_args (line 8) | def test_build_target_from_args(self):
    method test_build_target_from_args_without_method_and_without_body (line 22) | def test_build_target_from_args_without_method_and_without_body(self):
    method test_build_target_from_args_without_method_and_with_body (line 36) | def test_build_target_from_args_without_method_and_with_body(self):
    method test_build_target_from_raw_http (line 51) | def test_build_target_from_raw_http(self, mock_read_file: Mock):
    method test_build_target_from_raw_http_with_body (line 76) | def test_build_target_from_raw_http_with_body(self, mock_read_file: Mo...
    method test_build_wordlist (line 103) | def test_build_wordlist(self):
    method test_build_encoder (line 109) | def test_build_encoder(self):
    method test_build_scanner (line 115) | def test_build_scanner(self):
    method test_build_verbose_mode_without_verbose (line 121) | def test_build_verbose_mode_without_verbose(self):
    method test_build_verbose_mode_with_common_verbose (line 127) | def test_build_verbose_mode_with_common_verbose(self):
    method test_build_verbose_mode_with_detailed_verbose (line 133) | def test_build_verbose_mode_with_detailed_verbose(self):
    method test_build_blacklist_status_without_action (line 139) | def test_build_blacklist_status_without_action(self):
    method test_build_blacklist_status_with_action (line 145) | def test_build_blacklist_status_with_action(self):
    method test_build_blacklist_status_with_action_and_param (line 151) | def test_build_blacklist_status_with_action_and_param(self):

FILE: tests/utils/test_file_utils.py
  class TestFileUtils (line 10) | class TestFileUtils(unittest.TestCase):
    method test_read_file (line 12) | def test_read_file(self, mock_file: Mock):
    method test_read_file_with_comment (line 23) | def test_read_file_with_comment(self, mock_file: Mock):
    method test_read_file_exception (line 32) | def test_read_file_exception(self):

FILE: tests/utils/test_http_utils.py
  class TestHttpUtils (line 7) | class TestHttpUtils(unittest.TestCase):
    method test_get_url_without_scheme_without_scheme (line 8) | def test_get_url_without_scheme_without_scheme(self):
    method test_get_url_without_scheme_with_scheme (line 15) | def test_get_url_without_scheme_with_scheme(self):
    method test_get_pure_url_without_mark (line 22) | def test_get_pure_url_without_mark(self):
    method test_get_pure_url_with_mark (line 29) | def test_get_pure_url_with_mark(self):
    method test_get_pure_url_with_mark_and_dot (line 36) | def test_get_pure_url_with_mark_and_dot(self):
    method test_build_raw_response_header (line 43) | def test_build_raw_response_header(self):
    method test_urlparse_file (line 58) | def test_urlparse_file(self):
    method test_urlparse_file_name (line 65) | def test_urlparse_file_name(self):
    method test_urlparse_file_ext (line 72) | def test_urlparse_file_ext(self):

FILE: tests/utils/test_result_utils.py
  class TestResultUtils (line 7) | class TestResultUtils(unittest.TestCase):
    method tearDown (line 8) | def tearDown(self):
    method test_get_formatted_result_with_only_int (line 11) | def test_get_formatted_result_with_only_int(self):
    method test_get_formatted_result_with_rtt_float (line 32) | def test_get_formatted_result_with_rtt_float(self):
    method test_get_formatted_result_with_length_float (line 53) | def test_get_formatted_result_with_length_float(self):
    method test_format_custom_field (line 74) | def test_format_custom_field(self):
    method test_format_custom_field_with_detailed_list (line 80) | def test_format_custom_field_with_detailed_list(self):
    method test_format_custom_field_with_list (line 86) | def test_format_custom_field_with_list(self):

FILE: tests/utils/test_utils.py
  class TestUtils (line 9) | class TestUtils(unittest.TestCase):
    method test_get_indexes_to_parse_without_mark (line 10) | def test_get_indexes_to_parse_without_mark(self):
    method test_get_indexes_to_parse_with_one_mark (line 17) | def test_get_indexes_to_parse_with_one_mark(self):
    method test_get_indexes_to_parse_with_two_marks (line 24) | def test_get_indexes_to_parse_with_two_marks(self):
    method test_split_str_to_list_with_blank_string (line 31) | def test_split_str_to_list_with_blank_string(self):
    method test_split_str_to_list_without_separator (line 38) | def test_split_str_to_list_without_separator(self):
    method test_split_str_to_list_with_one_separator (line 45) | def test_split_str_to_list_with_one_separator(self):
    method test_split_str_to_list_with_two_separators (line 52) | def test_split_str_to_list_with_two_separators(self):
    method test_split_str_to_list_with_one_separator_and_ignorer (line 59) | def test_split_str_to_list_with_one_separator_and_ignorer(self):
    method test_split_str_to_list_with_two_separators_and_ignorer (line 66) | def test_split_str_to_list_with_two_separators_and_ignorer(self):
    method test_split_str_to_list_with_one_separator_and_ignorer_with_blank_result (line 73) | def test_split_str_to_list_with_one_separator_and_ignorer_with_blank_r...
    method test_stringfy_list_with_empty_list (line 80) | def test_stringfy_list_with_empty_list(self):
    method test_stringfy_list_with_filled_list (line 87) | def test_stringfy_list_with_filled_list(self):
    method test_get_human_length_with_zero_bytes (line 94) | def test_get_human_length_with_zero_bytes(self):
    method test_get_human_length_with_float_return (line 101) | def test_get_human_length_with_float_return(self):
    method test_get_human_length_with_one_tb (line 108) | def test_get_human_length_with_one_tb(self):
    method test_get_formatted_rtt_with_milliseconds (line 115) | def test_get_formatted_rtt_with_milliseconds(self):
    method test_get_formatted_rtt_with_seconds (line 122) | def test_get_formatted_rtt_with_seconds(self):
    method test_get_formatted_rtt_with_minutes (line 129) | def test_get_formatted_rtt_with_minutes(self):
    method test_get_formatted_rtt_with_hour (line 136) | def test_get_formatted_rtt_with_hour(self):
    method test_fix_payload_to_output_with_tab (line 143) | def test_fix_payload_to_output_with_tab(self):
    method test_fix_payload_to_output_with_large_payload (line 149) | def test_fix_payload_to_output_with_large_payload(self):
    method test_get_letter_range (line 155) | def test_get_letter_range(self):
    method test_get_letter_range_reversed (line 162) | def test_get_letter_range_reversed(self):
    method test_get_letter_range_inside_text (line 169) | def test_get_letter_range_inside_text(self):
    method test_get_number_range (line 176) | def test_get_number_range(self):
    method test_get_number_range_reversed (line 183) | def test_get_number_range_reversed(self):
    method test_get_number_range_inside_text (line 190) | def test_get_number_range_inside_text(self):
    method test_check_range_list_without_range (line 200) | def test_check_range_list_without_range(self):
    method test_check_range_list_with_range_ignorer (line 207) | def test_check_range_list_with_range_ignorer(self):
    method test_check_range_list_with_invalid_range (line 214) | def test_check_range_list_with_invalid_range(self):
    method test_check_range_list_with_letter_range (line 222) | def test_check_range_list_with_letter_range(self, mock_get_letter_rang...
    method test_check_range_list_with_letter_range_inside_text (line 232) | def test_check_range_list_with_letter_range_inside_text(self,
    method test_check_range_list_with_number_range (line 243) | def test_check_range_list_with_number_range(self, mock_get_number_rang...
    method test_check_range_list_with_number_range_inside_text (line 253) | def test_check_range_list_with_number_range_inside_text(self,
Condensed preview — 157 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (3,686K chars).
[
  {
    "path": ".github/CODE_OF_CONDUCT.md",
    "chars": 3189,
    "preview": "# Contributor Covenant Code of Conduct\n## Our Pledge\nIn the interest of fostering an open and welcoming environment, we "
  },
  {
    "path": ".github/CONTRIBUTING.md",
    "chars": 3226,
    "preview": "# Contributing\nBefore contribute to the FuzzingTool project, please read our [Code of Conduct](https://github.com/NESCAU"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/BUG_REPORT.md",
    "chars": 619,
    "preview": "---\nname: BUG REPORT\nabout: Report a bug\ntitle: ''\nlabels: bug\nassignees: ''\n\n---\n\n## Bug reporting\n**Description**: A c"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/FEATURE_REQUEST.md",
    "chars": 278,
    "preview": "---\nname: FEATURE REQUEST\nabout: Request a feature\ntitle: ''\nlabels: enhancement\nassignees: ''\n\n---\n\n## Feature request\n"
  },
  {
    "path": ".github/workflows/cd.yml",
    "chars": 484,
    "preview": "name: delivery\n\non:\n  release:\n    types: [published]\n\njobs:\n  pypi_upload:\n    runs-on: ubuntu-latest\n    steps:\n      "
  },
  {
    "path": ".github/workflows/ci.yml",
    "chars": 514,
    "preview": "name: integration\n\non: push\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v2\n    "
  },
  {
    "path": ".github/workflows/quality.yml",
    "chars": 1347,
    "preview": "name: code quality\n\non:\n  push:\n    branches:\n      - master\n  pull_request:\n    branches:\n      - develop\n      - maste"
  },
  {
    "path": ".github/workflows/sast.yml",
    "chars": 404,
    "preview": "name: sast\n\non: push\n\njobs:\n  bandit:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@master\n      "
  },
  {
    "path": ".github/workflows/sca.yml",
    "chars": 269,
    "preview": "name: sca\n\non: push\n\njobs:\n  snyk:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@master\n      - n"
  },
  {
    "path": ".gitignore",
    "chars": 247,
    "preview": "# Pycache\n__pycache__/\n\n# Distribution / packaging\n.Python\nenv/\nbuild/\ndevelop-eggs/\ndist/\ndownloads/\neggs/\nlib/\nlib64/\n"
  },
  {
    "path": "CONTRIBUTORS.md",
    "chars": 130,
    "preview": "## Contributors\n * <a target=\"_blank\" href=\"https://www.linkedin.com/in/gmprestes/\"><b>Gabriel Prestes</b></a>: Designed"
  },
  {
    "path": "LICENSE",
    "chars": 1077,
    "preview": "MIT License\n\nCopyright (c) 2020 - present Vitor Oriel\n\nPermission is hereby granted, free of charge, to any person obtai"
  },
  {
    "path": "README.md",
    "chars": 3113,
    "preview": "<p align=\"center\">\n <img src=\"https://user-images.githubusercontent.com/43549176/110254984-525fb200-7f70-11eb-84f0-9afdc"
  },
  {
    "path": "requirements.txt",
    "chars": 517,
    "preview": "#\n# This file is autogenerated by pip-compile\n# To update, run:\n#\n#    pip-compile --output-file=requirements.txt setup."
  },
  {
    "path": "setup.py",
    "chars": 1559,
    "preview": "import os\nfrom setuptools import setup, find_packages\n\nfrom src.fuzzingtool import __version__\n\n\ndef read(fname):\n    re"
  },
  {
    "path": "src/fuzzingtool/__init__.py",
    "chars": 1426,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/api.py",
    "chars": 1470,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/conn/__init__.py",
    "chars": 1188,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/conn/request_parser.py",
    "chars": 4427,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/conn/requesters/__init__.py",
    "chars": 1217,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/conn/requesters/requester.py",
    "chars": 15899,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/conn/requesters/subdomain_requester.py",
    "chars": 2421,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/core/__init__.py",
    "chars": 1488,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/core/bases/__init__.py",
    "chars": 1249,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/core/bases/base_encoder.py",
    "chars": 1557,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/core/bases/base_observer.py",
    "chars": 1582,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/core/bases/base_plugin.py",
    "chars": 1232,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/core/bases/base_scanner.py",
    "chars": 3566,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/core/bases/base_validator.py",
    "chars": 2064,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/core/bases/base_wordlist.py",
    "chars": 1861,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/core/bases/job_provider.py",
    "chars": 1784,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/core/blacklist_status.py",
    "chars": 4248,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/core/defaults/__init__.py",
    "chars": 1205,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/core/defaults/encoders/__init__.py",
    "chars": 1172,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/core/defaults/encoders/chain_encoder.py",
    "chars": 2088,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/core/defaults/scanners/__init__.py",
    "chars": 1256,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/core/defaults/scanners/data_scanner.py",
    "chars": 1478,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/core/defaults/scanners/path_scanner.py",
    "chars": 1632,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/core/defaults/scanners/subdomain_scanner.py",
    "chars": 1355,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/core/defaults/wordlists/__init__.py",
    "chars": 1212,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/core/defaults/wordlists/file_wordlist.py",
    "chars": 1657,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/core/defaults/wordlists/list_wordlist.py",
    "chars": 1704,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/core/dictionary.py",
    "chars": 3583,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/core/filter.py",
    "chars": 2966,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/core/fuzzer.py",
    "chars": 6203,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/core/job_manager.py",
    "chars": 4485,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/core/matcher.py",
    "chars": 13275,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/core/payloader.py",
    "chars": 8104,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/core/plugins/__init__.py",
    "chars": 1205,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/core/plugins/encoders/__init__.py",
    "chars": 1309,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/core/plugins/encoders/base64.py",
    "chars": 1740,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/core/plugins/encoders/hex.py",
    "chars": 1673,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/core/plugins/encoders/html.py",
    "chars": 1651,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/core/plugins/encoders/html_dec.py",
    "chars": 1626,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/core/plugins/encoders/html_hex.py",
    "chars": 1635,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/core/plugins/encoders/plain.py",
    "chars": 1527,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/core/plugins/encoders/url.py",
    "chars": 2382,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/core/plugins/scanners/__init__.py",
    "chars": 1252,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/core/plugins/scanners/backups.py",
    "chars": 2470,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/core/plugins/scanners/grep.py",
    "chars": 3142,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/core/plugins/scanners/reflected.py",
    "chars": 1640,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/core/plugins/scanners/wappalyzer.py",
    "chars": 2319,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/core/plugins/wordlists/__init__.py",
    "chars": 1284,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/core/plugins/wordlists/crt_sh.py",
    "chars": 4040,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/core/plugins/wordlists/dns_dumpster.py",
    "chars": 3980,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/core/plugins/wordlists/dns_zone.py",
    "chars": 3459,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/core/plugins/wordlists/overflow.py",
    "chars": 3068,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/core/plugins/wordlists/robots.py",
    "chars": 3175,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/core/recursion_manager.py",
    "chars": 3593,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/core/summary.py",
    "chars": 2107,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/decorators/__init__.py",
    "chars": 1131,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/decorators/plugin_meta.py",
    "chars": 4016,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/decorators/report_meta.py",
    "chars": 1926,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/exceptions/__init__.py",
    "chars": 1230,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/exceptions/base_exceptions.py",
    "chars": 1181,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/exceptions/main_exceptions.py",
    "chars": 1479,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/exceptions/param_exceptions.py",
    "chars": 1410,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/exceptions/plugin_exceptions.py",
    "chars": 1359,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/exceptions/request_exceptions.py",
    "chars": 1296,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/factories/__init__.py",
    "chars": 1220,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/factories/base_factories.py",
    "chars": 2837,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/factories/plugin_factory.py",
    "chars": 3664,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/factories/wordlist_factory.py",
    "chars": 2872,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/fuzz_lib.py",
    "chars": 18507,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/fuzzingtool.py",
    "chars": 1569,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/interfaces/__init__.py",
    "chars": 1131,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/interfaces/cli/__init__.py",
    "chars": 1132,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/interfaces/cli/cli_arguments.py",
    "chars": 17713,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/interfaces/cli/cli_controller.py",
    "chars": 16258,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/interfaces/cli/cli_output.py",
    "chars": 19518,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/objects/__init__.py",
    "chars": 1329,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/objects/base_objects.py",
    "chars": 1599,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/objects/error.py",
    "chars": 1914,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/objects/fuzz_word.py",
    "chars": 2557,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/objects/http_history.py",
    "chars": 3393,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/objects/payload.py",
    "chars": 4163,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/objects/result.py",
    "chars": 5198,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/objects/scanner_result.py",
    "chars": 1693,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/persistence/__init__.py",
    "chars": 1187,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/persistence/base_report.py",
    "chars": 3304,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/persistence/logger.py",
    "chars": 2753,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/persistence/report.py",
    "chars": 2902,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/persistence/reports/__init__.py",
    "chars": 1236,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/persistence/reports/csv_report.py",
    "chars": 1880,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/persistence/reports/json_report.py",
    "chars": 1716,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/persistence/reports/txt_report.py",
    "chars": 1797,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/utils/__init__.py",
    "chars": 1131,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/utils/argument_utils.py",
    "chars": 5930,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/utils/consts.py",
    "chars": 1811,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/utils/file_utils.py",
    "chars": 1651,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/utils/http_utils.py",
    "chars": 3400,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/utils/result_utils.py",
    "chars": 3102,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool/utils/utils.py",
    "chars": 7756,
    "preview": "# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "src/fuzzingtool.py",
    "chars": 1241,
    "preview": "#!/usr/bin/python3\n\n# Copyright (c) 2020 - present Vitor Oriel <https://github.com/VitorOriel>\n#\n# Permission is hereby "
  },
  {
    "path": "tests/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/conn/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/conn/requesters/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/conn/requesters/test_requester.py",
    "chars": 17687,
    "preview": "import unittest\nfrom unittest.mock import Mock, patch\n\nimport requests\n\nfrom src.fuzzingtool.conn.requesters.requester i"
  },
  {
    "path": "tests/conn/requesters/test_subdomain_requester.py",
    "chars": 2586,
    "preview": "import unittest\nfrom unittest.mock import Mock, patch\n\nimport socket\nfrom requests.models import Response\n\nfrom src.fuzz"
  },
  {
    "path": "tests/conn/test_request_parser.py",
    "chars": 4522,
    "preview": "import unittest\n\nfrom src.fuzzingtool.conn.request_parser import *\nfrom src.fuzzingtool.objects.fuzz_word import FuzzWor"
  },
  {
    "path": "tests/core/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/core/test_blacklist_status.py",
    "chars": 759,
    "preview": "import unittest\n\nfrom src.fuzzingtool.core.blacklist_status import BlacklistStatus\nfrom src.fuzzingtool.exceptions impor"
  },
  {
    "path": "tests/core/test_filter.py",
    "chars": 2331,
    "preview": "import unittest\n\nfrom src.fuzzingtool.core.filter import Filter\nfrom src.fuzzingtool.objects.result import Result, HttpH"
  },
  {
    "path": "tests/core/test_job_manager.py",
    "chars": 2829,
    "preview": "import unittest\nfrom queue import Queue\n\nfrom src.fuzzingtool.core.job_manager import JobManager\nfrom src.fuzzingtool.co"
  },
  {
    "path": "tests/core/test_matcher.py",
    "chars": 10200,
    "preview": "import unittest\nfrom unittest.mock import Mock, patch\nimport operator\n\nfrom src.fuzzingtool.core.matcher import Matcher\n"
  },
  {
    "path": "tests/core/test_payloader.py",
    "chars": 5700,
    "preview": "import unittest\nfrom typing import List\n\nfrom src.fuzzingtool.core.payloader import Payloader, EncodeManager\nfrom src.fu"
  },
  {
    "path": "tests/core/test_recursion_manager.py",
    "chars": 2427,
    "preview": "import unittest\nfrom unittest.mock import Mock, patch\n\nfrom src.fuzzingtool.core.recursion_manager import RecursionManag"
  },
  {
    "path": "tests/decorators/test_plugin_meta.py",
    "chars": 5420,
    "preview": "import unittest\n\nfrom src.fuzzingtool.decorators.plugin_meta import plugin_meta\nfrom src.fuzzingtool.exceptions import M"
  },
  {
    "path": "tests/factories/test_plugin_factory.py",
    "chars": 4713,
    "preview": "import unittest\nfrom unittest.mock import Mock, patch\n\nfrom src.fuzzingtool.utils.consts import PluginCategory\nfrom src."
  },
  {
    "path": "tests/factories/test_wordlist_factory.py",
    "chars": 6261,
    "preview": "import unittest\nfrom unittest.mock import Mock, patch\n\nfrom src.fuzzingtool.factories.wordlist_factory import WordlistFa"
  },
  {
    "path": "tests/interfaces/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/interfaces/cli/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/interfaces/cli/test_cli_arguments.py",
    "chars": 1275,
    "preview": "import unittest\nfrom argparse import Namespace\n\nfrom src.fuzzingtool.interfaces.cli.cli_arguments import CliArguments\nfr"
  },
  {
    "path": "tests/interfaces/cli/test_cli_output.py",
    "chars": 9890,
    "preview": "import unittest\nfrom unittest.mock import Mock, patch\nfrom datetime import datetime\n\nfrom src.fuzzingtool.interfaces.cli"
  },
  {
    "path": "tests/mock_utils/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/mock_utils/args_decorator.py",
    "chars": 305,
    "preview": "import sys\nfrom unittest.mock import patch\n\n\ndef mock_sys_args(sys_args):\n    sys_args = ['FuzzingTool'] + sys_args\n\n   "
  },
  {
    "path": "tests/mock_utils/response_mock.py",
    "chars": 1049,
    "preview": "from unittest.mock import Mock\nimport datetime\n\nfrom requests.models import PreparedRequest, Response\nfrom urllib3 impor"
  },
  {
    "path": "tests/mock_utils/wordlist_mock.py",
    "chars": 478,
    "preview": "from src.fuzzingtool.core.bases.base_wordlist import BaseWordlist\nfrom src.fuzzingtool.exceptions import WordlistCreatio"
  },
  {
    "path": "tests/objects/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/objects/test_error.py",
    "chars": 646,
    "preview": "import unittest\n\nfrom src.fuzzingtool.exceptions.request_exceptions import RequestException\nfrom src.fuzzingtool.objects"
  },
  {
    "path": "tests/objects/test_fuzz_word.py",
    "chars": 940,
    "preview": "import unittest\n\nfrom src.fuzzingtool.objects.fuzz_word import FuzzWord\nfrom src.fuzzingtool.utils.consts import FUZZING"
  },
  {
    "path": "tests/objects/test_http_history.py",
    "chars": 1927,
    "preview": "import unittest\nfrom unittest.mock import Mock, patch\n\nfrom src.fuzzingtool.objects.http_history import HttpHistory\nfrom"
  },
  {
    "path": "tests/objects/test_payload.py",
    "chars": 3335,
    "preview": "import unittest\n\nfrom src.fuzzingtool.objects.payload import Payload\n\n\nclass TestPayload(unittest.TestCase):\n    def tes"
  },
  {
    "path": "tests/objects/test_result.py",
    "chars": 3976,
    "preview": "import unittest\nfrom unittest.mock import Mock, patch\n\nfrom src.fuzzingtool.objects import Payload, Result, HttpHistory,"
  },
  {
    "path": "tests/persistence/test_logger.py",
    "chars": 2458,
    "preview": "import unittest\nfrom unittest.mock import Mock, patch, mock_open\nfrom datetime import datetime\nfrom pathlib import Path\n"
  },
  {
    "path": "tests/persistence/test_report.py",
    "chars": 2331,
    "preview": "import unittest\nfrom unittest.mock import Mock, patch\nfrom datetime import datetime\n\nfrom src.fuzzingtool.persistence im"
  },
  {
    "path": "tests/test_fuzz_lib.py",
    "chars": 9212,
    "preview": "import unittest\nfrom unittest.mock import Mock, patch\n\nfrom src.fuzzingtool.fuzz_lib import FuzzLib\nfrom src.fuzzingtool"
  },
  {
    "path": "tests/utils/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/utils/test_argument_utils.py",
    "chars": 6248,
    "preview": "import unittest\nfrom unittest.mock import patch, Mock\n\nfrom src.fuzzingtool.utils.argument_utils import *\n\n\nclass TestAr"
  },
  {
    "path": "tests/utils/test_file_utils.py",
    "chars": 1479,
    "preview": "import unittest\nfrom unittest.mock import Mock, patch, mock_open\n\nfrom src.fuzzingtool.utils.file_utils import read_file"
  },
  {
    "path": "tests/utils/test_http_utils.py",
    "chars": 3244,
    "preview": "import unittest\n\nfrom src.fuzzingtool.utils.http_utils import *\nfrom ..mock_utils.response_mock import ResponseMock\n\n\ncl"
  },
  {
    "path": "tests/utils/test_result_utils.py",
    "chars": 3330,
    "preview": "import unittest\n\nfrom src.fuzzingtool.utils.consts import MAX_PAYLOAD_LENGTH_TO_OUTPUT\nfrom src.fuzzingtool.utils.result"
  },
  {
    "path": "tests/utils/test_utils.py",
    "chars": 11649,
    "preview": "import unittest\nfrom unittest.mock import Mock, patch\n\nfrom src.fuzzingtool.utils.utils import *\nfrom src.fuzzingtool.ut"
  },
  {
    "path": "wordlists/enumeration/paths.txt",
    "chars": 68187,
    "preview": "#! Paths wordlist\n#! v0.1\n#! Contributors:\n#!  Vitor Oriel\n#!\n!.gitignore\n!.htaccess\n!.htpasswd\n%20../\n%2e%2e//google.co"
  },
  {
    "path": "wordlists/enumeration/subdomains.txt",
    "chars": 2702617,
    "preview": "#! Subdomains wordlist\n#! v0.1\n#! Contributors:\n#!  Vitor Oriel\n#!\n\\\\\n~0\n0\n00\n000\n0000\n00000\n000000\n0000000\n00000000\n000"
  },
  {
    "path": "wordlists/injection/sqli.txt",
    "chars": 74613,
    "preview": "#! SQLi wordlist\n#! v0.1\n#! Contributors:\n#!  Vitor Oriel\n#!\nfunction(){ return this.userid}\n' function(){ return this.u"
  },
  {
    "path": "wordlists/injection/xss.txt",
    "chars": 74982,
    "preview": "#! XSS wordlist\n#! v0.1\n#! Contributors:\n#!  Vitor Oriel\n#!\n<!--\n>\"'\n_\n/*-/*`/*`/*'/*\"/**/\n/*-/*`/*\\`/*'/*\"/**/\n'\n\"\n&#00"
  }
]

About this extraction

This page contains the full source code of the NESCAU-UFLA/FuzzingTool GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 157 files (3.2 MB), approximately 854.3k tokens, and a symbol index with 761 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!