├── .circleci └── config.yml ├── .coveragerc ├── .github ├── FUNDING.yml └── workflows │ ├── codacy.yml │ └── dependency-review.yml ├── .gitignore ├── .readthedocs.yaml ├── CHANGELOG.md ├── LICENSE ├── MANIFEST.in ├── README.md ├── VERSION ├── data ├── directories.dat ├── ignored.dat ├── proxies.dat ├── subdomains.dat └── useragents.dat ├── docs ├── Changelog.md ├── Contribution.md ├── Installation-and-update.md ├── License.md ├── Sniffers.md ├── Testing.md ├── Usage.md ├── Wizard.md ├── img │ ├── dependencies.jpg │ ├── favicon.ico │ ├── lgpl.jpg │ ├── open-door.png │ └── usage.jpg ├── index.md └── requirements.txt ├── mkdocs.yml ├── opendoor.conf ├── opendoor.py ├── requirements-dev.txt ├── requirements.txt ├── setup.py ├── src ├── __init__.py ├── controller.py ├── core │ ├── __init__.py │ ├── color │ │ ├── __init__.py │ │ └── color.py │ ├── core.py │ ├── decorators │ │ ├── __init__.py │ │ └── timer.py │ ├── filesystem │ │ ├── __init__.py │ │ ├── exceptions.py │ │ └── filesystem.py │ ├── helper │ │ ├── __init__.py │ │ └── helper.py │ ├── http │ │ ├── __init__.py │ │ ├── exceptions.py │ │ ├── http.py │ │ ├── https.py │ │ ├── plugins │ │ │ ├── __init__.py │ │ │ ├── exceptions.py │ │ │ ├── response │ │ │ │ ├── __init__.py │ │ │ │ ├── collation.py │ │ │ │ ├── file.py │ │ │ │ ├── indexof.py │ │ │ │ ├── provider │ │ │ │ │ ├── __init__.py │ │ │ │ │ └── provider.py │ │ │ │ ├── skipempty.py │ │ │ │ └── skipsizes.py │ │ │ └── response_plugin.py │ │ ├── providers │ │ │ ├── __init__.py │ │ │ ├── accept.py │ │ │ ├── cache.py │ │ │ ├── connection.py │ │ │ ├── cookies.py │ │ │ ├── debug.py │ │ │ ├── header.py │ │ │ ├── request.py │ │ │ ├── response.py │ │ │ └── user_agent.py │ │ ├── proxy.py │ │ ├── response.py │ │ └── socks.py │ ├── logger │ │ ├── __init__.py │ │ ├── colorize.py │ │ ├── config.py │ │ ├── exception.py │ │ ├── logger.py │ │ └── rainbow.py │ ├── options │ │ ├── __init__.py │ │ ├── exceptions.py │ │ ├── filter.py │ │ └── options.py │ └── system │ │ ├── __init__.py │ │ ├── exceptions.py │ │ ├── output.py │ │ ├── process.py │ │ └── terminal.py ├── exceptions.py └── lib │ ├── __init__.py │ ├── browser │ ├── __init__.py │ ├── browser.py │ ├── config.py │ ├── debug.py │ ├── exceptions.py │ ├── filter.py │ ├── threadpool.py │ └── worker.py │ ├── events │ ├── __init__.py │ └── events.py │ ├── io │ ├── __init__.py │ ├── arguments.py │ └── exceptions.py │ ├── package │ ├── __init__.py │ ├── exceptions.py │ └── package.py │ ├── reader │ ├── __init__.py │ ├── config.py │ ├── exceptions.py │ └── reader.py │ ├── reporter │ ├── __init__.py │ ├── exceptions.py │ ├── plugins │ │ ├── __init__.py │ │ ├── html.py │ │ ├── json.py │ │ ├── provider │ │ │ ├── __init__.py │ │ │ └── provider.py │ │ ├── std.py │ │ └── txt.py │ └── reporter.py │ └── tpl │ ├── __init__.py │ ├── config.py │ ├── exceptions.py │ └── tpl.py └── tests ├── __init__.py ├── data ├── directories-scan.dat ├── directories.dat ├── ignored.dat ├── proxies.dat ├── setup-scan.cfg ├── setup.cfg ├── setupwrong.cfg ├── subdomains.dat └── useragents.dat ├── reports └── test.local │ ├── success.txt │ ├── test.local.html │ └── test.local.json ├── syslog └── exceptions.log ├── test_controller.py ├── test_core_filter.py ├── test_core_options.py ├── test_core_terminal.py ├── test_lib_browser.py ├── test_lib_browser_config.py ├── test_lib_browser_debug.py ├── test_lib_browser_filter.py ├── test_lib_browser_threadpool.py ├── test_lib_browser_worker.py ├── test_lib_events.py ├── test_lib_package.py ├── test_lib_reader.py ├── test_lib_reporter.py ├── test_lib_tpl.py └── tmp └── list.tmp /.coveragerc: -------------------------------------------------------------------------------- 1 | # .coveragerc to control coverage.py 2 | [run] 3 | omit = 4 | *__init__* 5 | branch = true 6 | cover_pylib = false 7 | source = src/ 8 | 9 | [report] 10 | omit = 11 | *__init__* 12 | show_missing = false -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [stanislav-web] 4 | #patreon: # Replace with a single Patreon username 5 | #open_collective: # Replace with a single Open Collective username 6 | #ko_fi: # Replace with a single Ko-fi username 7 | #tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | #community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | #liberapay: # Replace with a single Liberapay username 10 | #issuehunt: # Replace with a single IssueHunt username 11 | #otechie: # Replace with a single Otechie username 12 | #lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 13 | #custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 14 | -------------------------------------------------------------------------------- /.github/workflows/codacy.yml: -------------------------------------------------------------------------------- 1 | # This workflow uses actions that are not certified by GitHub. 2 | # They are provided by a third-party and are governed by 3 | # separate terms of service, privacy policy, and support 4 | # documentation. 5 | 6 | # This workflow checks out code, performs a Codacy security scan 7 | # and integrates the results with the 8 | # GitHub Advanced Security code scanning feature. For more information on 9 | # the Codacy security scan action usage and parameters, see 10 | # https://github.com/codacy/codacy-analysis-cli-action. 11 | # For more information on Codacy Analysis CLI in general, see 12 | # https://github.com/codacy/codacy-analysis-cli. 13 | 14 | name: Codacy Security Scan 15 | 16 | on: 17 | push: 18 | branches: [ "master" ] 19 | pull_request: 20 | # The branches below must be a subset of the branches above 21 | branches: [ "master" ] 22 | schedule: 23 | - cron: '35 9 * * 0' 24 | 25 | permissions: 26 | contents: read 27 | 28 | jobs: 29 | codacy-security-scan: 30 | permissions: 31 | contents: read # for actions/checkout to fetch code 32 | security-events: write # for github/codeql-action/upload-sarif to upload SARIF results 33 | actions: read # only required for a private repository by github/codeql-action/upload-sarif to get the Action run status 34 | name: Codacy Security Scan 35 | runs-on: ubuntu-latest 36 | steps: 37 | # Checkout the repository to the GitHub Actions runner 38 | - name: Checkout code 39 | uses: actions/checkout@v3 40 | 41 | # Execute Codacy Analysis CLI and generate a SARIF output with the security issues identified during the analysis 42 | - name: Run Codacy Analysis CLI 43 | uses: codacy/codacy-analysis-cli-action@d840f886c4bd4edc059706d09c6a1586111c540b 44 | with: 45 | # Check https://github.com/codacy/codacy-analysis-cli#project-token to get your project token from your Codacy repository 46 | # You can also omit the token and run the tools that support default configurations 47 | project-token: ${{ secrets.CODACY_PROJECT_TOKEN }} 48 | verbose: true 49 | output: results.sarif 50 | format: sarif 51 | # Adjust severity of non-security issues 52 | gh-code-scanning-compat: true 53 | # Force 0 exit code to allow SARIF file generation 54 | # This will handover control about PR rejection to the GitHub side 55 | max-allowed-issues: 2147483647 56 | 57 | # Upload the SARIF file generated in the previous step 58 | - name: Upload SARIF results file 59 | uses: github/codeql-action/upload-sarif@v2 60 | with: 61 | sarif_file: results.sarif 62 | -------------------------------------------------------------------------------- /.github/workflows/dependency-review.yml: -------------------------------------------------------------------------------- 1 | # Dependency Review Action 2 | # 3 | # This Action will scan dependency manifest files that change as part of a Pull Request, surfacing known-vulnerable versions of the packages declared or updated in the PR. Once installed, if the workflow run is marked as required, PRs introducing known-vulnerable packages will be blocked from merging. 4 | # 5 | # Source repository: https://github.com/actions/dependency-review-action 6 | # Public documentation: https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/about-dependency-review#dependency-review-enforcement 7 | name: 'Dependency Review' 8 | on: [pull_request] 9 | 10 | permissions: 11 | contents: read 12 | 13 | jobs: 14 | dependency-review: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - name: 'Checkout Repository' 18 | uses: actions/checkout@v3 19 | - name: 'Dependency Review' 20 | uses: actions/dependency-review-action@v2 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | /tmp/ 3 | /reports/ 4 | /syslog/ 5 | /build/ 6 | /opendoor.egg-info 7 | .coverage 8 | *__pycache__/** 9 | *.pyc 10 | venv/ 11 | /opendoor.pub 12 | /opendoor 13 | /.eggs/ 14 | /dist/ 15 | TODO.txt 16 | test.py 17 | -------------------------------------------------------------------------------- /.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | # .readthedocs.yaml 2 | # Read the Docs configuration file 3 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details 4 | 5 | # Required 6 | version: 2 7 | 8 | # Set the version of Python and other tools you might need 9 | build: 10 | os: ubuntu-22.04 11 | tools: 12 | python: "3.11" 13 | 14 | mkdocs: 15 | configuration: mkdocs.yml 16 | 17 | # Optionally, build your docs in additional formats such as PDF 18 | formats: all 19 | 20 | # Optionally set the version of Python and requirements required to build your docs 21 | python: 22 | install: 23 | - requirements: docs/requirements.txt 24 | - method: pip 25 | path: . 26 | extra_requirements: 27 | - docs 28 | system_packages: true -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | # Include the data files 2 | include data/*.dat 3 | include opendoor.py 4 | include opendoor.conf -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | 4.2.0 -------------------------------------------------------------------------------- /data/ignored.dat: -------------------------------------------------------------------------------- 1 | 403.html 2 | 403.php 3 | 403.html 4 | 403.asp 5 | 404.html 6 | 404.php 7 | 404.html 8 | 404.asp 9 | 404 10 | 404_error.php 11 | 500 12 | 500.html 13 | index.html 14 | 500.php 15 | 500.asp 16 | goto.php 17 | goto 18 | error.php 19 | index.php 20 | notfound.php 21 | notfound.html 22 | notfound 23 | index 24 | page-not-found 25 | page-not-found.html -------------------------------------------------------------------------------- /docs/Contribution.md: -------------------------------------------------------------------------------- 1 | If you like to contribute to the development of the project, in that case, pull requests are open for you. 2 | Also, you can suggest an ideas and create a task in my track list 3 | 4 | #### Maintainers 5 | - @stanislav-web (Developer) 6 | - [Issues](https://github.com/stanislav-web/OpenDoor/issues) 7 | 8 | Please hold on Python Enhancement Proposals. [See more](https://www.python.org/dev/peps/) 9 | -------------------------------------------------------------------------------- /docs/Installation-and-update.md: -------------------------------------------------------------------------------- 1 | Installation 2 | =============== 3 | **Python v3.7 is a minor requirement**. 4 | At the moment, the package can be installed from this repository [https://github.com/stanislav-web/OpenDoor](https://github.com/stanislav-web/OpenDoor) 5 | Now being tested, and the next will be published in other sources, such as Pypi. 6 | 7 | | Python | Linux | OSX | 8 | |----------|-------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------| 9 | | 3.7 | ![CircleCI](https://circleci.com/gh/stanislav-web/OpenDoor.svg?style=shield&circle-token=6858e3bc123caac9e31ab8f18f5e9e22a03fdb0f ) | ![CircleCI](https://circleci.com/gh/stanislav-web/OpenDoor.svg?style=shield&circle-token=6858e3bc123caac9e31ab8f18f5e9e22a03fdb0f ) | 10 | | 3.8 | ![CircleCI](https://circleci.com/gh/stanislav-web/OpenDoor.svg?style=shield&circle-token=6858e3bc123caac9e31ab8f18f5e9e22a03fdb0f ) | ![CircleCI](https://circleci.com/gh/stanislav-web/OpenDoor.svg?style=shield&circle-token=6858e3bc123caac9e31ab8f18f5e9e22a03fdb0f ) | 11 | | 3.9 | ![CircleCI](https://circleci.com/gh/stanislav-web/OpenDoor.svg?style=shield&circle-token=6858e3bc123caac9e31ab8f18f5e9e22a03fdb0f ) | ![CircleCI](https://circleci.com/gh/stanislav-web/OpenDoor.svg?style=shield&circle-token=6858e3bc123caac9e31ab8f18f5e9e22a03fdb0f ) | 12 | | 3.10 | ![CircleCI](https://circleci.com/gh/stanislav-web/OpenDoor.svg?style=shield&circle-token=6858e3bc123caac9e31ab8f18f5e9e22a03fdb0f ) | ![CircleCI](https://circleci.com/gh/stanislav-web/OpenDoor.svg?style=shield&circle-token=6858e3bc123caac9e31ab8f18f5e9e22a03fdb0f ) | 13 | | 3.11 | ![CircleCI](https://circleci.com/gh/stanislav-web/OpenDoor.svg?style=shield&circle-token=6858e3bc123caac9e31ab8f18f5e9e22a03fdb0f ) | ![CircleCI](https://circleci.com/gh/stanislav-web/OpenDoor.svg?style=shield&circle-token=6858e3bc123caac9e31ab8f18f5e9e22a03fdb0f ) | 14 | 15 | Install PIP 16 | --------------------------- 17 | ```shell 18 | curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py 19 | ``` 20 | 21 | GNU Linux / OSX (Mac OS) 22 | --------------------------- 23 | 24 | ```shell 25 | # Install locally 26 | git clone https://github.com/stanislav-web/OpenDoor.git 27 | cd OpenDoor/ 28 | pip3 install -r requirements.txt 29 | chmod +x opendoor.py 30 | python3 opendoor.py --host http://www.example.com 31 | ``` 32 | 33 | ```shell 34 | # Install globally to env 35 | git clone https://github.com/stanislav-web/OpenDoor.git 36 | cd OpenDoor/ 37 | python3 setup.py build && python3 setup.py install 38 | opendoor --host http://www.example.com 39 | ``` 40 | 41 | Windows XP/7/8/10 42 | --------------------------- 43 | 44 | I would recommend you to install GUI for Git at first if you don't have pre-installed Git on your laptop. 45 | Please see [https://git-for-windows.github.io](https://git-for-windows.github.io) 46 | Go to your Git bash and clone repo 47 | 48 | ```shell 49 | git clone https://github.com/stanislav-web/OpenDoor.git opendoor 50 | cd opendoor 51 | ``` 52 | 53 | Next , install python package manager. 54 | Here you go > [https://pip.pypa.io/en/stable/installing/#do-i-need-to-install-pip](https://pip.pypa.io/en/stable/installing/#do-i-need-to-install-pip) 55 | Install dependencies 56 | 57 | ```shell 58 | C:\opendoor> pip install -r requirements.txt 59 | ``` 60 | s 61 | Unfortunately, you can't use Socks proxy on Windows. HTTP(S) supported only 62 | Try your fist launch 63 | 64 | ```shell 65 | C:\opendoor>python3 opendoor.py -h 66 | ``` 67 | 68 | Dependencies 69 | ============ 70 | ![Dependencies](img/dependencies.jpg) 71 | 72 | Update 73 | =============== 74 | You have an update a package using `git pull origin master` inside or run update process from interface: 75 | ```shell 76 | # GNU Linux 77 | python3 opendoor.py --update 78 | ``` 79 | 80 | ```shell 81 | # Win 82 | C:\opendoor>python opendoor.py --update 83 | ``` -------------------------------------------------------------------------------- /docs/Sniffers.md: -------------------------------------------------------------------------------- 1 | Sniff Tools 2 | =========== 3 | Allows you to apply different filters depending on the server response. 4 | Also, you can support the project and add own filters to the repository. 5 | Pull requests always open for you. 6 | 7 | **NOTICE**: All these filters work with GET request method by default. 8 | 9 | Usage 10 | ----- 11 | 12 | **--sniff file** - Allows you to detect large files from the server response. 13 | *Force scan method:* HEAD 14 | *Positive:* all success pages which contains more than 1mb fall under this filter 15 | 16 | ```shell 17 | opendoor --host www.example.com --sniff file 18 | ``` 19 | 20 | **--sniff indexof** - Allows you to detect empty (Index Of/) Apache directories. 21 | *Force scan method:* GET 22 | *Positive:* all success pages which contains title:(IndexOf|i):title fall under this filter 23 | 24 | ```shell 25 | opendoor --host www.example.com --sniff indexof 26 | ``` 27 | 28 | **--sniff skipempty** - Allows you to skip blank success pages to select correct result 29 | *Force scan method:* GET 30 | *Positive:* all success pages which contain less than 1000b are ignored for success 31 | 32 | ```shell 33 | opendoor --host www.example.com --sniff skipempty 34 | ``` 35 | 36 | **--sniff collation** - Heuristic detection of invalid success pages. This is might be when the page has success response but really hasn't meaningful value 37 | *Force scan method:* GET 38 | *Positive:* all successfully loaded pages are compared among themselves, and those that are very similar, fall under this filter and are excluded 39 | *Notice:* The behavior of this filter may vary depending on the source data 40 | 41 | ```shell 42 | opendoor --host www.example.com --sniff collation 43 | ``` 44 | 45 | **--sniff skipsizes=NUM:NUM:NUM..** - Identifies pages of the specified size (in kb) as false positive for scan. 46 | This is might be useful when the page has success response or redirect to 200 47 | *Force scan method:* GET 48 | *Positive:* all success pages which contain skipsizes=NUM:NUM kb are ignored for success 49 | 50 | ```shell 51 | opendoor --host www.example.com --sniff skipsizes=25:50:87.... 52 | ``` 53 | 54 | How would this work? 55 | --------------------- 56 | Also, you can combine these filters as you prefer. 57 | ```shell 58 | opendoor --host www.example.com --sniff skipempty,file,collation,indexof,skipsizes=24:41:50 --debug 1 59 | 60 | [23:16:04] debug: Starting debug level 1. Using scan method: GET ... 61 | [23:16:04] debug: Load sniffer: File (detect large files) 62 | [23:16:04] debug: Load sniffer: IndexOf (detect Index Of/ Apache directories) 63 | [23:16:04] debug: Load sniffer: Collation (detect and ignore false positive success pages) 64 | [23:16:04] debug: Load sniffer: SkipEmpty (skip empty success pages) 65 | [23:16:04] debug: Load sniffer: SkipSize (skip target size of page +-2000 bytes added) 66 | [23:16:04] info: Wait, please, checking connect to -> www.example.com:80 ... 67 | [23:16:05] info: Server www.example.com:80 (93.184.216.34) is online! 68 | [23:16:05] debug: Read 36312 directories list by line 69 | [23:16:05] debug: Creating queue with 5 thread(s)... 70 | [23:16:05] info: Scanning www.example.com ... 71 | ``` -------------------------------------------------------------------------------- /docs/Testing.md: -------------------------------------------------------------------------------- 1 | Run tests 2 | =========== 3 | ```shell 4 | pip install -r requirements-dev.txt 5 | python setup.py test 6 | coverage report 7 | ``` -------------------------------------------------------------------------------- /docs/Wizard.md: -------------------------------------------------------------------------------- 1 | Wizard 2 | ====== 3 | The Wizard allows you to select individual settings for each target. 4 | See example: 5 | 6 | Configure 7 | --------------------------- 8 | `opendoor.conf` 9 | 10 | ```ini 11 | [general] 12 | 13 | # Use ssl 14 | ssl = False 15 | 16 | # Target scheme 17 | scheme = http:// 18 | 19 | # Target host (ip) 20 | host = example.com 21 | 22 | # Custom port (Default 80) 23 | port = 80 24 | 25 | # HTTP method (use HEAD as default) 26 | method = HEAD 27 | 28 | # Delay between request's threads 29 | delay = 0 30 | 31 | # Request timeout (30 sec default) 32 | timeout = 60 33 | 34 | # Max retries to reconnect (default 3) 35 | retries = 10 36 | 37 | # Using built-in proxylist 38 | tor = False 39 | 40 | # Path to custom proxylist 41 | torlist = None 42 | 43 | # Custom permanent proxy server 44 | proxy = None 45 | 46 | # Randomize user-agent per request 47 | random-agent = False 48 | 49 | # Debug level 1 - 3 50 | debug = 0 51 | 52 | # Allowed threads 53 | threads = 1 54 | 55 | # Response sniff plugins (indexof,collation,file,skipempty) 56 | sniff = None 57 | 58 | # Scan type scan=directories or scan=subdomains 59 | scan = directories 60 | 61 | # Path to custom wordlist 62 | wordlist = None 63 | 64 | # Shuffle scan list 65 | random-list = False 66 | 67 | # Append path prefix to scan host 68 | prefix = None 69 | 70 | # Force use selected extensions for scan session -e php,json e.g 71 | extensions = None 72 | 73 | # Force ignore extensions for scan session -i aspx,jsp e.g 74 | ignore_extensions = None 75 | 76 | # Scan reports (json,std,txt,html) 77 | reports = std 78 | 79 | # Path to custom reports dir 80 | reports-dir = None 81 | ``` 82 | 83 | Usage 84 | ----- 85 | ```shell 86 | opendoor --wizard # get default config from opendoor.conf 87 | opendoor --wizard /usr/local/projects/mytarget.com.conf 88 | ``` -------------------------------------------------------------------------------- /docs/img/dependencies.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanislav-web/OpenDoor/5f8a2539f3cdb312853753cc231eaa598a313808/docs/img/dependencies.jpg -------------------------------------------------------------------------------- /docs/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanislav-web/OpenDoor/5f8a2539f3cdb312853753cc231eaa598a313808/docs/img/favicon.ico -------------------------------------------------------------------------------- /docs/img/lgpl.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanislav-web/OpenDoor/5f8a2539f3cdb312853753cc231eaa598a313808/docs/img/lgpl.jpg -------------------------------------------------------------------------------- /docs/img/open-door.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanislav-web/OpenDoor/5f8a2539f3cdb312853753cc231eaa598a313808/docs/img/open-door.png -------------------------------------------------------------------------------- /docs/img/usage.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanislav-web/OpenDoor/5f8a2539f3cdb312853753cc231eaa598a313808/docs/img/usage.jpg -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | Opendoor OWASP WEB Directory Scanner 2 | ===================================== 3 | 4 | **OpenDoor OWASP** is console multifunctional website's scanner. 5 | This application finds all possible ways to login, index of/ directories, 6 | The scanning is performed by the built-in dictionary and external dictionaries as well. Anonymity and speed are provided by means of using proxy servers. 7 | Software is written for informational purposes and is open source product under the GPL license. 8 | Dictionaries are constantly updated, also expanding application functionality. 9 | 10 | [![Contributors](https://img.shields.io/github/contributors/stanislav-web/Opendoor)](https://github.com/stanislav-web/OpenDoor/graphs/contributors) 11 | [![PyPI version](https://badge.fury.io/py/opendoor.svg)](https://badge.fury.io/py/opendoor) 12 | [![Python 3.7](https://img.shields.io/badge/python-3.7%20%2B-green.svg)](https://www.python.org/) 13 | 14 | 15 | #### Implements 16 | - ✅ directories scanner 17 | - ✅ subdomains scanner 18 | - ✅ multithreading control 19 | - ✅ scan's reports 20 | - ✅ HTTP(S) (PORT) support 21 | - ✅ Keep-alive long pooling 22 | - ✅ Invalid certificates scan 23 | - ✅ HTTP(S)/SOCKS proxies 24 | - ✅ dynamic request header 25 | - ✅ custom wordlists prefixes 26 | - ✅ custom wordlists, proxies, ignore lists 27 | - ✅ debug levels (1-3) 28 | - ✅ extensions filter 29 | - ✅ custom reports directory 30 | - ✅ custom config wizard (use random techniques) 31 | - ✅ analyze techniques: 32 | * skip empty pages 33 | * detect redirects 34 | * skip 200 OK redirects 35 | * detect index of/ Apache 36 | * detect large files 37 | * heuristic detect invalid pages 38 | * blank success page filter 39 | * certificate required pages 40 | - ✅ randomization techniques: 41 | * random user-agent per request 42 | * random proxy per request 43 | * wordlists shuffling 44 | * wordlists filters 45 | 46 | 47 | ***Testing of the software on the commercial systems and organizations is prohibited!*** 48 | 49 | ![Logo](img/open-door.png) -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | mkdocs==1.4.3 2 | sphinx==5.3.0 3 | sphinx_rtd_theme==1.2.2 4 | readthedocs-sphinx-search==0.3.1 -------------------------------------------------------------------------------- /mkdocs.yml: -------------------------------------------------------------------------------- 1 | site_name: Opendoor OWASP WEB Directory Scanner 2 | site_url: https://opendoor.readthedocs.io/ 3 | repo_url: https://github.com/stanislav-web/OpenDoor 4 | repo_name: OpenDoor 5 | site_description: OpenDoor OWASP is console multifunctional website's scanner 6 | site_author: Brain Storm Team 7 | copyright: Copyright (C) 2017-2023 Brain Storm Team 8 | extra: 9 | homepage: https://github.com/stanislav-web/OpenDoor 10 | version: latest 11 | 12 | nav: 13 | - Home: index.md 14 | - Installation and update: Installation-and-update.md 15 | - Usage: Usage.md 16 | - Sniffers: Sniffers.md 17 | - Wizard: Wizard.md 18 | - Testing: Testing.md 19 | - Contribution: Contribution.md 20 | - Changelog: Changelog.md 21 | - License: License.md 22 | theme: 23 | name: readthedocs 24 | -------------------------------------------------------------------------------- /opendoor.conf: -------------------------------------------------------------------------------- 1 | [general] 2 | 3 | # Use ssl 4 | ssl = False 5 | 6 | # Target sheme 7 | scheme = http:// 8 | 9 | # Target host (ip) 10 | host = example.com 11 | 12 | # Custom port (Default 80) 13 | port = 80 14 | 15 | # HTTP method (use HEAD as default) 16 | method = HEAD 17 | 18 | # Delay between request's threads 19 | delay = 0 20 | 21 | # Request timeout (30 sec default) 22 | timeout = 30 23 | 24 | # Max retries to reconnect (default 3) 25 | retries = 10 26 | 27 | # Using built-in proxylist 28 | tor = False 29 | 30 | # Path to custom proxylist 31 | torlist = None 32 | 33 | # Custom permanent proxy server 34 | proxy = None 35 | 36 | # Randomize user-agent per request 37 | random-agent = False 38 | 39 | # Debug level 1 - 3 40 | debug = 0 41 | 42 | # Allowed threads 43 | threads = 1 44 | 45 | # Response sniff plugins (skipempty,collation,indexof) 46 | sniff = None 47 | 48 | # Scan type scan=directories or scan=subdomains 49 | scan = directories 50 | 51 | # Path to custom wordlist 52 | wordlist = None 53 | 54 | # Shuffle scan list 55 | random-list = False 56 | 57 | # Append path prefix to scan host 58 | prefix = None 59 | 60 | # Force use selected extensions for scan session -e php,json e.g 61 | extensions = None 62 | 63 | # Force ignore extensions for scan session -i aspx,jsp e.g 64 | ignore_extensions = None 65 | 66 | # Scan reports (json,std,txt,html) 67 | reports = std 68 | 69 | # Path to custom reports dir 70 | reports-dir = None -------------------------------------------------------------------------------- /opendoor.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | """ OWASP OpenDoor launcher 5 | 6 | This program is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | 18 | Development Team: Brain Storm Team 19 | """ 20 | 21 | import sys 22 | 23 | for _ in ['urllib3', 'json2html', 'tabulate', 'importlib', 'packaging']: 24 | try: 25 | __import__(_) 26 | except ImportError as error: 27 | sys.exit("""\t\t[!] Several dependencies wasn't installed! Please run pip3 install -r requirements.txt. 28 | Details : %s.""" % error) 29 | 30 | if __name__ == "__main__": 31 | 32 | from src import Controller, SrcError 33 | import sys 34 | 35 | try: 36 | bootstrap = Controller() 37 | bootstrap.run() 38 | except SrcError: 39 | sys.exit() 40 | -------------------------------------------------------------------------------- /requirements-dev.txt: -------------------------------------------------------------------------------- 1 | ddt==1.6.0 2 | json2html==1.3.0 3 | mock==5.0.2 4 | packaging==23.1 5 | six==1.16.0 6 | tabulate==0.9.0 7 | urllib3==2.0.3 8 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | json2html==1.3.0 2 | packaging==23.1 3 | six==1.16.0 4 | tabulate==0.9.0 5 | urllib3==2.0.6 6 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . 16 | 17 | Development Team: Brain Storm Team 18 | """ 19 | 20 | from setuptools import setup, find_packages 21 | fVersion = open('VERSION').readline().rstrip() 22 | 23 | NAME = 'opendoor' 24 | VERSION = fVersion 25 | DESCRIPTION = 'OWASP WEB Directory Scanner' 26 | LONG_DESCRIPTION = open('README.md', 'r+', encoding='utf-8').read() 27 | HOMEPAGE = 'https://github.com/stanislav-web/OpenDoor' 28 | AUTHOR = 'Brain Storm Team', 29 | AUTHOR_EMAIL = 'nomail@gmail.com', 30 | MAINTAINER = 'Brain Storm Team', 31 | FULL_NAME = 'Brain Storm' 32 | DOWNLOAD_URL = 'https://github.com/stanislav-web/OpenDoor/archive/refs/heads/master.zip' 33 | setup(name=NAME, 34 | 35 | # Versions should comply with PEP440. For a discussion on single-sourcing 36 | # the version across setup.py and the project code, see 37 | # https://packaging.python.org/en/latest/single_source_version.html 38 | 39 | version=VERSION, 40 | 41 | description=DESCRIPTION, 42 | 43 | long_description=LONG_DESCRIPTION, 44 | 45 | long_description_content_type="text/markdown", 46 | 47 | # The project's main homepage. 48 | url=HOMEPAGE, 49 | 50 | # Author details 51 | author="".join(AUTHOR), 52 | 53 | fullname="".join(FULL_NAME), 54 | 55 | author_email="".join(AUTHOR_EMAIL), 56 | 57 | maintainer="".join(MAINTAINER), 58 | 59 | maintainer_email="".join(AUTHOR_EMAIL), 60 | 61 | # You can just specify the packages manually here if your project is 62 | # simple. Or you can use find_packages(). 63 | zip_safe=False, 64 | packages=find_packages(), 65 | data_files=[('.', ['opendoor.conf']), 66 | ('data', [ 67 | 'data/directories.dat', 68 | 'data/ignored.dat', 69 | 'data/proxies.dat', 70 | 'data/subdomains.dat', 71 | 'data/useragents.dat', 72 | ]) 73 | ], 74 | include_package_data=True, 75 | 76 | script_name='opendoor.py', 77 | # Choose your license 78 | license='GPL', 79 | # Unittests suite directory 80 | test_suite='tests', 81 | 82 | # What does your project relate to? 83 | keywords=[ 84 | 'owasp scanner', 85 | 'directory scanner', 86 | 'access directory scanner', 87 | 'fuzzer', 88 | 'auth scanner', 89 | 'dir search', 90 | 'dirmap' 91 | ], 92 | 93 | download_url=DOWNLOAD_URL, 94 | 95 | # To provide executable scripts, use entry points in preference to the 96 | # "scripts" keyword. Entry points provide cross-platform support and allow 97 | # pip to create the appropriate form of executable for the target platform. 98 | entry_points={'console_scripts': [ 99 | 'opendoor=src:main', 100 | 'coveralls = coveralls.cli:main' 101 | ]}, 102 | 103 | install_requires=[line.rstrip('\n') for line in open('requirements.txt')], 104 | tests_require=[line.rstrip('\n') for line in open('requirements-dev.txt')], 105 | 106 | platforms=['any'], 107 | # See https://pypi.python.org/pypi?%3Aaction=list_classifiers 108 | # How mature is this project? Common values are 109 | classifiers=[ 110 | # 3 - Alpha 111 | # 4 - Beta 112 | # 5 - Production/Stable 113 | 'Development Status :: 5 - Production/Stable', 114 | 115 | # Language 116 | 'Natural Language :: English', 117 | 118 | # Indicate who your project is intended for 119 | 'Intended Audience :: Developers', 120 | 121 | # OS, which support this package 122 | 'Operating System :: MacOS', 123 | 'Operating System :: Unix', 124 | 125 | # Pick your license as you wish (should match "license" above) 126 | 'License :: OSI Approved :: GNU General Public License v3 (GPLv3)', 127 | 128 | # Specify the Python versions you support here. In particular, ensure 129 | # that you indicate whether you support Python 2, Python 3 or both. 130 | 131 | 'Programming Language :: Python', 132 | 'Programming Language :: Python :: 3', 133 | 134 | # Specify the additional categories 135 | 'Topic :: Utilities', 136 | 'Topic :: Internet :: WWW/HTTP :: Site Management :: Link Checking', 137 | 'Topic :: Internet :: WWW/HTTP :: Indexing/Search', 138 | 'Topic :: Internet :: WWW/HTTP :: WSGI :: Application', 139 | ]) 140 | -------------------------------------------------------------------------------- /src/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . 16 | 17 | Development Team: Brain Storm Team 18 | """ 19 | 20 | import sys 21 | from .controller import Controller 22 | from .exceptions import SrcError 23 | 24 | for _ in ['urllib3', 'json2html', 'tabulate', 'importlib', 'packaging']: 25 | try: 26 | __import__(_) 27 | except ImportError as error: 28 | sys.exit("""\t\t[!] Several dependencies wasn't installed! Please run pip install -r requirements.txt. 29 | Details : %s.""" % error) 30 | 31 | 32 | def main(): 33 | """ 34 | This function loads the package and runs the Controller class. 35 | 36 | :except SrcError: Raises an exception if there is an error in the source code. 37 | :return: None 38 | """ 39 | try: 40 | bootstrap = Controller() 41 | bootstrap.run() 42 | except SrcError: 43 | sys.exit() 44 | 45 | 46 | if __name__ == "__main__": 47 | main() 48 | -------------------------------------------------------------------------------- /src/core/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | # noinspection PyPep8Naming 20 | from .color import Color as colour 21 | # noinspection PyPep8Naming 22 | from .core import CoreConfig 23 | # noinspection PyPep8Naming 24 | from .decorators import execution_time 25 | # noinspection PyPep8Naming 26 | from .filesystem import FileSystem as filesystem 27 | from .filesystem.exceptions import FileSystemError 28 | # noinspection PyPep8Naming 29 | from .helper import Helper as helper 30 | # noinspection PyPep8Naming 31 | from .http import HttpRequest as request_http 32 | # noinspection PyPep8Naming 33 | from .http import HttpsRequest as request_https 34 | # noinspection PyPep8Naming 35 | from .http import Proxy as request_proxy 36 | # noinspection PyPep8Naming 37 | from .http import Response as response 38 | # noinspection PyPep8Naming 39 | from .http import Socket as socket 40 | from .http.exceptions import HttpRequestError 41 | from .http.exceptions import HttpsRequestError 42 | from .http.exceptions import ProxyRequestError 43 | from .http.exceptions import ResponseError 44 | from .http.exceptions import SocketError 45 | # noinspection PyPep8Naming 46 | from .logger import LoggerException as exception 47 | # noinspection PyPep8Naming 48 | from .logger import Logger as logger 49 | # noinspection PyPep8Naming 50 | from .options import Options as options 51 | from .options.exceptions import OptionsError 52 | # noinspection PyPep8Naming 53 | from .system import Term as process 54 | # noinspection PyPep8Naming 55 | from .system import Output as sys 56 | from .system.exceptions import CoreSystemError 57 | -------------------------------------------------------------------------------- /src/core/color/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | from .color import Color 20 | -------------------------------------------------------------------------------- /src/core/color/color.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | import sys 20 | 21 | 22 | class Color(object): 23 | 24 | """Color class""" 25 | 26 | default = 'white' 27 | 28 | @staticmethod 29 | def __get(key): 30 | """ 31 | Get color key 32 | :param str key: color name 33 | :return: int 34 | """ 35 | 36 | colorlist = {'black': 0, 'red': 1, 'green': 2, 'yellow': 3, 'blue': 4, 'magenta': 5, 'cyan': 6, 'white': 7} 37 | color_text = colorlist[key] if key in colorlist else colorlist[Color.default] 38 | return color_text 39 | 40 | @staticmethod 41 | def __has_colors(stream): 42 | """ 43 | Is tty output check 44 | :param object stream: input stream 45 | :return: bool 46 | """ 47 | 48 | if not hasattr(stream, "isatty"): 49 | return False 50 | # noinspection PyUnresolvedReferences 51 | if not stream.isatty(): 52 | return False # auto color only on TTYs 53 | # noinspection PyBroadException 54 | try: 55 | import curses 56 | curses.setupterm() 57 | return curses.tigetnum("colors") > 2 58 | except Exception: 59 | # guess false in case of error 60 | return False 61 | 62 | @staticmethod 63 | def colored(text, color): 64 | """ 65 | Output colorized text 66 | :param str text: message 67 | :param str color: prefered color 68 | :return: string 69 | """ 70 | 71 | if Color.__has_colors(sys.stdout): 72 | 73 | if isinstance(text, bytes): 74 | text = str(text, "utf-8") 75 | 76 | text = text.strip('\n') 77 | seq = "\x1b[%dm" % (30 + Color.__get(color)) + text + "\x1b[0m" 78 | return seq 79 | else: 80 | return text 81 | -------------------------------------------------------------------------------- /src/core/core.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | fVersion = open('VERSION', 'r+').readline().rstrip() 19 | 20 | CoreConfig = { 21 | 'info': { 22 | 'name': 'Opendoor scanner', 23 | 'repository': 'git@github.com:stanislav-web/OpenDoor.git', 24 | 'remote_version': 'https://raw.githubusercontent.com/stanislav-web/OpenDoor/master/VERSION', 25 | 'license': 'License: GNU General Public License', 26 | 'version': fVersion, 27 | 'documentation': 'https://opendoor.readthedocs.org', 28 | 'required_versions': { 29 | 'minor': '3.7', 30 | 'major': '3.11' 31 | }, 32 | }, 33 | 'data': { 34 | 'directories': 'data/directories.dat', 35 | 'ignored': 'data/ignored.dat', 36 | 'proxies': 'data/proxies.dat', 37 | 'subdomains': 'data/subdomains.dat', 38 | 'useragents': 'data/useragents.dat', 39 | 'tmplist': 'tmp/list.tmp', 40 | 'extensionlist': 'tmp/extensionlist.tmp', 41 | 'ignore_extensionlist': 'tmp/ignore_extensionlist.tmp', 42 | 'reports': 'reports/', 43 | 'exceptions_log': 'syslog/exceptions.log', 44 | }, 45 | 'command': { 46 | 'cvsupdate': '/usr/bin/git pull origin master', 47 | 'cvslog': '/usr/bin/git log --oneline -n 1', 48 | }, 49 | 'examples': """ 50 | 51 | Examples: 52 | python3 ./opendoor.py --examples 53 | python3 ./opendoor.py --update 54 | python3 ./opendoor.py --version 55 | python3 ./opendoor.py --docs 56 | python3 ./opendoor.py --wizard 57 | python3 ./opendoor.py --wizard /usr/local/projects/my.conf 58 | python3 ./opendoor.py --host "http://example.com" 59 | python3 ./opendoor.py --host "https://example.com" --port 8080 60 | python3 ./opendoor.py --host "http://example.com" --scan subdomains 61 | python3 ./opendoor.py --host "http://example.com" --threads 10 62 | python3 ./opendoor.py --host "http://example.com" -random-list --extensions php,html 63 | python3 ./opendoor.py --host "http://example.com" -random-list --ignore-extensions aspx,jsp 64 | python3 ./opendoor.py --host "http://example.com" --threads 10 --random-list 65 | python3 ./opendoor.py --host "http://example.com" --threads 10 --random-agent 66 | python3 ./opendoor.py --host "http://example.com" --threads 10 --tor 67 | python3 ./opendoor.py --host "http://example.com" --threads 10 --delay 10 68 | python3 ./opendoor.py --host "http://example.com" --threads 10 --prefix en/ 69 | python3 ./opendoor.py --host "http://example.com" --threads 10 --delay 10 --timeout 10 70 | python3 ./opendoor.py --host "http://example.com" --random-list --threads 10 --delay 10 --timeout 10 71 | python3 ./opendoor.py --host "http://example.com" --threads 10 --delay 10 --timeout 10 --debug 1 72 | python3 ./opendoor.py --host "http://example.com" --threads 10 --debug 1 --reports std,txt 73 | python3 ./opendoor.py --host "http://example.com" --debug 1 --reports std,txt --reports-dir /reports 74 | python3 ./opendoor.py --host "http://example.com" --threads 10 --debug 1 --extensions php,html 75 | """, 'banner': """ 76 | ############################################################ 77 | # # 78 | # _____ ____ ____ _ _ ____ _____ _____ ____ # 79 | # ( _ )( _ \( ___)( \( ) ( _ \ ( _ )( _ )( _ \ # 80 | # )(_)( )___/ )__) ) ( )(_) ) )(_)( )(_)( ) / # 81 | # (_____)(__) (____)(_)\_) (____/ (_____)(_____)(_)\_) # 82 | # # 83 | # {0}\t\t # 84 | # {1}\t\t # 85 | # {2}\t\t\t # 86 | # {3}\t\t\t # 87 | # {4} # 88 | ############################################################""", 'version': """ 89 | 90 | {0}: {1} -> {2} 91 | {3} 92 | {4} 93 | ============================================================""", 'update': """ 94 | 95 | {status} 96 | ============================================================""" 97 | } 98 | -------------------------------------------------------------------------------- /src/core/decorators/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | from .timer import execution_time 20 | -------------------------------------------------------------------------------- /src/core/decorators/timer.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | import datetime 20 | import functools 21 | import time 22 | 23 | 24 | def execution_time(func=None, log=None): 25 | """ 26 | Time execution decorator @execution_time(log=tpl) 27 | :param funct func: wrapped function 28 | :param funct log: logger 29 | :return: func 30 | """ 31 | 32 | if not func: 33 | # noinspection PyArgumentList 34 | return functools.partial(execution_time, log=log) 35 | 36 | @functools.wraps(func) 37 | def function_timer(*args, **kwargs): 38 | """ 39 | Function timer 40 | :param args: arguments 41 | :param kwargs: key arguments 42 | :return: func 43 | """ 44 | 45 | start = time.time() 46 | result = func(*args, **kwargs) 47 | end = time.time() 48 | timeless = "{0}".format(datetime.timedelta(seconds=(end - start))) 49 | log.debug(key='total_time_lvl3', time=timeless) 50 | return result 51 | 52 | return function_timer 53 | -------------------------------------------------------------------------------- /src/core/filesystem/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | from .filesystem import FileSystem 20 | -------------------------------------------------------------------------------- /src/core/filesystem/exceptions.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | 20 | class FileSystemError(Exception): 21 | 22 | """FileSystemError class""" 23 | 24 | def __init__(self, message): 25 | """ 26 | FileSystemError class constructor 27 | :param str message: error message 28 | """ 29 | super(FileSystemError, self).__init__(message) 30 | -------------------------------------------------------------------------------- /src/core/helper/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | from .helper import Helper 20 | -------------------------------------------------------------------------------- /src/core/http/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | from .http import HttpRequest 20 | from .proxy import Proxy 21 | from .response import Response 22 | from .socks import Socket 23 | from .https import HttpsRequest 24 | 25 | -------------------------------------------------------------------------------- /src/core/http/exceptions.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | 20 | class SocketError(Exception): 21 | 22 | """SocketError class""" 23 | 24 | def __init__(self, message): 25 | """ 26 | SocketError class constructor 27 | :param str message: error message 28 | """ 29 | 30 | super(SocketError, self).__init__(message) 31 | 32 | 33 | class ProxyRequestError(Exception): 34 | """ProxyRequestError class""" 35 | 36 | def __init__(self, message): 37 | """ 38 | ProxyRequestError class constructor 39 | :param str message: error message 40 | """ 41 | 42 | super(ProxyRequestError, self).__init__(message) 43 | 44 | 45 | class HttpRequestError(Exception): 46 | """HttpRequestError class""" 47 | 48 | def __init__(self, message): 49 | """ 50 | HttpRequestError class constructor 51 | :param str message: error message 52 | """ 53 | 54 | super(HttpRequestError, self).__init__(message) 55 | 56 | 57 | class HttpsRequestError(Exception): 58 | """HttpsRequestError class""" 59 | 60 | def __init__(self, message): 61 | """ 62 | HttpsRequestError class constructor 63 | :param str message: error message 64 | """ 65 | 66 | super(HttpsRequestError, self).__init__(message) 67 | 68 | 69 | class ResponseError(Exception): 70 | """ResponseError class""" 71 | 72 | def __init__(self, message): 73 | """ 74 | ResponseError class constructor 75 | :param str message: error message 76 | """ 77 | 78 | super(ResponseError, self).__init__(message) 79 | -------------------------------------------------------------------------------- /src/core/http/http.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | from urllib3 import HTTPConnectionPool, PoolManager, Timeout 20 | from urllib3.exceptions import MaxRetryError, ReadTimeoutError, ConnectTimeoutError, HostChangedError 21 | from src.core import helper 22 | from .exceptions import HttpRequestError 23 | from .providers import DebugProvider 24 | from .providers import RequestProvider 25 | 26 | 27 | class HttpRequest(RequestProvider, DebugProvider): 28 | 29 | """HttpRequest class""" 30 | 31 | def __init__(self, config, debug, **kwargs): 32 | """ 33 | HttpRequest instance 34 | :param src.lib.browser.config.Config config: global configurations 35 | :param DebugProvider debug: debugger 36 | """ 37 | 38 | try: 39 | self.__tpl = kwargs.get('tpl') 40 | RequestProvider.__init__(self, config, agent_list=kwargs.get('agent_list')) 41 | self.__headers = self._headers 42 | self.__connection_header = 'default' 43 | if True is config.keep_alive: 44 | self.__connection_header = self._keep_alive 45 | except (TypeError, ValueError) as error: 46 | raise HttpRequestError(error) 47 | 48 | self.__cfg = config 49 | self.__debug = debug 50 | 51 | if self.__cfg.DEFAULT_SCAN == self.__cfg.scan: 52 | self.__pool = self.__http_pool() 53 | 54 | def __http_pool(self): 55 | """ 56 | Create HTTP connection pool 57 | :raise HttpRequestError 58 | :return: urllib3.HTTPConnectionPool 59 | """ 60 | 61 | try: 62 | pool = HTTPConnectionPool(self.__cfg.host, 63 | port=self.__cfg.port, 64 | maxsize=self.__cfg.threads, 65 | timeout=Timeout(connect=self.__cfg.timeout, read=self.__cfg.timeout), 66 | block=True) 67 | if self._HTTP_DBG_LEVEL <= self.__debug.level: 68 | self.__debug.debug_connection_pool('http_pool_start', pool, self.__connection_header) 69 | return pool 70 | except Exception as error: 71 | raise HttpRequestError(str(error)) 72 | 73 | def request(self, url): 74 | """ 75 | Client request HTTP 76 | :param str url: request uri 77 | :return: urllib3.HTTPResponse 78 | """ 79 | 80 | self.__headers.update({'User-Agent': self._user_agent}) 81 | if 'default' is not self.__connection_header: 82 | self.__headers.update({'Connection': self.__connection_header}) 83 | if self._HTTP_DBG_LEVEL <= self.__debug.level: 84 | self.__debug.debug_request(self.__headers, url, self.__cfg.method) 85 | try: 86 | if self.__cfg.DEFAULT_SCAN == self.__cfg.scan: 87 | response = self.__pool.request(self.__cfg.method, 88 | helper.parse_url(url).path, 89 | headers=self.__headers, 90 | retries=self.__cfg.retries, 91 | assert_same_host=True, 92 | redirect=False) 93 | self.cookies_middleware(is_accept=self.__cfg.accept_cookies, response=response) 94 | else: 95 | response = PoolManager().request(self.__cfg.method, url, 96 | headers=self.__headers, 97 | retries=self.__cfg.retries, 98 | assert_same_host=False, 99 | redirect=False, 100 | timeout=Timeout(connect=self.__cfg.timeout, read=self.__cfg.timeout)) 101 | return response 102 | 103 | except MaxRetryError: 104 | if self.__cfg.DEFAULT_SCAN == self.__cfg.scan: 105 | self.__tpl.warning(key='max_retry_error', url=helper.parse_url(url).path) 106 | pass 107 | 108 | except HostChangedError as error: 109 | self.__tpl.warning(key='host_changed_error', details=error) 110 | pass 111 | 112 | except ReadTimeoutError: 113 | self.__tpl.warning(key='read_timeout_error', url=url) 114 | pass 115 | 116 | except ConnectTimeoutError: 117 | self.__tpl.warning(key='connection_timeout_error', url=url) 118 | pass 119 | -------------------------------------------------------------------------------- /src/core/http/plugins/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | from .exceptions import ResponsePluginError 20 | from .response_plugin import ResponsePlugin 21 | 22 | -------------------------------------------------------------------------------- /src/core/http/plugins/exceptions.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | 20 | class ResponsePluginError(Exception): 21 | 22 | """ResponsePluginError class""" 23 | 24 | def __init__(self, message): 25 | """ 26 | Error message 27 | :param message: message 28 | :return: None 29 | """ 30 | 31 | super(ResponsePluginError, self).__init__(message) 32 | -------------------------------------------------------------------------------- /src/core/http/plugins/response/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | # noinspection PyPep8Naming 20 | from .collation import CollationResponsePlugin as collation 21 | # noinspection PyPep8Naming 22 | from .indexof import IndexofResponsePlugin as indexof 23 | # noinspection PyPep8Naming 24 | from .skipempty import SkipemptyResponsePlugin as skipempty 25 | # noinspection PyPep8Naming 26 | from .file import FileResponsePlugin as file 27 | # noinspection PyPep8Naming 28 | from .skipsizes import SkipSizesResponsePlugin as skipsizes 29 | -------------------------------------------------------------------------------- /src/core/http/plugins/response/collation.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | from difflib import SequenceMatcher 20 | from .provider import ResponsePluginProvider 21 | 22 | 23 | class CollationResponsePlugin(ResponsePluginProvider): 24 | """ CollationResponsePlugin class""" 25 | 26 | DESCRIPTION = 'Collation (detect and ignore false positive success pages)' 27 | RESPONSE_INDEX = 'failed' 28 | DEFAULT_STATUSES = [100, 101, 200, 201, 202, 203, 204, 205, 206, 207, 208] 29 | MIN_RATIO_INDEX = 0.98 30 | MIN_CONTENT_LENGTH = 100 31 | 32 | def __init__(self, void): 33 | """ 34 | ResponsePluginProvider constructor 35 | """ 36 | 37 | ResponsePluginProvider.__init__(self) 38 | self.strong_false_item = {} 39 | self.previous_item = {} 40 | self.current_item = {} 41 | 42 | def process(self, response): 43 | """ 44 | Process data 45 | :return: str 46 | """ 47 | 48 | if response.status in self.DEFAULT_STATUSES: 49 | super().process(response) 50 | length = self.__get_content_length() 51 | if self.MIN_CONTENT_LENGTH < length: 52 | # the page is allowed for comparison 53 | 54 | if not self.previous_item: 55 | # 1st match. Push items for next compare step 56 | self.previous_item.update({'length': length, 'text': self._body}) 57 | return None 58 | else: 59 | if length == self.previous_item.get('length') and self.MIN_CONTENT_LENGTH < length: 60 | # identical, seems to drop failed for success 61 | return self.RESPONSE_INDEX 62 | else: 63 | matcher = SequenceMatcher(a=self.previous_item['text'], b=self._body) 64 | matcher.get_matching_blocks() 65 | 66 | if 'length' in self.current_item: 67 | next_matcher = SequenceMatcher(a=self.current_item['text'], b=self._body) 68 | if next_matcher.ratio() == matcher.ratio(): 69 | return self.RESPONSE_INDEX 70 | if self.MIN_RATIO_INDEX < matcher.ratio(): 71 | return self.RESPONSE_INDEX 72 | else: 73 | self.current_item.update({'length': length, 'text': self._body}) 74 | 75 | if self.MIN_CONTENT_LENGTH < length: 76 | self.previous_item.update({'length': length, 'text': self._body}) 77 | return None 78 | 79 | def __get_content_length(self): 80 | """ 81 | Get content length 82 | :return: int 83 | """ 84 | 85 | length = 0 86 | if 'Content-Length' in self._headers: 87 | if 0 < int(self._headers['Content-Length']): 88 | length = self._headers['Content-Length'] 89 | else: 90 | length = len(self._body) 91 | return int(length) 92 | -------------------------------------------------------------------------------- /src/core/http/plugins/response/file.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | from .provider import ResponsePluginProvider 20 | 21 | 22 | class FileResponsePlugin(ResponsePluginProvider): 23 | """ FileResponsePlugin class""" 24 | 25 | DESCRIPTION = 'File (detect large files)' 26 | RESPONSE_INDEX = 'file' 27 | DEFAULT_STATUSES = [100, 101, 200, 201, 202, 203, 204, 205, 206, 207, 208] 28 | DEFAULT_SOURCE_DETECT_MIN_SIZE = 1000000 29 | 30 | def __init__(self, void): 31 | """ 32 | ResponsePluginProvider constructor 33 | """ 34 | 35 | ResponsePluginProvider.__init__(self) 36 | 37 | def process(self, response): 38 | """ 39 | Process data 40 | :return: str 41 | """ 42 | 43 | if response.status in self.DEFAULT_STATUSES: 44 | super().process(response) 45 | if 'Content-Length' in self._headers: 46 | if self.DEFAULT_SOURCE_DETECT_MIN_SIZE <= int(self._headers['Content-Length']): 47 | return self.RESPONSE_INDEX 48 | elif self.DEFAULT_SOURCE_DETECT_MIN_SIZE <= len(self._body): 49 | return self.RESPONSE_INDEX 50 | return None 51 | -------------------------------------------------------------------------------- /src/core/http/plugins/response/indexof.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | import re 20 | from .provider import ResponsePluginProvider 21 | 22 | 23 | class IndexofResponsePlugin(ResponsePluginProvider): 24 | """ IndexofResponsePlugin class""" 25 | 26 | DESCRIPTION = 'IndexOf (detect Index Of/ Apache directories)' 27 | RESPONSE_INDEX = 'indexof' 28 | DEFAULT_STATUSES = [100, 101, 200, 201, 202, 203, 204, 205, 206, 207, 208] 29 | INDEX_OF_TITLE = 'Index of /' 30 | 31 | def __init__(self, void): 32 | """ 33 | ResponsePluginProvider constructor 34 | """ 35 | 36 | ResponsePluginProvider.__init__(self) 37 | 38 | def process(self, response): 39 | """ 40 | Process data 41 | :return: str 42 | """ 43 | 44 | if response.status in self.DEFAULT_STATUSES: 45 | super().process(response) 46 | 47 | if 0 < len(self._body): 48 | title = re.search('(.+?)', self._body, re.IGNORECASE | re.DOTALL) 49 | if None is not title and None is not re.search(self.INDEX_OF_TITLE, title.group(1), re.IGNORECASE): 50 | return self.RESPONSE_INDEX 51 | return None 52 | -------------------------------------------------------------------------------- /src/core/http/plugins/response/provider/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | from .provider import ResponsePluginProvider 20 | 21 | -------------------------------------------------------------------------------- /src/core/http/plugins/response/provider/provider.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | from src.core import helper 20 | 21 | 22 | class ResponsePluginProvider(object): 23 | """"ResponsePluginProvider class""" 24 | 25 | def __init__(self): 26 | """ 27 | PluginProvider constructor 28 | """ 29 | self._status = 0 30 | self._headers = {} 31 | self._body = '' 32 | 33 | def __set_body(self, body): 34 | """ 35 | Set response data 36 | :param str body: response data 37 | :return: None 38 | """ 39 | 40 | if False is isinstance(body, str): 41 | self._body = helper.decode(body) 42 | 43 | def process(self, response): 44 | """ 45 | Process data from the given response object. 46 | :param urllib3.response.HTTPResponse response: The response object containing the data to be processed. 47 | :return: A string representing the processed data. 48 | """ 49 | 50 | self._status = int(float(response.status)) 51 | self._headers = response.headers 52 | self.__set_body(response.data) 53 | 54 | pass 55 | -------------------------------------------------------------------------------- /src/core/http/plugins/response/skipempty.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | from .provider import ResponsePluginProvider 20 | 21 | 22 | class SkipemptyResponsePlugin(ResponsePluginProvider): 23 | """ SkipemptyResponsePlugin class""" 24 | 25 | DESCRIPTION = 'SkipEmpty (skip empty success pages)' 26 | RESPONSE_INDEX = 'skip' 27 | DEFAULT_STATUSES = [100, 101, 200, 201, 202, 203, 204, 205, 206, 207, 208] 28 | DEFAULT_RECON_TO_SKIP_EMPTY_PAGE = 500 29 | 30 | def __init__(self, void): 31 | """ 32 | ResponsePluginProvider constructor 33 | """ 34 | 35 | ResponsePluginProvider.__init__(self) 36 | 37 | def process(self, response): 38 | """ 39 | Process data 40 | :return: str 41 | """ 42 | 43 | if response.status in self.DEFAULT_STATUSES: 44 | super().process(response) 45 | if 'Content-Length' in self._headers: 46 | if self.DEFAULT_RECON_TO_SKIP_EMPTY_PAGE >= int(self._headers['Content-Length']): 47 | return self.RESPONSE_INDEX 48 | else: 49 | return None 50 | elif self.DEFAULT_RECON_TO_SKIP_EMPTY_PAGE >= len(self._body): 51 | return self.RESPONSE_INDEX 52 | return None 53 | 54 | 55 | -------------------------------------------------------------------------------- /src/core/http/plugins/response/skipsizes.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | from .provider import ResponsePluginProvider 20 | from src.core.filesystem import FileSystem 21 | from src.core.helper import Helper 22 | 23 | 24 | class SkipSizesResponsePlugin(ResponsePluginProvider): 25 | """ SkipSizesResponsePlugin class""" 26 | 27 | DESCRIPTION = 'SkipSizesStatuses (skip target sizes of page: {} kbs for 200 OK redirects)' 28 | RESPONSE_INDEX = 'skip' 29 | DEFAULT_STATUSES = [200] 30 | SIZE_VALUES = None 31 | 32 | def __init__(self, values): 33 | """ 34 | ResponsePluginProvider constructor 35 | """ 36 | if values is not None: 37 | self.SIZE_VALUES = Helper.to_list(values, ':') 38 | size_list = list(map(lambda x: str(x)+'KB', self.SIZE_VALUES)) 39 | size_string = ','.join(self.SIZE_VALUES) 40 | self.DESCRIPTION = self.DESCRIPTION.format(size_string) 41 | self.SIZE_VALUES = size_list 42 | ResponsePluginProvider.__init__(self) 43 | 44 | def process(self, response): 45 | """ 46 | Process the given response data. 47 | 48 | :param response: The response object to be processed. 49 | :type response: object 50 | :return: The response index if the data meets the specified conditions, otherwise None. 51 | :rtype: str or None 52 | """ 53 | if hasattr(response, 'status') and response.status in self.DEFAULT_STATUSES: 54 | super().process(response) 55 | if 'Content-Length' in self._headers: 56 | for size in self.SIZE_VALUES: 57 | if size == FileSystem.human_size(int(self._headers['Content-Length']), 0): 58 | return self.RESPONSE_INDEX 59 | else: 60 | for size in self.SIZE_VALUES: 61 | if size == FileSystem.human_size(len(self._body), 0): 62 | return self.RESPONSE_INDEX 63 | return None 64 | -------------------------------------------------------------------------------- /src/core/http/plugins/response_plugin.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | import importlib 20 | from .exceptions import ResponsePluginError 21 | 22 | 23 | class ResponsePlugin(object): 24 | """ResponsePlugin class""" 25 | 26 | @staticmethod 27 | def load(plugin): 28 | """ 29 | Load response plugin 30 | :param str plugin: response plugin name 31 | :raise ResponsePluginError 32 | :return: src.core.http.plugins.response.provider.provider.ResponsePluginProvider 33 | """ 34 | 35 | plugin_value = None 36 | 37 | try: 38 | plugin_name, plugin_value = plugin.split('=') 39 | except ValueError: 40 | plugin_name = plugin 41 | pass 42 | try: 43 | package_module = importlib.import_module('src.core.http.plugins.response') 44 | 45 | try: 46 | response_plugin = getattr(package_module, plugin_name) 47 | return response_plugin(plugin_value) 48 | except (TypeError, AttributeError, Exception) as error: 49 | raise ResponsePluginError('Unable to get response plugin `{plugin}`. Reason: {error}' 50 | .format(plugin=plugin_name, error=error)) 51 | except ImportError: 52 | raise ResponsePluginError('Unable to get response\'s plugins') 53 | -------------------------------------------------------------------------------- /src/core/http/providers/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | from .cookies import CookiesProvider 20 | from .debug import DebugProvider 21 | from .header import HeaderProvider 22 | from .user_agent import UserAgentHeaderProvider 23 | from .connection import ConnectionHeaderProvider 24 | from .request import RequestProvider 25 | from .response import ResponseProvider 26 | 27 | -------------------------------------------------------------------------------- /src/core/http/providers/accept.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | import random 20 | 21 | 22 | class AcceptHeaderProvider(object): 23 | """ AcceptHeaderProvider class""" 24 | 25 | def __init__(self): 26 | """ 27 | Init interface 28 | """ 29 | 30 | self.__accept = '*/*' 31 | 32 | self.__accept_encoding = 'identity' 33 | 34 | self.__accept_language = ( 35 | 'en-US,en;q=0.5,ru-RU,ru;q=0.8', 36 | 'ru-RU,ru;q=0.8,en-US;q=0.6,en;q=0.4,uk;q=0.2,es;q=0.2,pl;q=0.2', 37 | 'en,en-gb;q=0.8, en;q=0.7' 38 | ) 39 | 40 | @property 41 | def _accept(self): 42 | """ 43 | Get 'Accept' Header 44 | :return: str 45 | """ 46 | 47 | return self.__accept 48 | 49 | @property 50 | def _accept_encoding(self): 51 | """ 52 | Get 'Accept-Encoding' Header 53 | :return: str 54 | """ 55 | 56 | return self.__accept_encoding 57 | 58 | @property 59 | def _accept_language(self): 60 | """ 61 | Get 'Accept-Language' Header 62 | :return: str 63 | """ 64 | 65 | index = random.randrange(0, len(self.__accept_language)) 66 | accept = self.__accept_language[index] 67 | 68 | return accept 69 | -------------------------------------------------------------------------------- /src/core/http/providers/cache.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | class CacheControlProvider(object): 20 | """ CacheControlProvider class""" 21 | 22 | def __init__(self): 23 | """ 24 | Init interface 25 | """ 26 | 27 | self.__cache_control = 'max-age=0' 28 | 29 | @property 30 | def _cache_control(self): 31 | """ 32 | Get 'Cache-Control' Header 33 | :return: str 34 | """ 35 | 36 | return self.__cache_control 37 | -------------------------------------------------------------------------------- /src/core/http/providers/connection.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | 20 | class ConnectionHeaderProvider(object): 21 | """ ConnectionHeaderProvider class""" 22 | 23 | KEEP_ALIVE = 'keep-alive' 24 | 25 | def __init__(self, config): 26 | """ 27 | Init interface 28 | Parameters: 29 | """ 30 | 31 | self.__cfg = config 32 | 33 | @property 34 | def _keep_alive(self): 35 | """ 36 | Get 'Connection' Header 37 | :return: str 38 | """ 39 | 40 | return self.KEEP_ALIVE 41 | -------------------------------------------------------------------------------- /src/core/http/providers/cookies.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | 20 | class CookiesProvider(object): 21 | """ CookiesProvider class""" 22 | 23 | def __init__(self): 24 | """ 25 | Init interface 26 | """ 27 | 28 | self._cookies = None 29 | 30 | @property 31 | def _is_cookie_fetched(self): 32 | """ 33 | Check if cookies have been fetched from response 34 | :return: bool 35 | """ 36 | 37 | return False if None is self._cookies else True 38 | 39 | def _fetch_cookies(self, headers): 40 | """ 41 | Fetch cookies from response 42 | :param dict headers: header 43 | :return: None 44 | """ 45 | 46 | if 'set-cookie' in headers: 47 | self._cookies = headers.get('set-cookie') 48 | 49 | def _push_cookies(self): 50 | """ 51 | Push cookies to request 52 | :return: str cookies 53 | """ 54 | 55 | return self._cookies.strip() 56 | -------------------------------------------------------------------------------- /src/core/http/providers/debug.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | 20 | class DebugProvider(object): 21 | """ DebugProvider class""" 22 | 23 | @property 24 | def level(self): 25 | """ 26 | Get debug level 27 | :return: int 28 | """ 29 | 30 | return None 31 | 32 | def debug_user_agents(self): 33 | """ 34 | Debug info for user agent 35 | :return: bool 36 | """ 37 | 38 | pass 39 | 40 | def debug_connection_pool(self, keymsg, pool, connection_type): 41 | """ 42 | Debug connection pool message 43 | :param str keymsg: tpl key 44 | :param object pool: pool object 45 | :param object connection_type: type string 46 | :return: bool 47 | """ 48 | 49 | pass 50 | 51 | def debug_proxy_pool(self): 52 | """ 53 | Debug proxy pool message 54 | :return: bool 55 | """ 56 | 57 | pass 58 | 59 | def debug_list(self, total_lines): 60 | """ 61 | Debug scan list 62 | :param int total_lines: total list lines 63 | :return: bool 64 | """ 65 | 66 | pass 67 | 68 | def debug_request(self, request_header, url, method): 69 | """ 70 | Debug request 71 | :param dict request_header: request header 72 | :param str url: request url 73 | :param str method: request method 74 | :return: bool 75 | """ 76 | 77 | pass 78 | 79 | def debug_response(self, response_header): 80 | """ 81 | Debug response 82 | :param dict response_header: response header 83 | :return: bool 84 | """ 85 | 86 | pass 87 | 88 | def debug_request_uri(self, status, request_uri, **kwargs): 89 | """ 90 | Debug request_uri 91 | :param int status: response status 92 | :param str request_uri: request urli 93 | :return: bool 94 | """ 95 | 96 | pass 97 | 98 | def debug_load_sniffer_plugin(self, description): 99 | """ 100 | Debug load sniffers plugin 101 | :param str description: plugin description 102 | :return: bool 103 | """ 104 | 105 | pass 106 | -------------------------------------------------------------------------------- /src/core/http/providers/header.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | from urllib3._collections import HTTPHeaderDict 20 | 21 | from .accept import AcceptHeaderProvider 22 | from .cache import CacheControlProvider 23 | 24 | 25 | class HeaderProvider(AcceptHeaderProvider, CacheControlProvider): 26 | """ HeaderProvider class""" 27 | 28 | def __init__(self, config): 29 | """ 30 | Init interface. 31 | Accept external params 32 | :param src.lib.browser.config.Config config: browser configurations 33 | """ 34 | 35 | self.__headers = HTTPHeaderDict() 36 | 37 | self.__cfg = config 38 | 39 | AcceptHeaderProvider.__init__(self) 40 | CacheControlProvider.__init__(self) 41 | 42 | def add_header(self, key, value): 43 | """ 44 | Add custom header 45 | 46 | :param str key: header name 47 | :param str value: header value 48 | :return: HeaderProvider 49 | """ 50 | 51 | self.__headers.update({key.strip(): value.strip()}) 52 | return self 53 | 54 | @property 55 | def _headers(self): 56 | """ 57 | Get Headers 58 | :return: dict headers 59 | """ 60 | 61 | origin = ''.join([self.__cfg.scheme, self.__cfg.host]) 62 | referer = ''.join([self.__cfg.scheme, self.__cfg.host]) + ':' + str(self.__cfg.port) 63 | self.add_header('Accept', self._accept) \ 64 | .add_header('Accept-Encoding', self._accept_encoding) \ 65 | .add_header('Accept-Language', self._accept_language) \ 66 | .add_header('Origin', origin) \ 67 | .add_header('Referer', referer) \ 68 | .add_header('Cache-Control', self._cache_control) \ 69 | .add_header('Upgrade-Insecure-Requests', '1') \ 70 | .add_header('Pragma', 'no-cache') 71 | return self.__headers 72 | -------------------------------------------------------------------------------- /src/core/http/providers/request.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | from .cookies import CookiesProvider 20 | from .header import HeaderProvider 21 | from .user_agent import UserAgentHeaderProvider 22 | from .connection import ConnectionHeaderProvider 23 | 24 | 25 | class RequestProvider(CookiesProvider, HeaderProvider, UserAgentHeaderProvider, ConnectionHeaderProvider): 26 | """ RequestProvider class""" 27 | 28 | _HTTP_DBG_LEVEL = 2 29 | 30 | def __init__(self, config, agent_list): 31 | """ 32 | Init interface 33 | :param src.lib.browser.config.Config config: configurations 34 | :param dict agent_list: list of user agents 35 | """ 36 | 37 | HeaderProvider.__init__(self, config) 38 | ConnectionHeaderProvider.__init__(self, config) 39 | UserAgentHeaderProvider.__init__(self, config, agent_list) 40 | CookiesProvider.__init__(self) 41 | 42 | def request(self, url): 43 | """ 44 | Client request 45 | :param str url: request uri 46 | :return: None 47 | """ 48 | 49 | pass 50 | 51 | def cookies_middleware(self, is_accept, response): 52 | """ 53 | Route fetched cookies from first response to the next requests 54 | :param is_accept: Is cookies was accepted 55 | :param urllib3.response.BaseHTTPResponse response: Http response 56 | :return: None 57 | """ 58 | 59 | if True is is_accept and hasattr(response, 'headers'): 60 | self._fetch_cookies(response.headers) 61 | if True is self._is_cookie_fetched: 62 | self.add_header('Cookie', self._push_cookies()) 63 | -------------------------------------------------------------------------------- /src/core/http/providers/user_agent.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | import random 20 | 21 | 22 | class UserAgentHeaderProvider(object): 23 | """ UserAgentHeaderProvider class""" 24 | 25 | def __init__(self, config, agent_list=()): 26 | """ 27 | Init interface 28 | Parameters: 29 | agent_list (tuple, optional): A tuple containing the initial list of agents. Defaults to an empty tuple. 30 | """ 31 | 32 | self.__cfg = config 33 | self.__agent_list = agent_list 34 | 35 | @property 36 | def _user_agent(self): 37 | """ 38 | Get 'User-Agent' Header 39 | :return: str 40 | """ 41 | 42 | if True is self.__cfg.is_random_user_agent: 43 | index = random.randrange(0, len(self.__agent_list)) 44 | user_agent = self.__agent_list[index].strip() 45 | else: 46 | user_agent = self.__cfg.user_agent 47 | return user_agent 48 | -------------------------------------------------------------------------------- /src/core/http/socks.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | import socket 20 | from .exceptions import SocketError 21 | 22 | 23 | class Socket(object): 24 | 25 | """Socket class""" 26 | 27 | @staticmethod 28 | def ping(host, port, timeout=10): 29 | """ 30 | Ping remote host 31 | :param str host: target host 32 | :param int port: target port 33 | :param int timeout: connection timeout 34 | :raise SocketError 35 | :return: None 36 | """ 37 | 38 | sock = socket.socket() 39 | 40 | try: 41 | 42 | sock.settimeout(timeout) 43 | sock.connect((host, port)) 44 | 45 | except (socket.gaierror, socket.error, socket.timeout, SocketError) as error: 46 | raise SocketError(error) 47 | finally: 48 | sock.close() 49 | 50 | @staticmethod 51 | def get_ip_address(host): 52 | """ 53 | Get remote ip address 54 | :param str host: target host 55 | :raise SocketError 56 | :return: str 57 | """ 58 | 59 | try: 60 | ip_address = socket.gethostbyname(host) 61 | return ip_address 62 | except socket.gaierror as error: 63 | raise SocketError(str(error)) 64 | 65 | @staticmethod 66 | def get_ips_addresses(host): 67 | """ 68 | Get remote ip addresses 69 | :param str host: target host 70 | :return: list 71 | """ 72 | 73 | try: 74 | _, _, ips_list = socket.gethostbyname_ex(host) 75 | if not ips_list: 76 | ips = '' 77 | else: 78 | ips = '['+', '.join(ips_list) +']' 79 | except socket.gaierror: 80 | ips = '' 81 | return ips 82 | -------------------------------------------------------------------------------- /src/core/logger/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | from .exception import LoggerException 20 | from .logger import Logger 21 | 22 | -------------------------------------------------------------------------------- /src/core/logger/colorize.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | import ctypes 20 | import logging 21 | import os 22 | import re 23 | 24 | 25 | class ColorizingStreamHandler(logging.StreamHandler): 26 | 27 | """ ColorizingStreamHandler class""" 28 | 29 | # color names to indices 30 | color_map = { 31 | 'black': 0, 32 | 'red': 1, 33 | 'green': 2, 34 | 'yellow': 3, 35 | 'blue': 4, 36 | 'magenta': 5, 37 | 'cyan': 6, 38 | 'white': 7 39 | } 40 | 41 | # levels to (background, foreground, bold/intense) 42 | level_map = { 43 | logging.DEBUG: (None, 'blue', False), 44 | logging.INFO: (None, 'black', False), 45 | logging.WARNING: (None, 'yellow', False), 46 | logging.ERROR: (None, 'red', False), 47 | logging.CRITICAL: ('red', 'white', True) 48 | } 49 | 50 | csi = '\x1b[' 51 | reset = '\x1b[0m' 52 | 53 | @property 54 | def is_tty(self): 55 | """ 56 | Is tty output check 57 | :return: bool 58 | """ 59 | 60 | isatty = getattr(self.stream, 'isatty', None) 61 | return isatty and isatty() 62 | 63 | def emit(self, record): 64 | """ 65 | Emmit message 66 | :param str record: message 67 | :raise Error 68 | :return: None 69 | """ 70 | 71 | try: 72 | message = self.format(record) 73 | stream = self.stream 74 | if not self.is_tty: 75 | stream.write(message) 76 | else: 77 | self.output_colorized(message) 78 | stream.write(getattr(self, 'terminator', '\n')) 79 | self.flush() 80 | except (KeyboardInterrupt, SystemExit): 81 | raise 82 | except Exception as error: 83 | record.msg = error 84 | self.handleError(record) 85 | 86 | if os.name != 'nt': 87 | def output_colorized(self, message): 88 | """ 89 | Prepare colorized string 90 | :param str message: message 91 | :return: None 92 | """ 93 | 94 | self.stream.write(message) 95 | 96 | else: 97 | ansi_esc = re.compile(r'\x1b\[((?:\d+)(?:;(?:\d+))*)m') 98 | 99 | nt_color_map = { 100 | 0: 0x00, # black 101 | 1: 0x04, # red 102 | 2: 0x02, # green 103 | 3: 0x06, # yellow 104 | 4: 0x01, # blue 105 | 5: 0x05, # magenta 106 | 6: 0x03, # cyan 107 | 7: 0x07 # white 108 | } 109 | 110 | def output_colorized(self, message): 111 | """ 112 | Prepare colorized string 113 | :param str message: message 114 | :return: None 115 | """ 116 | 117 | parts = self.ansi_esc.split(message) 118 | write = self.stream.write 119 | h = None 120 | fd = getattr(self.stream, 'fileno', None) 121 | if fd is not None: 122 | fd = fd() 123 | if fd in (1, 2): # stdout or stderr 124 | h = ctypes.windll.kernel32.GetStdHandle(-10 - fd) 125 | while parts: 126 | text = parts.pop(0) 127 | if text: 128 | write(text) 129 | if parts: 130 | params = parts.pop(0) 131 | if h is not None: 132 | params = [int(p) for p in params.split(';')] 133 | color = 0 134 | for p in params: 135 | if 40 <= p <= 47: 136 | color |= self.nt_color_map[p - 40] << 4 137 | elif 30 <= p <= 37: 138 | color |= self.nt_color_map[p - 30] 139 | elif p == 1: 140 | color |= 0x08 # foreground intensity on 141 | elif p == 0: # reset to default color 142 | color = 0x07 143 | else: 144 | pass # error condition ignored 145 | ctypes.windll.kernel32.SetConsoleTextAttribute(h, color) 146 | -------------------------------------------------------------------------------- /src/core/logger/config.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | import os 20 | 21 | from src.core import filesystem 22 | from src.core import CoreConfig 23 | 24 | 25 | def exception_log(): 26 | """ 27 | Get exception log path 28 | :return: string 29 | """ 30 | 31 | exception_filelog = CoreConfig.get('data').get('exceptions_log') 32 | return filesystem.getabsname(exception_filelog) 33 | 34 | 35 | class Config(object): 36 | 37 | """Config class""" 38 | 39 | logdir = os.path.dirname(exception_log()) 40 | exceptions = { 41 | "version": 1, 42 | "disable_existing_loggers": False, 43 | "formatters": { 44 | "exception_format": { 45 | "format": "%(asctime)s [%(levelname)s] : %(message)s", 46 | "datefmt": "%Y-%m-%d %H:%M:%S" 47 | } 48 | }, 49 | "handlers": { 50 | "exception_file_handler": { 51 | "level": "ERROR", 52 | "formatter": "exception_format", 53 | "class": "logging.handlers.RotatingFileHandler", 54 | "filename": exception_log(), 55 | "maxBytes": 10485760, 56 | "backupCount": 10 57 | } 58 | }, 59 | "loggers": { 60 | "exceptions": { 61 | "handlers": ["exception_file_handler"] 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/core/logger/exception.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | import inspect 20 | import logging 21 | import logging.config 22 | 23 | from src.core import filesystem 24 | from .config import Config 25 | 26 | 27 | class LoggerException(object): 28 | 29 | """ Exception class """ 30 | 31 | @staticmethod 32 | def log(class_name='Error', message=''): 33 | """ 34 | Syslog error handler 35 | :param str class_name: log name 36 | :param str message: log message 37 | :raise Error 38 | :return: None 39 | """ 40 | 41 | try: 42 | 43 | filesystem.makedir(Config.logdir) 44 | logging.config.dictConfig(Config.exceptions) 45 | logger = logging.getLogger('exceptions') 46 | func = inspect.currentframe().f_back.f_code 47 | message = "{class_name}: {message} in {file} -> {func}() line {line}".format( 48 | class_name=class_name, 49 | message=message, 50 | file=func.co_filename, 51 | func=func.co_name, 52 | line=func.co_firstlineno) 53 | logger.error(message) 54 | except (Exception, ValueError): 55 | # skip error undefined owner 56 | pass 57 | -------------------------------------------------------------------------------- /src/core/logger/logger.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | import logging 20 | import logging.config 21 | import sys 22 | import time 23 | from inspect import currentframe 24 | from .rainbow import RainbowLoggingHandler 25 | 26 | 27 | class Logger(object): 28 | 29 | """ Logger class""" 30 | 31 | _record = None 32 | 33 | _levels = {'error': 40, 'warning': 30, 'info': 20, 'debug': 10} 34 | 35 | @staticmethod 36 | def inline(msg='', status='info'): 37 | """ 38 | Formatted log message for inline console stdout 39 | :param str msg: formatted message 40 | :param str status: status name 41 | :return: str 42 | """ 43 | 44 | if None is Logger._record: 45 | Logger._record = type('record', (object,), 46 | dict(exc_info=False, 47 | stack_info=False, 48 | exc_text=False, 49 | name='', 50 | levelno=Logger._levels.get(status), 51 | funcName=status, 52 | lineno=currentframe().f_back.f_lineno) 53 | ) 54 | 55 | Logger._record.created = time.time() 56 | 57 | # noinspection PyPep8Naming 58 | def getMessage(__class__): 59 | """ 60 | Emulate message 61 | 62 | :param __class__: current class 63 | :return: str 64 | """ 65 | 66 | del __class__ 67 | 68 | return msg 69 | 70 | setattr(Logger._record, 'getMessage', classmethod(getMessage)) 71 | message = RainbowLoggingHandler().colorize(Logger._record) 72 | return message 73 | 74 | @staticmethod 75 | def log(name=__name__): 76 | """ 77 | Log handler 78 | :param str name: log name 79 | :return: logging 80 | """ 81 | 82 | logger = logging.getLogger(name) 83 | 84 | if not len(logger.handlers): 85 | logger.setLevel(logging.ERROR) 86 | logger.setLevel(logging.INFO) 87 | logger.setLevel(logging.WARNING) 88 | logger.setLevel(logging.DEBUG) 89 | handler = RainbowLoggingHandler(sys.stdout) 90 | logger.addHandler(handler) 91 | 92 | return logger 93 | -------------------------------------------------------------------------------- /src/core/logger/rainbow.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | import logging 20 | import re 21 | 22 | from .colorize import ColorizingStreamHandler 23 | from src.core.system import Term 24 | 25 | 26 | class RainbowLoggingHandler(ColorizingStreamHandler): 27 | 28 | """ Class RainbowLoggingHandler """ 29 | 30 | # Define color for message payload 31 | level_map = { 32 | logging.DEBUG: ('cyan', False), 33 | logging.INFO: ('white', False), 34 | logging.WARNING: ('yellow', False), 35 | logging.ERROR: ('red', True), 36 | logging.CRITICAL: ('red', True) 37 | } 38 | 39 | date_format = "%H:%M:%S" 40 | 41 | #: How many characters reserve to function name logging 42 | who_padding = 7 43 | 44 | def get_color(self, fg=None, bold=False): 45 | """ 46 | Construct a terminal color code 47 | :param str fg: Symbolic name of foreground color 48 | :param bool bold: Brightness bit 49 | """ 50 | 51 | params = [] 52 | 53 | if fg in self.color_map: 54 | params.append(str(self.color_map[fg] + 30)) 55 | if bold: 56 | params.append('1') 57 | 58 | color_code = ''.join((self.csi, ';'.join(params), 'm')) 59 | 60 | return color_code 61 | 62 | def colorize(self, record): 63 | """ 64 | Get a special format string with ASCII color codes 65 | :param dict|None record: logging record 66 | :return: str 67 | """ 68 | 69 | # Dynamic message color based on logging level 70 | if not hasattr(record, 'levelno'): 71 | record.levelno = 20 72 | fg, bold = self.level_map[record.levelno] 73 | 74 | template = [ 75 | "[", self.get_color("black"), 76 | "%(asctime)s", self.reset, "] ", 77 | "", 78 | "", 79 | "%(padded_who)s", self.reset, " ", self.get_color(fg, bold), "%(message)s", self.reset] 80 | 81 | format_string = "".join(template) 82 | 83 | who = [self.get_color("green"), getattr(record, "funcName", ""), self.get_color("black", True), ":", 84 | self.get_color("cyan")] 85 | 86 | who = "".join(who) 87 | # We need to calculate padding length manualy 88 | # as color codes mess up string length based calcs 89 | unformatted_who = getattr(record, "funcName", "") 90 | 91 | if len(unformatted_who) < self.who_padding: 92 | spaces = " " * (self.who_padding - len(unformatted_who)) 93 | else: 94 | spaces = "" 95 | 96 | record.padded_who = who + spaces 97 | 98 | formatter = logging.Formatter(format_string, self.date_format) 99 | output = formatter.format(record) 100 | # Clean cache so the color codes of traceback don't leak to other formatters 101 | record.ext_text = None 102 | # noinspection PyUnresolvedReferences 103 | width = int(Term.terminal_size['width']) 104 | pure_length = self.__pure_line_len(output) 105 | length = width - pure_length 106 | if record.levelno != logging.DEBUG: 107 | if pure_length > width and record.levelno != logging.ERROR: 108 | output = (output[:width] + '...') 109 | 110 | end = (' ' * length)[:length] 111 | return output + end 112 | 113 | @classmethod 114 | def __pure_line_len(cls, string): 115 | """ 116 | Get pure line 117 | :param str string: input string 118 | :return: str 119 | """ 120 | 121 | ansi_escape = re.compile(r'\x1b[^m]*m') 122 | return len(ansi_escape.sub('', string)) 123 | 124 | def format(self, record): 125 | """ 126 | Formats a record for output. 127 | Takes a custom formatting path on a terminal. 128 | :param dict record: input record logging 129 | :return: str 130 | """ 131 | 132 | if self.is_tty: 133 | message = self.colorize(record) 134 | else: 135 | message = logging.StreamHandler.format(self, record) 136 | 137 | return message 138 | -------------------------------------------------------------------------------- /src/core/options/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | from .options import Options 20 | -------------------------------------------------------------------------------- /src/core/options/exceptions.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | # noinspection PyCompatibility 20 | from argparse import ArgumentParser 21 | 22 | 23 | class ArgumentParserError(Exception): 24 | 25 | """ArgumentParserError class""" 26 | pass 27 | 28 | 29 | class ThrowingArgumentParser(ArgumentParser): 30 | 31 | """ThrowingArgumentParser class""" 32 | 33 | @classmethod 34 | def error(cls, message): 35 | """ 36 | Error message 37 | :param message: message 38 | :raise ArgumentParserError 39 | :return: None 40 | """ 41 | 42 | raise ArgumentParserError(message) 43 | 44 | 45 | class OptionsError(Exception): 46 | 47 | """OptionsError class""" 48 | 49 | def __init__(self, message): 50 | """ 51 | Error message 52 | :param message: message 53 | :return: None 54 | """ 55 | 56 | super(OptionsError, self).__init__(message) 57 | 58 | 59 | class FilterError(Exception): 60 | 61 | """FilterError class""" 62 | 63 | def __init__(self, message): 64 | """ 65 | Error message 66 | :param message: message 67 | :return: None 68 | """ 69 | 70 | super(FilterError, self).__init__(message) 71 | -------------------------------------------------------------------------------- /src/core/options/filter.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | import re 20 | 21 | from src.core import helper 22 | from .exceptions import FilterError 23 | 24 | 25 | class Filter(object): 26 | 27 | """Filter class""" 28 | 29 | URL_REGEX = "^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})|(?:[-A-Za-z0-9]+\.)+([-A-Za-z]|\w){2,8}$" 30 | 31 | @staticmethod 32 | def filter(args): 33 | """ 34 | Filter options 35 | :param dict args: 36 | :return: dict 37 | """ 38 | 39 | filtered = {} 40 | 41 | for key, value in args.items(): 42 | if 'scan' == key: 43 | filtered['scan'] = Filter.scan(value) 44 | elif 'host' == key: 45 | filtered['host'] = Filter.host(value) 46 | filtered['scheme'] = Filter.scheme(value) 47 | filtered['ssl'] = Filter.ssl(filtered['scheme']) 48 | else: 49 | if 'proxy' == key: 50 | filtered[key] = Filter.proxy(value) 51 | else: 52 | filtered[key] = value 53 | 54 | return filtered 55 | 56 | @staticmethod 57 | def scheme(hostname): 58 | """ 59 | Get the scheme of the input hostname. 60 | 61 | :param hostname: A string representing the input hostname. 62 | :type hostname: str 63 | :return: A string representing the scheme of the input hostname. 64 | :rtype: str 65 | """ 66 | 67 | scheme = helper.parse_url(hostname).scheme 68 | if not scheme: 69 | scheme = 'http' 70 | return scheme + "://" 71 | 72 | @staticmethod 73 | def ssl(scheme): 74 | """ 75 | If `ssl` in action 76 | :param str scheme: scheme protocol 77 | :return: bool 78 | """ 79 | 80 | return 'https://' == scheme 81 | 82 | @staticmethod 83 | def host(hostname): 84 | """ 85 | Input `host` param filter 86 | :param str hostname: input hostname 87 | :raise FilterError 88 | :return: str 89 | """ 90 | 91 | if not re.search('http', hostname, re.IGNORECASE): 92 | if re.search('https', hostname, re.IGNORECASE): 93 | hostname = "https://" + hostname 94 | else: 95 | hostname = "http://" + hostname 96 | 97 | hostname = helper.parse_url(hostname).netloc 98 | regex = re.compile(r"" + Filter.URL_REGEX + "", re.UNICODE) 99 | 100 | if not regex.match(hostname): 101 | try: 102 | hostname = helper.decode_hostname(hostname) 103 | except UnicodeError as error: 104 | raise FilterError("\"{0}\" is invalid host. {1}".format(hostname, str(error))) 105 | if not regex.match(hostname): 106 | raise FilterError("\"{0}\" is invalid host. Use ip, http(s) or just hostname".format(hostname)) 107 | return hostname 108 | 109 | @staticmethod 110 | def proxy(proxyaddress): 111 | """ 112 | Input `proxy` param filter 113 | :param str proxyaddress: input proxy server address 114 | :raise FilterError 115 | :return: str 116 | """ 117 | 118 | proxy = helper.parse_url(proxyaddress) 119 | 120 | if proxy.scheme not in ['http', 'https', 'socks4', 'socks5'] or None is proxy.port: 121 | raise FilterError("\"{0}\" is invalid proxy in --proxy. Use scheme:ip:port format".format(proxyaddress)) 122 | return proxyaddress 123 | 124 | @staticmethod 125 | def scan(choose): 126 | """ 127 | Input `scan` type filter 128 | :param str choose: preferred scan type 129 | :return: str 130 | """ 131 | 132 | if choose not in ['directories', 'subdomains']: 133 | choose = 'directories' 134 | return choose 135 | -------------------------------------------------------------------------------- /src/core/system/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | from .process import Term 20 | from .output import Output 21 | -------------------------------------------------------------------------------- /src/core/system/exceptions.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | 20 | class CoreSystemError(Exception): 21 | 22 | """SystemError class""" 23 | 24 | def __init__(self, message): 25 | """ 26 | CoreSystemError class constructor 27 | :param str message: error message 28 | """ 29 | 30 | super(CoreSystemError, self).__init__(message) 31 | -------------------------------------------------------------------------------- /src/core/system/output.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | import sys 20 | import platform 21 | import os 22 | 23 | 24 | class Output(object): 25 | 26 | """Output class""" 27 | 28 | __is_windows = None 29 | 30 | @staticmethod 31 | def exit(msg): 32 | """ 33 | Abort session 34 | :param str msg: input message 35 | :return: None 36 | """ 37 | 38 | sys.exit(msg) 39 | 40 | @staticmethod 41 | def writels(msg, flush=True): 42 | """ 43 | Write to stdout on one line dynamically 44 | :param str msg: input message 45 | :param bool flush: force clear line 46 | :return: None 47 | """ 48 | 49 | sys.stdout.write("\r\x1b[K" + msg.__str__()) 50 | if True is flush: 51 | sys.stdout.flush() 52 | 53 | @staticmethod 54 | def writeln(msg): 55 | """ 56 | Write new line 57 | :param str msg: input message 58 | :return: None 59 | """ 60 | 61 | sys.stdout.write('{0}\n'.format(msg)) 62 | 63 | @staticmethod 64 | def version(): 65 | """ 66 | Interpreter version 67 | :return: string 68 | """ 69 | 70 | version = platform.python_version().split(".") 71 | return "{0}.{1}".format(version[0], version[1]) 72 | 73 | @property 74 | def is_windows(self): 75 | """ 76 | Check for windows signature 77 | :return: bool 78 | """ 79 | 80 | if None is Output.__is_windows: 81 | Output.__is_windows = True if sys.platform.startswith('win') or os.name == 'nt' else False 82 | return Output.__is_windows 83 | -------------------------------------------------------------------------------- /src/core/system/process.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | import os 20 | import signal 21 | import subprocess 22 | from .exceptions import CoreSystemError 23 | from .terminal import Terminal 24 | 25 | 26 | class Process(object): 27 | 28 | """ Process class""" 29 | 30 | def __init__(self, classname=None, typeobj=None, params=None): 31 | """ 32 | Init metaclass 33 | :param classname: passed classname 34 | :param str typeobj: passed classname type 35 | :param dict params: passed params 36 | """ 37 | 38 | del classname, typeobj, params 39 | self.ts = None 40 | 41 | @property 42 | def terminal_size(self): 43 | """ 44 | Get terminal window size 45 | :raise CoreSystemError 46 | :return: dict 47 | """ 48 | 49 | if getattr(self, 'ts', None) is None: 50 | (width, height) = Terminal().get_ts() 51 | self.ts = {'height': height, 'width': width} 52 | return self.ts 53 | 54 | @staticmethod 55 | def termination_handler(): 56 | """ 57 | Exit Ctrl-Z handler 58 | :return: None 59 | """ 60 | 61 | def kill_process(signum, frame): 62 | """ 63 | Kill process os signal 64 | :param int signum: signal code 65 | :param object frame: frame object 66 | :return: None 67 | """ 68 | 69 | del signum 70 | del frame 71 | 72 | os.kill(os.getpid(), signal.SIGTERM) 73 | 74 | sig = getattr(signal, 'SIGTSTP', signal.SIGABRT) 75 | signal.signal(sig, kill_process) 76 | 77 | @staticmethod 78 | def kill(): 79 | """ 80 | Immediatelly terminate process 81 | :return: None 82 | """ 83 | 84 | os.kill(os.getpid(), signal.SIGTERM) # or signal.SIGKILL 85 | 86 | @staticmethod 87 | def execute(process): 88 | """ 89 | Excecute OS process 90 | :param str process: os command 91 | :raise CoreSystemError 92 | :return: dic 93 | """ 94 | 95 | try: 96 | pr = subprocess.Popen(process, cwd=os.getcwd(), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 97 | (out, error) = pr.communicate() 98 | if pr.returncode != 0: 99 | raise OSError(error.strip()) 100 | 101 | return out 102 | except (subprocess.CalledProcessError, OSError) as error: 103 | raise CoreSystemError(error) 104 | 105 | 106 | class Term(metaclass=Process): 107 | """Term class""" 108 | 109 | __metaclass__ = None 110 | pass 111 | -------------------------------------------------------------------------------- /src/core/system/terminal.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | import platform 20 | import shlex 21 | import struct 22 | import subprocess 23 | 24 | 25 | class Terminal(object): 26 | 27 | """ Terminal class""" 28 | 29 | def get_ts(self): 30 | """ 31 | Get width and height of console 32 | :return: tuple 33 | """ 34 | 35 | current_os = platform.system() 36 | tuple_xy = (80, 25) # default value 37 | if current_os == 'Windows': 38 | tuple_xy = self.__get_ts_windows() 39 | if tuple_xy is None: 40 | tuple_xy = self.__get_ts_tput() 41 | if current_os in ['Linux', 'Darwin'] or current_os.startswith('CYGWIN'): 42 | tuple_xy = self.__get_ts_unix() 43 | return tuple_xy 44 | 45 | @staticmethod 46 | def __get_ts_windows(): 47 | """ 48 | Get windows terminal size 49 | :return: tuple 50 | """ 51 | 52 | # noinspection PyBroadException 53 | try: 54 | from ctypes import windll, create_string_buffer 55 | (sizex, sizey) = 25, 80 # default value 56 | h = windll.kernel32.GetStdHandle(-12) 57 | csbi = create_string_buffer(22) 58 | res = windll.kernel32.GetConsoleScreenBufferInfo(h, csbi) 59 | if res: 60 | (bufx, bufy, curx, cury, wattr, 61 | left, top, right, bottom, 62 | maxx, maxy) = struct.unpack("hhhhHhhhhhh", csbi.raw) 63 | sizex = right - left + 1 64 | sizey = bottom - top + 1 65 | return sizex, sizey 66 | except Exception: 67 | pass 68 | 69 | @staticmethod 70 | def __get_ts_unix(): 71 | """ 72 | Get unix terminal size 73 | :return tuple 74 | """ 75 | (height, width) = 25, 80 76 | 77 | try: 78 | (height, width) = subprocess.check_output(['stty', 'size']).split() 79 | except (AttributeError, subprocess.CalledProcessError): 80 | subprocess.check_output = Terminal.__legacy_call 81 | (height, width) = subprocess.check_output(['stty', 'size']).split() 82 | finally: 83 | return width, height 84 | 85 | @staticmethod 86 | def __legacy_call(*popenargs, **kwargs): 87 | """ 88 | Subprocess check output for legacy python version 2.6 89 | :param popenargs: 90 | :param kwargs: 91 | :return: 92 | """ 93 | 94 | if 'stdout' in kwargs: 95 | raise ValueError('stdout argument not allowed, it will be overridden.') 96 | process = subprocess.Popen(stdout=subprocess.PIPE, *popenargs, **kwargs) 97 | output, unused_err = process.communicate() 98 | retcode = process.poll() 99 | if retcode: 100 | cmd = kwargs.get("args") 101 | if cmd is None: 102 | cmd = popenargs[0] 103 | raise subprocess.CalledProcessError(retcode, cmd) 104 | del unused_err 105 | return output 106 | 107 | @staticmethod 108 | def __get_ts_tput(): 109 | """ 110 | Get terminal height / width 111 | :return: tuple 112 | """ 113 | 114 | try: 115 | cols = int(subprocess.check_call(shlex.split('tput cols'))) 116 | rows = int(subprocess.check_call(shlex.split('tput lines'))) 117 | return cols, rows 118 | except subprocess.CalledProcessError: 119 | pass 120 | -------------------------------------------------------------------------------- /src/exceptions.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | 20 | class SrcError(Exception): 21 | 22 | """SrcError class""" 23 | 24 | def __init__(self, error): 25 | """ 26 | SrcError class constructor 27 | :param str error: error message 28 | """ 29 | 30 | super(SrcError, self).__init__(error) 31 | -------------------------------------------------------------------------------- /src/lib/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | # noinspection PyPep8Naming 20 | from .browser import Browser as browser, BrowserError 21 | # noinspection PyPep8Naming 22 | from .events import EventHandler as events 23 | # noinspection PyPep8Naming 24 | from .io import Arguments as args, ArgumentsError 25 | # noinspection PyPep8Naming 26 | from .package import Package as package, PackageError 27 | # noinspection PyPep8Naming 28 | from .reader import Reader as reader, ReaderError 29 | # noinspection PyPep8Naming 30 | from .reporter import Reporter as reporter, ReporterError 31 | # noinspection PyPep8Naming 32 | from .tpl import Tpl as tpl, TplError 33 | 34 | -------------------------------------------------------------------------------- /src/lib/browser/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | from .browser import Browser 20 | from .exceptions import BrowserError 21 | -------------------------------------------------------------------------------- /src/lib/browser/exceptions.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | from src.core import exception 19 | 20 | 21 | class BrowserError(Exception): 22 | 23 | """BrowserError class""" 24 | 25 | def __init__(self, error): 26 | """ 27 | BrowserError class constructor 28 | :param Exception error: error 29 | """ 30 | 31 | class_name = type(error).__name__ 32 | 33 | if self.__class__.__name__ is not class_name: 34 | exception.log(class_name=class_name, message=str(error)) 35 | 36 | super(BrowserError, self).__init__("{0}: {1}".format(str(class_name), str(error))) 37 | -------------------------------------------------------------------------------- /src/lib/browser/filter.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | # noinspection PyPep8Naming 20 | from src.lib.tpl import Tpl as tpl 21 | 22 | 23 | class Filter(object): 24 | 25 | """Filter class""" 26 | 27 | # noinspection PyPep8Naming 28 | def __init__(self, Config, total_lines): 29 | """ 30 | Filter constructor 31 | :param Config: Config 32 | :param int total_lines: num lines in list 33 | """ 34 | 35 | if Config.threads > Config.DEFAULT_MAX_THREADS or Config.threads > total_lines: 36 | 37 | max_threads = total_lines if Config.DEFAULT_MAX_THREADS > total_lines else Config.DEFAULT_MAX_THREADS 38 | tpl.warning(key='thread_limit', threads=Config.threads, max=max_threads) 39 | Config.set_threads(max_threads) 40 | -------------------------------------------------------------------------------- /src/lib/browser/threadpool.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | import threading 20 | import time 21 | from queue import Queue 22 | 23 | # noinspection PyPep8Naming 24 | from src.lib.tpl import Tpl as tpl 25 | from .worker import Worker 26 | 27 | 28 | class ThreadPool(object): 29 | 30 | """ThreadPool class""" 31 | 32 | def __init__(self, num_threads, total_items, timeout): 33 | """ 34 | Initialize thread pool 35 | :param int num_threads: active workers 36 | :param int total_items: total items 37 | :param int timeout: delay between threads 38 | """ 39 | 40 | self.__queue = Queue(num_threads) 41 | self.__workers = [] 42 | self.total_items_size = total_items 43 | self.is_started = True 44 | 45 | for _ in range(num_threads): 46 | 47 | worker = Worker(self.__queue, num_threads, timeout) 48 | if False is worker.is_alive(): 49 | worker.daemon = True 50 | worker.start() 51 | self.__workers.append(worker) 52 | 53 | @property 54 | def size(self): 55 | """ 56 | Get pool size 57 | :return: int 58 | """ 59 | 60 | return self.__queue.qsize() 61 | 62 | @property 63 | def workers_size(self): 64 | """ 65 | Get pool workers (threads) 66 | :return: int 67 | """ 68 | 69 | return self.__workers.__len__() 70 | 71 | @property 72 | def items_size(self): 73 | """ 74 | Get pool items size 75 | :return: int 76 | """ 77 | 78 | counter = 0 79 | for worker in self.__workers: 80 | counter += worker.counter 81 | return counter 82 | 83 | def add(self, func, *args, **kargs): 84 | """ 85 | Add a task to the queue 86 | :param func func: callback function 87 | :param dict args: arguments 88 | :param kargs: keys arguments 89 | :return: None 90 | """ 91 | 92 | try: 93 | if True is self.is_started: 94 | if self.items_size < self.total_items_size: 95 | self.__queue.put((func, args, kargs)) 96 | except (SystemExit, KeyboardInterrupt): 97 | time.sleep(2) 98 | self.pause() 99 | 100 | def join(self): 101 | """ 102 | Join queue 103 | :return: None 104 | """ 105 | 106 | self.__queue.join() 107 | 108 | def pause(self): 109 | """ 110 | ThreadPool pause 111 | :raise KeyboardInterrupt 112 | :return: None 113 | """ 114 | 115 | self.is_started = False 116 | tpl.info(key='stop_threads', threads=len(self.__workers)) 117 | 118 | try: 119 | while 0 < threading.active_count(): 120 | for worker in threading.enumerate(): 121 | if threading.current_thread().__class__.__name__ != '_MainThread': 122 | worker.pause() 123 | time.sleep(2) 124 | 125 | char = tpl.prompt(key='option_prompt') 126 | if char.lower() == 'e': 127 | raise KeyboardInterrupt 128 | elif char.lower() == 'c': 129 | self.resume() 130 | break 131 | else: 132 | continue 133 | 134 | except (SystemExit, KeyboardInterrupt): 135 | raise KeyboardInterrupt 136 | 137 | def resume(self): 138 | """ 139 | Resume threadpool 140 | :return: None 141 | """ 142 | 143 | if False is self.is_started: 144 | tpl.info(key='resume_threads') 145 | for worker in self.__workers: 146 | worker.resume() 147 | self.is_started = True 148 | -------------------------------------------------------------------------------- /src/lib/browser/worker.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | import threading 20 | import time 21 | from queue import Empty as QueueEmptyError 22 | from threading import BoundedSemaphore, Event 23 | 24 | from src.core import process 25 | # noinspection PyPep8Naming 26 | from src.lib.tpl import Tpl as tpl 27 | 28 | 29 | class Worker(threading.Thread): 30 | 31 | """Worker class""" 32 | 33 | def __init__(self, queue, num_threads, timeout=0): 34 | """ 35 | Init thread worker 36 | :param Queue.Queue queue: simple queue object 37 | :param int num_threads: threads numbers 38 | :param int timeout: delay timeout 39 | """ 40 | 41 | super(Worker, self).__init__() 42 | self.__semaphore = BoundedSemaphore(num_threads) 43 | self.__event = Event() 44 | self.__event.set() 45 | self.__empty = False 46 | self.__running = True 47 | self.__queue = queue 48 | self.__timeout = timeout 49 | self.counter = 0 50 | 51 | def pause(self): 52 | """ 53 | Pause current worker 54 | :return: None 55 | """ 56 | 57 | self.__running = False 58 | self.__event.clear() 59 | 60 | def resume(self): 61 | """ 62 | Resume current worker 63 | :return: None 64 | """ 65 | 66 | self.__running = True 67 | self.__event.set() 68 | 69 | def run(self): 70 | """ 71 | Run current worker 72 | :return: None 73 | """ 74 | 75 | try: 76 | 77 | self.__event.wait() 78 | 79 | while self.__running: 80 | 81 | if 0 < self.__timeout: 82 | time.sleep(self.__timeout) 83 | 84 | try: 85 | self.__process() 86 | except QueueEmptyError: 87 | self.__empty = True 88 | 89 | finally: 90 | if not self.__event.is_set(): 91 | self.__semaphore.release() 92 | self.__event.wait() 93 | except Exception as error: 94 | self.terminate(str(error)) 95 | 96 | def __process(self): 97 | """ 98 | Task process 99 | :return: None 100 | """ 101 | 102 | func, args, kargs = self.__queue.get(block=True) 103 | self.counter += 1 104 | func(*args, **kargs) 105 | self.__queue.task_done() 106 | 107 | @classmethod 108 | def terminate(cls, msg): 109 | """ 110 | Terminate thread 111 | :param str msg: output message 112 | :return: None 113 | """ 114 | 115 | tpl.error(msg) 116 | process.kill() 117 | -------------------------------------------------------------------------------- /src/lib/events/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | from .events import EventHandler 20 | -------------------------------------------------------------------------------- /src/lib/events/events.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | from src.core import process 20 | 21 | 22 | class EventHandler(object): 23 | 24 | """EventHandler class""" 25 | 26 | @staticmethod 27 | def terminate(): 28 | """ 29 | Define termination event handler 30 | :return: None 31 | """ 32 | 33 | process.termination_handler() 34 | -------------------------------------------------------------------------------- /src/lib/io/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | from .arguments import Arguments 19 | from .exceptions import ArgumentsError 20 | 21 | -------------------------------------------------------------------------------- /src/lib/io/arguments.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | from src.core import options, OptionsError 20 | from src.core import helper 21 | from .exceptions import ArgumentsError 22 | 23 | 24 | class Arguments(object): 25 | 26 | """Arguments class""" 27 | 28 | @staticmethod 29 | def get_arguments(): 30 | """ 31 | Get input arguments with their options 32 | :raise ArgumentsError 33 | :return: dict 34 | """ 35 | 36 | try: 37 | args = options().get_arg_values() 38 | return args 39 | except OptionsError as error: 40 | raise ArgumentsError(str(error)) 41 | 42 | @staticmethod 43 | def is_arg_callable(arg): 44 | """ 45 | Check if argument is callable 46 | 47 | :param callable arg: 48 | :return: bool 49 | """ 50 | 51 | return helper.is_callable(arg) 52 | -------------------------------------------------------------------------------- /src/lib/io/exceptions.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | from src.core import exception 20 | 21 | 22 | class ArgumentsError(Exception): 23 | 24 | """ArgumentsError class""" 25 | 26 | def __init__(self, error): 27 | """ 28 | ArgumentsError class constructor 29 | :param str error: error message 30 | """ 31 | 32 | class_name = type(error).__name__ 33 | 34 | if self.__class__.__name__ is not class_name: 35 | exception.log(class_name=class_name, message=error) 36 | 37 | super(ArgumentsError, self).__init__("{0}: {1}".format(str(class_name), str(error))) 38 | -------------------------------------------------------------------------------- /src/lib/package/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | from .exceptions import PackageError 20 | from .package import Package 21 | 22 | -------------------------------------------------------------------------------- /src/lib/package/exceptions.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | from src.core import exception 20 | 21 | 22 | class PackageError(Exception): 23 | 24 | """PackageError class""" 25 | 26 | def __init__(self, error): 27 | """ 28 | PackageError class constructor 29 | :param str error: error message 30 | """ 31 | 32 | class_name = type(error).__name__ 33 | 34 | if self.__class__.__name__ is not class_name: 35 | exception.log(class_name=class_name, message=error) 36 | 37 | super(PackageError, self).__init__("{0}: {1}".format(str(class_name), str(error))) 38 | -------------------------------------------------------------------------------- /src/lib/reader/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | from .exceptions import ReaderError 20 | from .reader import Reader 21 | 22 | -------------------------------------------------------------------------------- /src/lib/reader/config.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | 20 | class Config(object): 21 | """Config class""" 22 | 23 | http_port = 80 24 | ssl_port = 443 25 | -------------------------------------------------------------------------------- /src/lib/reader/exceptions.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | from src.core import exception 19 | 20 | 21 | class ReaderError(Exception): 22 | 23 | """PackageError class""" 24 | 25 | def __init__(self, error): 26 | """ 27 | ReaderError class constructor 28 | :param str error: error message 29 | """ 30 | 31 | class_name = type(error).__name__ 32 | 33 | if self.__class__.__name__ is not class_name: 34 | exception.log(class_name=class_name, message=error) 35 | 36 | super(ReaderError, self).__init__("{0}: {1}".format(str(class_name), str(error))) 37 | -------------------------------------------------------------------------------- /src/lib/reporter/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | from .exceptions import ReporterError 20 | from .reporter import Reporter 21 | 22 | -------------------------------------------------------------------------------- /src/lib/reporter/exceptions.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | 20 | class ReporterError(Exception): 21 | 22 | """ReporterError class""" 23 | 24 | def __init__(self, message): 25 | """ 26 | Error message 27 | :param message: message 28 | :return: None 29 | """ 30 | 31 | super(ReporterError, self).__init__(message) 32 | -------------------------------------------------------------------------------- /src/lib/reporter/plugins/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | # noinspection PyPep8Naming 20 | from .std import StdReportPlugin as std 21 | # noinspection PyPep8Naming 22 | from .txt import TextReportPlugin as txt 23 | # noinspection PyPep8Naming 24 | from .json import JsonReportPlugin as json 25 | # noinspection PyPep8Naming 26 | from .html import HtmlReportPlugin as html 27 | 28 | -------------------------------------------------------------------------------- /src/lib/reporter/plugins/html.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | from .provider import PluginProvider 20 | from src.core import CoreConfig 21 | from src.core import filesystem, FileSystemError 22 | from json2html.jsonconv import Json2Html 23 | 24 | 25 | class HtmlReportPlugin(PluginProvider): 26 | """ HtmlReportPlugin class""" 27 | 28 | PLUGIN_NAME = 'HtmlReport' 29 | EXTENSION_SET = '.html' 30 | 31 | def __init__(self, target, data, directory=None): 32 | """ 33 | PluginProvider constructor 34 | :param str target: target host 35 | :param dict data: result set 36 | :param str directory: custom directory 37 | """ 38 | 39 | PluginProvider.__init__(self, target, data) 40 | 41 | try: 42 | 43 | if None is directory: 44 | directory = CoreConfig.get('data').get('reports') 45 | self.__target_dir = filesystem.makedir("".join((directory, self._target))) 46 | except FileSystemError as error: 47 | raise Exception(error) 48 | 49 | def process(self): 50 | """ 51 | Process data 52 | :return: str 53 | """ 54 | 55 | try: 56 | filesystem.clear(self.__target_dir, extension=self.EXTENSION_SET) 57 | resultset = Json2Html().convert(json=self._data, table_attributes='border="1" cellpadding="2"') 58 | self.record(self.__target_dir, self._target, resultset) 59 | except FileSystemError as error: 60 | raise Exception(error) 61 | -------------------------------------------------------------------------------- /src/lib/reporter/plugins/json.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | from .provider import PluginProvider 20 | from src.core import CoreConfig 21 | from src.core import filesystem, FileSystemError 22 | from src.core import helper 23 | 24 | 25 | class JsonReportPlugin(PluginProvider): 26 | """ JsonReportPlugin class""" 27 | 28 | PLUGIN_NAME = 'JsonReport' 29 | EXTENSION_SET = '.json' 30 | 31 | def __init__(self, target, data, directory=None): 32 | """ 33 | PluginProvider constructor 34 | :param str target: target host 35 | :param dict data: result set 36 | :param str directory: custom directory 37 | """ 38 | 39 | PluginProvider.__init__(self, target, data) 40 | 41 | try: 42 | if None is directory: 43 | directory = CoreConfig.get('data').get('reports') 44 | self.__target_dir = filesystem.makedir("".join((directory, self._target))) 45 | except FileSystemError as error: 46 | raise Exception(error) 47 | 48 | def process(self): 49 | """ 50 | Process data 51 | :return: str 52 | """ 53 | 54 | resultset = helper.to_json(self._data) 55 | 56 | try: 57 | filesystem.clear(self.__target_dir, extension=self.EXTENSION_SET) 58 | self.record(self.__target_dir, self._target, resultset) 59 | except (Exception, FileSystemError) as error: 60 | raise Exception(error) 61 | -------------------------------------------------------------------------------- /src/lib/reporter/plugins/provider/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | from .provider import PluginProvider 20 | 21 | -------------------------------------------------------------------------------- /src/lib/reporter/plugins/provider/provider.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | from src.core import filesystem, FileSystemError 20 | from src.lib import tpl 21 | 22 | 23 | class PluginProvider(object): 24 | """"PluginProvider class""" 25 | 26 | PLUGIN_NAME = 'PluginProvider' 27 | EXTENSION_SET = '.pp' 28 | 29 | def __init__(self, target, data): 30 | """ 31 | PluginProvider constructor 32 | :param str target: target host 33 | :param dict data: result set 34 | """ 35 | 36 | self._target = str(target) 37 | self._data = {} 38 | self.__set_data(data) 39 | 40 | def __set_data(self, data): 41 | """ 42 | Set report data 43 | :param dict data: 44 | :return: 45 | """ 46 | 47 | if False is isinstance(data, dict): 48 | raise TypeError("Report data has a wrong type") 49 | self._data = data 50 | 51 | def process(self): 52 | """ 53 | Process data 54 | :return: mixed 55 | """ 56 | 57 | pass 58 | 59 | @classmethod 60 | def record(cls, dirname, filename, resultset, separator=''): 61 | """ 62 | Record data process 63 | :param str dirname: report directory 64 | :param str filename: report filename 65 | :param list resultset: report result 66 | :param str separator: result separator 67 | :raise Exception 68 | :return: None 69 | """ 70 | 71 | try: 72 | filename = "".join((dirname, filesystem.sep, filename, cls.EXTENSION_SET)) 73 | filename = filesystem.makefile(filename) 74 | filesystem.writelist(filename, resultset, separator) 75 | tpl.info(key='report', plugin=cls.PLUGIN_NAME, dest=filesystem.getabsname(filename)) 76 | except FileSystemError as error: 77 | raise Exception(error) 78 | -------------------------------------------------------------------------------- /src/lib/reporter/plugins/std.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | from tabulate import tabulate 20 | 21 | from .provider import PluginProvider 22 | from src.core import sys 23 | 24 | 25 | class StdReportPlugin(PluginProvider): 26 | """ StdReportPlugin class""" 27 | 28 | def __init__(self, target, data, directory=None): 29 | """ 30 | PluginProvider constructor 31 | :param str target: target host 32 | :param dict data: result set 33 | """ 34 | 35 | PluginProvider.__init__(self, target, data) 36 | self.directory = directory 37 | 38 | def process(self): 39 | """ 40 | Process data 41 | :return: str 42 | """ 43 | 44 | data = self._data.get('total').items() 45 | title = 'Statistics ({0})'.format(self._target) 46 | sys.writeln(tabulate(data, headers=[title, 'Summary'], tablefmt="psql")) 47 | -------------------------------------------------------------------------------- /src/lib/reporter/plugins/txt.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | from .provider import PluginProvider 20 | from src.core import CoreConfig 21 | from src.core import filesystem, FileSystemError 22 | 23 | 24 | class TextReportPlugin(PluginProvider): 25 | """ TextReportPlugin class""" 26 | 27 | PLUGIN_NAME = 'TextReport' 28 | EXTENSION_SET = '.txt' 29 | 30 | def __init__(self, target, data, directory=None): 31 | """ 32 | PluginProvider constructor 33 | :param str target: target host 34 | :param dict data: result set 35 | :param str directory: custom directory 36 | """ 37 | 38 | PluginProvider.__init__(self, target, data) 39 | 40 | try: 41 | if None is directory: 42 | directory = CoreConfig.get('data').get('reports') 43 | self.__target_dir = filesystem.makedir("".join((directory, self._target))) 44 | except FileSystemError as error: 45 | raise Exception(error) 46 | 47 | def process(self): 48 | """ 49 | Process data 50 | :return: str 51 | """ 52 | 53 | resultset = self._data.get('items').items() 54 | 55 | try: 56 | filesystem.clear(self.__target_dir, extension=self.EXTENSION_SET) 57 | 58 | for status, data in resultset: 59 | 60 | if status not in ['failed']: 61 | self.record(self.__target_dir, status, data, '\n') 62 | except (Exception, FileSystemError) as error: 63 | raise Exception(error) 64 | -------------------------------------------------------------------------------- /src/lib/reporter/reporter.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | import importlib 20 | import os 21 | from src.core import CoreConfig 22 | from src.core import filesystem, FileSystemError 23 | from .exceptions import ReporterError 24 | 25 | 26 | class Reporter(object): 27 | 28 | """Reporter class""" 29 | 30 | default = 'std' 31 | external_directory = None 32 | config = CoreConfig.get('data') 33 | 34 | @staticmethod 35 | def is_reported(resource): 36 | """ 37 | Check if session is already reported 38 | :param str resource: target report 39 | :return: bool 40 | """ 41 | 42 | try: 43 | if None is not Reporter.external_directory: 44 | if not Reporter.external_directory.endswith(os.path.sep): 45 | Reporter.external_directory += os.path.sep 46 | is_reported = filesystem.is_exist(Reporter.external_directory, resource) 47 | else: 48 | is_reported = filesystem.is_exist(Reporter.config.get('reports'), resource) 49 | return is_reported 50 | except FileSystemError as error: 51 | raise ReporterError(error) 52 | 53 | @staticmethod 54 | def load(plugin_name, target, data): 55 | """ 56 | Load report plugin 57 | :param str plugin_name: name 58 | :param str target: target host 59 | :param dict data: report data 60 | :raise ReporterError 61 | :return: src.lib.reporter.plugins.provider.provider.PluginProvider 62 | """ 63 | 64 | try: 65 | package_module = importlib.import_module('src.lib.reporter.plugins') 66 | 67 | try: 68 | report = getattr(package_module, plugin_name) 69 | return report(target, data, Reporter.external_directory) 70 | except (TypeError, AttributeError, Exception) as error: 71 | raise ReporterError('Unable to get reporter `{plugin}`. Reason: {error}' 72 | .format(plugin=plugin_name, error=error)) 73 | except ImportError: 74 | raise ReporterError('Unable to get report\'s plugins`') 75 | -------------------------------------------------------------------------------- /src/lib/tpl/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | from .tpl import Tpl 20 | from .exceptions import TplError 21 | -------------------------------------------------------------------------------- /src/lib/tpl/config.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | 20 | class Config(object): 21 | 22 | """Config class""" 23 | 24 | templates = { 25 | 'unsupported': 'Your Python version v{actual} is not supported by this application. Please consider {expected}', 26 | 'abort': 'Session canceled', 27 | 'upd_win_stat': 'Win OS does not support --update inside.\nPlease run your GIT binary to fetch data manualy', 28 | 'use_reports': 'Use --report param to store your scan results', 29 | 'load_wizard': 'Load wizard options from : {config}', 30 | 'report': '{plugin} : {dest}', 31 | 'logged': 'Scanned host has been reported. Press ENTER to rescan or CTRL+C to exit: ', 32 | 'checking_connect': 'Wait, please, checking connect to -> {host}:{port} ...', 33 | 'slow_connection': 'Too slow connection. Please decrease the num of threads and increase the request timeout', 34 | 'online': 'Server {host}:{port} ({ip}) is online!', 35 | 'create_queue_progress': 'Create queue {bar}', 36 | 'scanning': 'Scanning {host} ...', 37 | 'debug': 'Starting debug level {level}. Using scan method: {method} ...', 38 | 'randomizing': 'Randomizing scan list ...', 39 | 'browser': 'Fetching user-agent: {browser}', 40 | 'directories': 'Read {total} directories list by line', 41 | 'ext_filter': 'Read {total} directories list required only: {ext}', 42 | 'ext_ignore_filter': 'Read {total} directories exclude only: {ext}', 43 | 'create_queue': 'Creating queue with {threads} thread(s)...', 44 | 'subdomains': 'Read {total} subdomains list by line...', 45 | 'random_browser': 'Fetching random user-agent per request...', 46 | 'total_time_lvl3': 'Total time running: {time}', 47 | 'thread_limit': 'Threads has been reduced to {max} (max) instead of {threads}', 48 | 'stop_threads': 'Stopping threads ({threads})...', 49 | 'option_prompt': 'Press "[C]ontinue" to resume or "[E]xit" to abort session: ', 50 | 'resume_threads': 'Resuming scan...', 51 | 'get_item': '{percent} [{current}/{total}] - {size} - {item}', 52 | 'ignored_item': 'skip [{current}/{total}] - Ignored {item}', 53 | 'max_retry_error': 'skip. Max retries exceeded: {url}', 54 | 'addtopool': 'Adding {total} lines to queue...', 55 | 'http_pool_start': 'Using HTTP {type} connection', 56 | 'https_pool_start': 'Using SSL {type} connection', 57 | 'proxy_pool_standalone': 'Using custom proxy server: {server}', 58 | 'proxy_pool_internal_start': 'Fetching internal proxy list...', 59 | 'proxy_pool_external_start': 'Fetching external proxy list...', 60 | 'request_header_dbg': 'Request header:\n{dbg}', 61 | 'response_header_dbg': 'Response header:\n{dbg}', 62 | 'load_sniffer_plugin': 'Load sniffer: {description}', 63 | 'ignored_path': 'Ignored. The path {path} in ignore list', 64 | 'proxy_max_retry_error': 'Skipped. Proxy {proxy} Max retries exceeded: {url}', 65 | 'host_changed_error': 'Block external redirect -> {details}', 66 | 'read_timeout_error': 'Read timeout error! {url}. Increase using --timeout option', 67 | 'connection_timeout_error': 'Connection timeout error! {url}. Increase using --timeout option', 68 | 'certificate': 'Cert required {url}', 69 | 'success': 'OK {url}', 70 | 'file': 'File {url}', 71 | 'indexof': 'Index {url}', 72 | 'forbidden': 'Denied {url}', 73 | 'auth': 'Auth {url}', 74 | 'redirect': 'R {url} -> {rurl}' 75 | } 76 | -------------------------------------------------------------------------------- /src/lib/tpl/exceptions.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | from src.core import exception 20 | 21 | 22 | class TplError(Exception): 23 | 24 | """TplError class""" 25 | 26 | def __init__(self, error): 27 | """ 28 | TplError class constructor 29 | :param str error: error message 30 | """ 31 | 32 | class_name = type(error).__name__ 33 | 34 | if self.__class__.__name__ is not class_name: 35 | exception.log(class_name=class_name, message=error) 36 | 37 | super(TplError, self).__init__("{0}: {1}".format(str(class_name), str(error))) 38 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | pass 20 | -------------------------------------------------------------------------------- /tests/data/directories-scan.dat: -------------------------------------------------------------------------------- 1 | admin/access.php 2 | index.php 3 | 404.php -------------------------------------------------------------------------------- /tests/data/directories.dat: -------------------------------------------------------------------------------- 1 | admin/access.php 2 | admin/access.txt 3 | admin/access_log 4 | admin/account.asp 5 | admin/account.html 6 | admin/account.php 7 | admin/admin-login.html 8 | admin/admin-login.php 9 | admin/admin-login/ 10 | admin/admin.html 11 | admin/admin.php 12 | admin/admin.shtml 13 | admin/admin/ 14 | admin/admin/login/ 15 | admin/adminLogin.htm 16 | -------------------------------------------------------------------------------- /tests/data/ignored.dat: -------------------------------------------------------------------------------- 1 | 403.html 2 | 403.php 3 | 403.html 4 | 403.asp 5 | 404.html 6 | 404.php 7 | 404.html 8 | 404.asp 9 | 404/ 10 | goto.php 11 | goto/ 12 | notfound.php 13 | notfound.html 14 | notfound/ -------------------------------------------------------------------------------- /tests/data/proxies.dat: -------------------------------------------------------------------------------- 1 | http://58.71.17.34:80 2 | http://110.168.108.197:3128 3 | https://213.24.60.52:8080 4 | socks5://localhost:8889 -------------------------------------------------------------------------------- /tests/data/setup-scan.cfg: -------------------------------------------------------------------------------- 1 | [opendoor] 2 | directories = tests/data/directories-scan.dat 3 | ignored = tests/data/ignored.dat 4 | proxies = tests/data/proxies.dat 5 | subdomains = tests/data/subdomains.dat 6 | useragents = tests/data/useragents.dat 7 | tmplist = tests/tmp/list.tmp 8 | reports = tests/reports/ 9 | 10 | -------------------------------------------------------------------------------- /tests/data/setup.cfg: -------------------------------------------------------------------------------- 1 | [opendoor] 2 | directories = tests/data/directories.dat 3 | ignored = tests/data/ignored.dat 4 | proxies = tests/data/proxies.dat 5 | subdomains = tests/data/subdomains.dat 6 | useragents = tests/data/useragents.dat 7 | tmplist = tests/tmp/list.tmp 8 | reports = tests/reports/ 9 | 10 | -------------------------------------------------------------------------------- /tests/data/setupwrong.cfg: -------------------------------------------------------------------------------- 1 | [opendoor] 2 | directories = tests/data/wrong.dat 3 | ignored = tests/data/wrong.dat 4 | proxies = tests/data/wrong.dat 5 | subdomains = tests/data/wrong.dat 6 | useragents = tests/data/wrong.dat 7 | tmplist = tests/tmp/list.tmp 8 | reports = tests/wrong/ 9 | 10 | -------------------------------------------------------------------------------- /tests/data/subdomains.dat: -------------------------------------------------------------------------------- 1 | www 2 | feasterville 3 | feat 4 | feather 5 | feats 6 | feature 7 | featured 8 | featureworld 9 | feb 10 | feba -------------------------------------------------------------------------------- /tests/data/useragents.dat: -------------------------------------------------------------------------------- 1 | Mozilla/6.0 2 | Opera 9/10 3 | Mozilla/4.0 -------------------------------------------------------------------------------- /tests/reports/test.local/success.txt: -------------------------------------------------------------------------------- 1 | http://test.local/cron/exp.php 2 | http://test.local/cron/cron-online.php -------------------------------------------------------------------------------- /tests/reports/test.local/test.local.html: -------------------------------------------------------------------------------- 1 |
items
failed
  • http://test.local/swfobject.js
  • http://test.local/swfobject.php
  • http://test.local/swfobject/
  • http://test.local/swfs/
  • http://test.local/swfupload.php
  • http://test.local/swfupload/
  • http://test.local/swift/
  • http://test.local/login/
  • http://test.local/users/
  • http://test.local/swiss/
  • http://test.local/switch.php
  • http://test.local/switch/
  • http://test.local/switcher/
  • http://test.local/switchover/
  • http://test.local/switchoverfiles/
success
  • http://test.local/cron/exp.php
  • http://test.local/cron/cron-online.php
total
items17
workers1
failed15
success2
-------------------------------------------------------------------------------- /tests/reports/test.local/test.local.json: -------------------------------------------------------------------------------- 1 | { 2 | "items": { 3 | "failed": [ 4 | "http://test.local/swfobject.js", 5 | "http://test.local/swfobject.php", 6 | "http://test.local/swfobject/", 7 | "http://test.local/swfs/", 8 | "http://test.local/swfupload.php", 9 | "http://test.local/swfupload/", 10 | "http://test.local/swift/", 11 | "http://test.local/login/", 12 | "http://test.local/users/", 13 | "http://test.local/swiss/", 14 | "http://test.local/switch.php", 15 | "http://test.local/switch/", 16 | "http://test.local/switcher/", 17 | "http://test.local/switchover/", 18 | "http://test.local/switchoverfiles/" 19 | ], 20 | "success": [ 21 | "http://test.local/cron/exp.php", 22 | "http://test.local/cron/cron-online.php" 23 | ] 24 | }, 25 | "total": { 26 | "failed": 15, 27 | "items": 17, 28 | "success": 2, 29 | "workers": 1 30 | } 31 | } -------------------------------------------------------------------------------- /tests/test_controller.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | from __future__ import absolute_import 20 | import unittest 21 | from ddt import ddt, data 22 | from src.core import CoreConfig 23 | from src import Controller, SrcError 24 | 25 | 26 | @ddt 27 | class TestController(unittest.TestCase): 28 | """TestController class""" 29 | 30 | def setUp(self): 31 | self.controller = Controller.__new__(Controller) 32 | self.config = CoreConfig 33 | 34 | def tearDown(self): 35 | del self.controller 36 | del self.config 37 | 38 | def test_init_exception(self): 39 | """ Controller.init() exception test """ 40 | 41 | self.config['info']['required_versions'] = { 42 | 'minor': '4.0', 43 | 'major': '4.5' 44 | } 45 | with self.assertRaises(SrcError) as context: 46 | Controller().scan_action({}) 47 | self.assertTrue(SrcError == context.expected) 48 | 49 | @data( {'version': True}, {'examples': True}, {'update' : True}) #, {'docs' : True} 50 | def test_run(self, args): 51 | """ Controller.run() test """ 52 | 53 | setattr(self.controller, 'ioargs', args) 54 | self.controller.run() 55 | self.assertTrue(True) 56 | 57 | def test_run_exception(self): 58 | """ Controller.run() exception test """ 59 | 60 | with self.assertRaises(SrcError) as context: 61 | self.controller.run() 62 | self.assertTrue(SrcError == context.expected) 63 | 64 | def test_scan_action_exception(self): 65 | """ Controller.scan_action() exception test """ 66 | 67 | with self.assertRaises(SrcError) as context: 68 | self.controller.scan_action(params={ 69 | 'host': 'http://example.com', 70 | 'port': 80 71 | }) 72 | self.assertTrue(SrcError == context.expected) 73 | 74 | def test_examples_action(self): 75 | """ Controller.examples_action() test """ 76 | 77 | self.assertIsNone(self.controller.examples_action()) 78 | 79 | def test_update_action(self): 80 | """ Controller.update_action() test """ 81 | 82 | self.assertIsNone(self.controller.update_action()) 83 | 84 | def test_version_action(self): 85 | """ Controller.version_action() test """ 86 | 87 | self.assertIsNone(self.controller.version_action()) 88 | 89 | def test_local_version(self): 90 | """ Controller.local_version() test """ 91 | 92 | self.assertIsNone(self.controller.local_version()) 93 | 94 | 95 | if __name__ == "__main__": 96 | unittest.main() 97 | -------------------------------------------------------------------------------- /tests/test_core_filter.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | from __future__ import absolute_import 20 | import unittest 21 | from ddt import ddt, data 22 | from src.core.options.filter import Filter 23 | 24 | @ddt 25 | class TestFilter(unittest.TestCase): 26 | """TestFilter class""" 27 | 28 | @data( 29 | {'host': 'example.com', 'port': 80, 'debug': 1}, 30 | {'host': 'https://example.com', 'port': 223, 'debug': 1}, 31 | {'host': 'example.com','debug': 1, 'scan': 'directories'}, 32 | {'host': 'example.com','debug': 1, 'scan': 'subdomains'} 33 | ) 34 | def test_filter(self, args): 35 | """ Filter.filter() test """ 36 | 37 | flt = Filter.filter(args) 38 | self.assertIs(type(flt), dict) 39 | 40 | 41 | 42 | if __name__ == "__main__": 43 | unittest.main() 44 | -------------------------------------------------------------------------------- /tests/test_core_options.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | from __future__ import absolute_import 20 | import unittest 21 | # noinspection PyCompatibility 22 | import argparse 23 | from ddt import ddt, data 24 | from src.core.options import Options 25 | from src.core.options.exceptions import OptionsError 26 | 27 | @ddt 28 | class TestOptions(unittest.TestCase): 29 | """TestOptions class""" 30 | 31 | @data( 32 | {'version': True, 'examples': False, 'update': None, 'docs' : None}, 33 | {'examples': True, 'version': None, 'update': False, 'docs' : None}, 34 | {'update': True , 'version': False, 'examples': False, 'docs' : None} 35 | ) 36 | def test_get_arg_values_standalone(self, data): 37 | """ Arguments.get_arg_values() standalone call test """ 38 | 39 | opt = Options.__new__(Options) 40 | args = argparse.Namespace() 41 | args.host = '' 42 | args.version = data.get('version') 43 | args.update = data.get('update') 44 | args.examples = data.get('examples') 45 | args.docs = data.get('docs') 46 | setattr(opt, '_Options__standalone', ["version", "update", "examples","docs"]) 47 | setattr(opt, 'args', args) 48 | actual = opt.get_arg_values() 49 | self.assertTrue(isinstance(actual, dict)) 50 | self.assertTrue(1 == len(actual)) 51 | 52 | @data( 53 | {'host': 'example.com', 'port': 80}, 54 | {'host': 'https://example.com', 'port': 223}, 55 | {'host': 'example.com','scan': 'directories'}, 56 | {'host': 'example.com','scan': 'subdomains'}, 57 | {'host': 'example.com', 'proxy': '127.0.0.1'}, 58 | ) 59 | def test_get_arg_values(self, data): 60 | """ Arguments.get_arg_values() test """ 61 | 62 | opt = Options.__new__(Options) 63 | args = argparse.Namespace() 64 | args.host = data.get('host') 65 | args.port = data.get('port') 66 | args.scan = data.get('scan') 67 | args.version = False 68 | args.update = False 69 | args.examples = False 70 | args.docs = False 71 | setattr(opt, '_Options__standalone', ["version", "update", "examples", "docs"]) 72 | setattr(opt, 'args', args) 73 | actual = opt.get_arg_values() 74 | self.assertTrue(isinstance(actual, dict)) 75 | 76 | def test_get_arg_values_exception2(self): 77 | """ Arguments.get_arg_values() exception2 test """ 78 | 79 | opt = Options.__new__(Options) 80 | setattr(opt, '_Options__standalone', ["version", "update", "examples", "docs"]) 81 | setattr(opt, 'args', {}) 82 | with self.assertRaises(OptionsError) as context: 83 | opt.get_arg_values() 84 | self.assertTrue(OptionsError == context.expected) 85 | 86 | def test_get_arg_values_exception3(self): 87 | """ Arguments.get_arg_values() exception3 test """ 88 | 89 | opt = Options.__new__(Options) 90 | args = argparse.Namespace() 91 | args.host = '' 92 | args.version = False 93 | args.update = False 94 | args.examples = False 95 | args.docs = False 96 | setattr(opt, '_Options__standalone', ["version", "update", "examples", "docs"]) 97 | setattr(opt, 'args', args) 98 | with self.assertRaises(OptionsError) as context: 99 | opt.get_arg_values() 100 | self.assertTrue(OptionsError == context.expected) 101 | 102 | if __name__ == "__main__": 103 | unittest.main() 104 | -------------------------------------------------------------------------------- /tests/test_core_terminal.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | from __future__ import absolute_import 20 | import unittest 21 | from src.core.system.terminal import Terminal 22 | from src.core.system.output import Output 23 | 24 | @unittest.skipIf(False is Output().is_windows, "Test can run on Windows") 25 | class TestTerminal(unittest.TestCase): 26 | """TestTerminal class""" 27 | 28 | # def test_get_ts_windows(self): 29 | # """ Terminal.__get_ts_windows() test """ 30 | # 31 | # term = getattr(Terminal, '_Terminal__get_ts_windows')() 32 | # self.assertIsNotNone(term) 33 | 34 | 35 | if __name__ == "__main__": 36 | unittest.main() 37 | -------------------------------------------------------------------------------- /tests/test_lib_browser_config.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | import unittest 19 | from src.lib.browser.config import Config 20 | 21 | 22 | class TestBrowserConfig(unittest.TestCase): 23 | """TestBrowserConfig class""" 24 | 25 | def test_config_properties(self): 26 | """ Config.init() """ 27 | 28 | empty_config = Config({}) 29 | self.assertIs(type(Config.scan), property) 30 | self.assertTrue(str(Config.DEFAULT_SCAN) is str(empty_config.scan)) 31 | 32 | self.assertIs(type(Config.scheme), property) 33 | self.assertTrue('http://' is str(Config({'scheme' : 'http://'}).scheme)) 34 | 35 | self.assertIs(type(Config.is_ssl), property) 36 | self.assertFalse(empty_config.is_ssl) 37 | 38 | self.assertIs(type(Config.prefix), property) 39 | self.assertTrue('test/' is str(Config({'prefix': 'test/'}).prefix)) 40 | 41 | self.assertIs(type(Config.host), property) 42 | self.assertTrue('example.com' is str(Config({'host': 'example.com'}).host)) 43 | 44 | self.assertIs(type(Config.port), property) 45 | self.assertTrue(80 is Config({'port': 80}).port) 46 | 47 | self.assertIs(type(Config.method), property) 48 | self.assertTrue(str(Config.DEFAULT_HTTP_METHOD) is str(Config({'method' : 'HEAD'}).method)) 49 | 50 | self.assertIs(type(Config.delay), property) 51 | self.assertTrue(1 is Config({'delay' : 1}).delay) 52 | 53 | self.assertIs(type(Config.timeout), property) 54 | 55 | self.assertAlmostEqual(Config.DEFAULT_SOCKET_TIMEOUT, Config({'timeout' : 10}).timeout) 56 | 57 | self.assertIs(type(Config.retries), property) 58 | self.assertTrue(3 is Config({'retries' : 3}).retries) 59 | 60 | self.assertIs(type(Config.debug), property) 61 | self.assertTrue(1 is Config({'debug' : 1}).debug) 62 | 63 | self.assertIs(type(Config.proxy), property) 64 | self.assertTrue('' is empty_config.proxy) 65 | 66 | self.assertIs(type(Config.is_proxy), property) 67 | self.assertFalse(empty_config.is_proxy) 68 | 69 | self.assertIs(type(Config.is_random_user_agent), property) 70 | self.assertFalse(empty_config.is_random_user_agent) 71 | 72 | self.assertIs(type(Config.is_random_list), property) 73 | self.assertFalse(empty_config.is_random_list) 74 | 75 | self.assertIs(type(Config.is_standalone_proxy), property) 76 | self.assertFalse(empty_config.is_standalone_proxy) 77 | 78 | self.assertIs(type(Config.is_internal_torlist), property) 79 | self.assertFalse(empty_config.is_internal_torlist) 80 | 81 | self.assertIs(type(Config.is_external_torlist), property) 82 | self.assertFalse(empty_config.is_external_torlist) 83 | 84 | self.assertIs(type(Config.is_external_wordlist), property) 85 | self.assertFalse(empty_config.is_external_wordlist) 86 | 87 | self.assertIs(type(Config.torlist), property) 88 | self.assertTrue('' is empty_config.torlist) 89 | 90 | self.assertIs(type(Config.reports), property) 91 | self.assertIs(type(Config({'reports' : 'std'}).reports), list) 92 | self.assertTrue(Config.DEFAULT_REPORT in Config({'reports' : 'std'}).reports) 93 | 94 | self.assertIs(type(Config.user_agent), property) 95 | self.assertTrue(Config.DEFAULT_USER_AGENT is empty_config.user_agent) 96 | 97 | empty_config.set_threads(Config.DEFAULT_MIN_THREADS) 98 | self.assertIs(type(Config.threads), property) 99 | self.assertTrue(empty_config.threads == Config.DEFAULT_MIN_THREADS) 100 | 101 | self.assertIs(type(Config.accept_cookies), property) 102 | self.assertFalse(empty_config.accept_cookies) 103 | 104 | if __name__ == "__main__": 105 | unittest.main() -------------------------------------------------------------------------------- /tests/test_lib_browser_debug.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | import unittest 20 | from src.lib.browser.debug import Debug 21 | from src.lib.browser.config import Config 22 | from mock import patch 23 | from src.core.logger.logger import Logger 24 | from io import StringIO 25 | from ddt import ddt, data 26 | 27 | 28 | @ddt 29 | class TestBrowserDebug(unittest.TestCase): 30 | """TestBrowserDebug class""" 31 | 32 | CONFIG = Config({ 33 | 'debug' : 1, 34 | 'method' : 'HEAD', 35 | 'indexof' : None, 36 | 'random_agent': False, 37 | 'random_list' : True, 38 | 'threads' : 1 39 | }) 40 | 41 | def setUp(self): 42 | with patch('sys.stdout', new=StringIO()): 43 | self.debug = Debug(self.CONFIG) 44 | 45 | def tearDown(self): 46 | StringIO().flush() 47 | logger = Logger.log() 48 | for handler in logger.handlers: 49 | logger.removeHandler(handler) 50 | del self.debug 51 | 52 | def test_level(self): 53 | """ Debug.level test """ 54 | 55 | self.assertIs(type(self.debug.level), int) 56 | self.assertTrue(0 < self.debug.level) 57 | 58 | @data('success', 'file', 'indexof', 'bad','forbidden', 'redirect', 'certificat', 'auth') 59 | def test_debug_request_uri(self, status): 60 | """ Debug.debug_request_uri() test """ 61 | 62 | setattr(self.debug, '_Reader__cfg.DEFAULT_SCAN', 'directories') 63 | if 'forbidden' in status: 64 | setattr(self.debug, '_Reader__cfg.scan', 'directories') 65 | else: 66 | setattr(self.debug, '_Reader__cfg.scan', 'subdomains') 67 | 68 | with patch('sys.stdout', new=StringIO()): 69 | self.assertTrue(self.debug.debug_request_uri(status,'http://test.local/data/')) 70 | 71 | def test_debug_request(self): 72 | """ Debug.debug_request() test """ 73 | 74 | self.assertTrue(self.debug.debug_request({},'http://test.local/data/', 'HEAD')) 75 | 76 | def test_debug_response(self): 77 | """ Debug.debug_response() test """ 78 | 79 | self.assertTrue(self.debug.debug_response(response_header={})) 80 | 81 | def test_debug_list(self): 82 | """ Debug.debug_list() test """ 83 | 84 | self.assertTrue(self.debug.debug_list(1)) 85 | 86 | def test_debug_connection_pool(self): 87 | """ Debug.debug_connection_pool() test """ 88 | 89 | self.assertTrue(self.debug.debug_connection_pool('http_pool_start', '', '')) 90 | 91 | def test_debug_proxy_pool(self): 92 | """ Debug.debug_proxy_pool() test """ 93 | 94 | self.assertTrue(self.debug.debug_proxy_pool()) 95 | 96 | def test_debug_user_agents(self): 97 | """ Debug.debug_user_agents() test """ 98 | self.assertTrue(self.debug.debug_user_agents()) 99 | 100 | 101 | if __name__ == "__main__": 102 | unittest.main() -------------------------------------------------------------------------------- /tests/test_lib_browser_filter.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | from io import StringIO 20 | from mock import patch 21 | import unittest 22 | from src.lib.browser.filter import Filter 23 | from src.lib.browser.config import Config 24 | from src.core.logger.logger import Logger 25 | 26 | 27 | class TestBrowserFilter(unittest.TestCase): 28 | """TestBrowserFilter class""" 29 | 30 | def setUp(self): 31 | 32 | logger = Logger.log() 33 | for handler in logger.handlers: 34 | logger.removeHandler(handler) 35 | 36 | self.config = Config({ 37 | 'debug' : 1, 38 | 'method' : 'HEAD', 39 | 'indexof' : None, 40 | 'random_agent': False, 41 | 'random_list' : True, 42 | 'threads' : 1000 43 | }) 44 | 45 | def test_filter_threads_to_max(self): 46 | """ Filter.init() test max threads """ 47 | 48 | with patch('sys.stdout', new=StringIO()): 49 | Filter(self.config, 300) 50 | self.assertEqual(self.config.threads, Config.DEFAULT_MAX_THREADS) 51 | 52 | def test_filter_threads_to_list_lines(self): 53 | """ Filter.init() test max lines""" 54 | 55 | with patch('sys.stdout', new=StringIO()): 56 | Filter(self.config, 10) 57 | self.assertEqual(self.config.threads, 10) 58 | 59 | 60 | if __name__ == "__main__": 61 | unittest.main() -------------------------------------------------------------------------------- /tests/test_lib_browser_threadpool.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | import unittest 20 | from mock import patch 21 | from src.lib.browser.threadpool import ThreadPool 22 | from src.core.logger.logger import Logger 23 | 24 | 25 | class TestBrowserThreadPool(unittest.TestCase): 26 | """TestBrowserThreadPool class""" 27 | 28 | THREADS = 2 29 | 30 | def __test_function(self,arg): 31 | pass 32 | 33 | def setUp(self): 34 | self._pool = ThreadPool(num_threads=self.THREADS, total_items=10, timeout=0) 35 | 36 | def tearDown(self): 37 | logger = Logger.log() 38 | for handler in logger.handlers: 39 | logger.removeHandler(handler) 40 | self._pool.join() 41 | 42 | def test_size(self): 43 | """ ThreadPool.size test """ 44 | 45 | self.assertIs(type(self._pool.size), int) 46 | self.assertEqual(self._pool.size, 0) 47 | 48 | def test_worker_size(self): 49 | """ ThreadPool.worker_size test """ 50 | 51 | self.assertIs(type(self._pool.workers_size), int) 52 | self.assertEqual(self._pool.workers_size, self.THREADS) 53 | 54 | def test_items_size(self): 55 | """ ThreadPool.items_size test """ 56 | 57 | self.assertIs(type(self._pool.items_size), int) 58 | self.assertEqual(self._pool.items_size, 0) 59 | 60 | def test_add(self): 61 | """ ThreadPool.add() test """ 62 | 63 | self.assertIs(self._pool.add(self.__test_function, 1), None) 64 | 65 | def pause(self): 66 | ans = self._pool.pause() 67 | return ans 68 | 69 | def test_pause(self): 70 | """ ThreadPool.pause() test """ 71 | 72 | with self.assertRaises(KeyboardInterrupt) as context: 73 | with patch('builtins.input', return_value='e') as _raw_input: 74 | self.assertEqual(self.pause(), 'e') 75 | _raw_input.assert_called_once_with('e') 76 | self.assertTrue(KeyboardInterrupt == context.expected) 77 | 78 | def test_resume(self): 79 | """ ThreadPool.resume() test """ 80 | 81 | self._pool.is_started = False 82 | self.assertIs(self._pool.resume(), None) 83 | 84 | 85 | if __name__ == "__main__": 86 | unittest.main() -------------------------------------------------------------------------------- /tests/test_lib_browser_worker.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | import unittest 20 | from src.lib.browser.worker import Worker 21 | # noinspection PyCompatibility 22 | from queue import Queue 23 | 24 | 25 | class TestBrowserWorker(unittest.TestCase): 26 | """TestBrowserWorker class""" 27 | 28 | THREADS = 1 29 | 30 | def _kill_waiting_thread(self): 31 | exit() 32 | 33 | def setUp(self): 34 | self._worker = Worker(Queue(self.THREADS), num_threads=self.THREADS, timeout=0) 35 | 36 | def tearDown(self): 37 | with self.assertRaises(SystemExit): 38 | self._kill_waiting_thread() 39 | self._worker.join(1) 40 | 41 | def test_pause(self): 42 | """ Worker.pause() test """ 43 | 44 | self.assertEqual(self._worker.pause(), None) 45 | self.assertFalse(getattr(self._worker, '_Worker__running', True)) 46 | 47 | if __name__ == "__main__": 48 | unittest.main() -------------------------------------------------------------------------------- /tests/test_lib_events.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | from __future__ import absolute_import 20 | import unittest 21 | import os 22 | import sys 23 | import signal 24 | from src.lib.events import EventHandler 25 | 26 | @unittest.skipUnless(hasattr(os, 'kill'), "Test requires os.kill") 27 | @unittest.skipIf(sys.platform =="win32", "Test cannot run on Windows") 28 | @unittest.skipIf(sys.platform == 'freebsd6', "Test kills regrtest on freebsd6 " 29 | "if threads have been used") 30 | class TestEvents(unittest.TestCase): 31 | """TestEvents class""" 32 | 33 | def test_termination_handler(self): 34 | """ Events.terminate() exception test """ 35 | 36 | EventHandler.terminate() 37 | 38 | self.assertIs('kill_process', signal.getsignal(signal.SIGTSTP).__name__) 39 | self.assertTrue(None is not signal.getsignal(signal.SIGTERM)) 40 | 41 | if __name__ == "__main__": 42 | unittest.main() 43 | -------------------------------------------------------------------------------- /tests/test_lib_package.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | Development Team: Brain Storm Team 17 | """ 18 | 19 | import unittest 20 | from src.core import sys 21 | from src.lib.package import Package, PackageError 22 | from src.core.filesystem import FileSystem 23 | from src.core.logger.logger import Logger 24 | 25 | 26 | class TestPackage(unittest.TestCase): 27 | """TestPackage class""" 28 | 29 | def tearDown(self): 30 | logger = Logger.log() 31 | 32 | for handler in logger.handlers: 33 | logger.removeHandler(handler) 34 | 35 | def test_check_interpreter(self): 36 | """ Package.check_interpreter() test """ 37 | 38 | expected = Package.check_interpreter() 39 | self.assertTrue(expected) 40 | 41 | def test_examples(self): 42 | """ Package.examples() test """ 43 | 44 | expected = Package.examples() 45 | self.assertIsNotNone(expected) 46 | self.assertIs(type(expected), str) 47 | 48 | # def test_banner(self): 49 | # """ Package.banner() test """ 50 | # 51 | # Config.params['cfg'] = 'setup.cfg' 52 | # expected = Package.banner() 53 | # self.assertIsNotNone(expected) 54 | # self.assertIs(type(expected), str) 55 | # 56 | # def test_version(self): 57 | # """ Package.version() test """ 58 | # 59 | # Config.params['cfg'] = 'setup.cfg' 60 | # expected = Package.version() 61 | # self.assertIsNotNone(expected) 62 | # self.assertIs(type(expected), str) 63 | # 64 | # def test_update_unix(self): 65 | # """ Package.update() unix test """ 66 | # 67 | # Config.params['cfg'] = 'setup.cfg' 68 | # Config.params['update'] = '{status}' 69 | # expected = Package.update() 70 | # self.assertIsNotNone(expected) 71 | # self.assertIs(type(expected), str) 72 | # 73 | # def test_update_windows(self): 74 | # """ Package.update() test """ 75 | # 76 | # Config.params['cfg'] = 'setup.cfg' 77 | # Config.params['update'] = '{status}' 78 | # setattr(sys, 'is_windows', True) 79 | # expected = Package.update() 80 | # self.assertIsNotNone(expected) 81 | 82 | # def test_local_version(self): 83 | # """ Package.local_version() test """ 84 | # 85 | # Config.params['cfg'] = 'setup.cfg' 86 | # actual = FileSystem.readcfg('setup.cfg').get('info', 'version') 87 | # expected = Package.local_version() 88 | # self.assertEqual(actual, expected) 89 | # 90 | # def test_local_version_exception(self): 91 | # """ Package.local_version() exception test """ 92 | # 93 | # Config.params['cfg'] = 'wrong.cfg' 94 | # with self.assertRaises(PackageError) as context: 95 | # Package.local_version() 96 | # self.assertTrue(PackageError == context.expected) 97 | # 98 | # def test_update_exception(self): 99 | # """ Package.update() exception test """ 100 | # Config.params['cvsupdate'] = 'wrongcvs' 101 | # with self.assertRaises(PackageError) as context: 102 | # Package.update() 103 | # self.assertTrue(PackageError == context.expected) 104 | # Config.params['cvsupdate'] = '/usr/bin/git pull origin master' 105 | # 106 | # def test_version_exception(self): 107 | # """ Package.version() exception test """ 108 | # 109 | # Config.params['cfg'] = 'wrong.cfg' 110 | # with self.assertRaises(PackageError) as context: 111 | # Package.version() 112 | # self.assertTrue(PackageError == context.expected) 113 | # 114 | # def test_banner_exception(self): 115 | # """ Package.banner() exception test """ 116 | # 117 | # Config.params['cfg'] = 'wrong.cfg' 118 | # with self.assertRaises(PackageError) as context: 119 | # Package.banner() 120 | # self.assertTrue(PackageError == context.expected) 121 | 122 | if __name__ == "__main__": 123 | unittest.main() 124 | -------------------------------------------------------------------------------- /tests/tmp/list.tmp: -------------------------------------------------------------------------------- 1 | admin/account.php 2 | admin/admin-login.php 3 | admin/access.php 4 | admin/access.txt 5 | admin/admin/login/ 6 | admin/admin.php 7 | admin/account.html 8 | admin/admin/ 9 | admin/admin-login.html 10 | admin/admin-login/ 11 | admin/adminLogin.htm 12 | admin/admin.shtml 13 | admin/access_log 14 | admin/admin.html 15 | admin/account.asp 16 | --------------------------------------------------------------------------------