├── .codecov.yml
├── .coveragerc
├── .flake8
├── .github
├── FUNDING.yml
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── feature_request.md
├── PULL_REQUEST_TEMPLATE.md
├── release-drafter.yml
└── workflows
│ └── main.yaml
├── .gitignore
├── CONTRIBUTING.md
├── Dockerfile
├── LICENSE
├── README.md
├── conftest.py
├── fixtures
├── file
└── test
│ └── file
├── images
├── logo.png
├── main_demo.gif
├── pcap_demo.gif
├── subcategories.png
└── wannacry_demo.png
├── noxfile.py
├── poetry.lock
├── pyproject.toml
├── pywhat
├── Data
│ ├── file_signatures.json
│ ├── mac_vendors.json
│ ├── mastercard_companies.json
│ ├── phone_codes.json
│ └── regex.json
├── __init__.py
├── __main__.py
├── filter.py
├── helper.py
├── identifier.py
├── magic_numbers.py
├── printer.py
├── regex_identifier.py
└── what.py
├── scripts
├── format_regex.py
├── get_file_sigs.py
└── get_tlds.py
└── tests
├── __init__.py
├── test_click.py
├── test_filtration.py
├── test_identifier.py
├── test_regex_database.py
└── test_regex_identifier.py
/.codecov.yml:
--------------------------------------------------------------------------------
1 | coverage:
2 | status:
3 | project:
4 | default:
5 | target: 90%
6 | patch:
7 | default:
8 | target: 80%
9 |
--------------------------------------------------------------------------------
/.coveragerc:
--------------------------------------------------------------------------------
1 | [run]
2 | omit =
3 | ./noxfile.py
4 | [report]
5 | exclude_lines =
6 | pragma: no cover
7 | if __name__ == .__main__.:
8 |
--------------------------------------------------------------------------------
/.flake8:
--------------------------------------------------------------------------------
1 | [flake8]
2 | max-line-length = 88
3 | ignore = E501, E203, W503
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: bee-san
4 | patreon: # Replace with a single Patreon username
5 | open_collective: # Replace with a single Open Collective username
6 | ko_fi: hacker
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 | custom: ["https://www.buymeacoffee.com/beecodes", "http://paypal.me/brandonskerritt"]
13 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | A clear and concise description of what the bug is.
12 |
13 | **To Reproduce**
14 | Steps to reproduce the behavior:
15 | 1. Go to '...'
16 | 2. Click on '....'
17 | 3. Scroll down to '....'
18 | 4. See error
19 |
20 | **Expected behavior**
21 | A clear and concise description of what you expected to happen.
22 |
23 | **Screenshots**
24 | If applicable, add screenshots to help explain your problem.
25 |
26 | **Desktop (please complete the following information):**
27 | - OS: [e.g. iOS]
28 | - Browser [e.g. chrome, safari]
29 | - Version [e.g. 22]
30 |
31 | **Smartphone (please complete the following information):**
32 | - Device: [e.g. iPhone6]
33 | - OS: [e.g. iOS8.1]
34 | - Browser [e.g. stock browser, safari]
35 | - Version [e.g. 22]
36 |
37 | **Additional context**
38 | Add any other context about the problem here.
39 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12 |
13 | **Describe the solution you'd like**
14 | A clear and concise description of what you want to happen.
15 |
16 | **Describe alternatives you've considered**
17 | A clear and concise description of any alternative solutions or features you've considered.
18 |
19 | **Additional context**
20 | Add any other context or screenshots about the feature request here.
21 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | **⚠ Pull Requests not made with this template will be automatically closed 🔥**
2 |
3 | ## Prerequisites
4 | - [ ] Have you read the documentation on contributing? https://github.com/bee-san/pyWhat/wiki/Adding-your-own-Regex
5 |
6 | ## Why do we need this pull request?
7 | * Explain the _why_ behind your PR. We can see what it does from the code. But _why_ does it do that?
8 |
9 | ## What [GitHub issues](https://github.com/bee-san/pyWhat/issues) does this fix?
10 | * Fixes #10000
11 |
12 | ## Copy / paste of output
13 |
14 | Please copy and paste the output of PyWhat with your new addition using an example that tests this addition below:
15 |
16 | ```console
17 |
18 | ```
19 |
--------------------------------------------------------------------------------
/.github/release-drafter.yml:
--------------------------------------------------------------------------------
1 | template: |
2 | ## What’s Changed
3 | $CHANGES
--------------------------------------------------------------------------------
/.github/workflows/main.yaml:
--------------------------------------------------------------------------------
1 | # .github/workflows/tests.yml
2 | name: Tests
3 | on: [push, pull_request]
4 | jobs:
5 | tests:
6 | strategy:
7 | fail-fast: false
8 | matrix:
9 | python-version: ['3.7', '3.8', '3.9', '3.10']
10 | os: [ubuntu-latest, windows-latest, macos-latest]
11 | runs-on: ${{ matrix.os }}
12 | name: Python ${{ matrix.python-version }} on ${{ matrix.os }}
13 | steps:
14 | - uses: actions/checkout@v2
15 | - uses: actions/setup-python@v1
16 | with:
17 | python-version: ${{ matrix.python-version }}
18 | architecture: x64
19 | - run: python -m pip install nox poetry
20 | - run: python -m nox
21 | env:
22 | OS: ${{ matrix.os }}
23 | PYTHON: ${{ matrix.python-version }}
24 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Binaries for programs and plugins
2 | *.exe
3 | *.exe~
4 | *.dll
5 | *.so
6 | *.dylib
7 |
8 | # Test binary, built with `go test -c`
9 | *.test
10 |
11 | # Output of the go coverage tool, specifically when used with LiteIDE
12 | *.out
13 |
14 | # Dependency directories (remove the comment below to include it)
15 | # vendor/
16 |
17 | # Created by https://www.toptal.com/developers/gitignore/api/python
18 | # Edit at https://www.toptal.com/developers/gitignore?templates=python
19 |
20 | ### Python ###
21 | # Byte-compiled / optimized / DLL files
22 | __pycache__/
23 | *.py[cod]
24 | *$py.class
25 | tests/__pycache__/
26 |
27 | # C extensions
28 | *.so
29 |
30 | # Distribution / packaging
31 | .Python
32 | build/
33 | develop-eggs/
34 | dist/
35 | downloads/
36 | eggs/
37 | .eggs/
38 | parts/
39 | sdist/
40 | var/
41 | wheels/
42 | pip-wheel-metadata/
43 | share/python-wheels/
44 | *.egg-info/
45 | .installed.cfg
46 | *.egg
47 | MANIFEST
48 |
49 | # PyInstaller
50 | # Usually these files are written by a python script from a template
51 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
52 | *.manifest
53 | *.spec
54 |
55 | # Installer logs
56 | pip-log.txt
57 | pip-delete-this-directory.txt
58 |
59 | # Unit test / coverage reports
60 | htmlcov/
61 | .tox/
62 | .nox/
63 | .coverage
64 | .coverage.*
65 | .cache
66 | nosetests.xml
67 | coverage.xml
68 | *.cover
69 | *.py,cover
70 | .hypothesis/
71 | .pytest_cache/
72 | pytestdebug.log
73 |
74 | # Translations
75 | *.mo
76 | *.pot
77 |
78 | # Django stuff:
79 | *.log
80 | local_settings.py
81 | db.sqlite3
82 | db.sqlite3-journal
83 |
84 | # Flask stuff:
85 | instance/
86 | .webassets-cache
87 |
88 | # Scrapy stuff:
89 | .scrapy
90 |
91 | # Sphinx documentation
92 | docs/_build/
93 | doc/_build/
94 |
95 | # PyBuilder
96 | target/
97 |
98 | # Jupyter Notebook
99 | .ipynb_checkpoints
100 |
101 | # IPython
102 | profile_default/
103 | ipython_config.py
104 |
105 | # pyenv
106 | .python-version
107 |
108 | # pipenv
109 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
110 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
111 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
112 | # install all needed dependencies.
113 | #Pipfile.lock
114 |
115 | # poetry
116 | #poetry.lock
117 |
118 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow
119 | __pypackages__/
120 |
121 | # Celery stuff
122 | celerybeat-schedule
123 | celerybeat.pid
124 |
125 | # SageMath parsed files
126 | *.sage.py
127 |
128 | # Environments
129 | # .env
130 | .env/
131 | .venv/
132 | env/
133 | venv/
134 | ENV/
135 | env.bak/
136 | venv.bak/
137 | pythonenv*
138 |
139 | # Spyder project settings
140 | .spyderproject
141 | .spyproject
142 |
143 | # Rope project settings
144 | .ropeproject
145 |
146 | # mkdocs documentation
147 | /site
148 |
149 | # mypy
150 | .mypy_cache/
151 | .dmypy.json
152 | dmypy.json
153 |
154 | # Pyre type checker
155 | .pyre/
156 |
157 | # pytype static type analyzer
158 | .pytype/
159 |
160 | # operating system-related files
161 | # file properties cache/storage on macOS
162 | *.DS_Store
163 | # thumbnail cache on Windows
164 | Thumbs.db
165 |
166 | # profiling data
167 | .prof
168 |
169 |
170 | # End of https://www.toptal.com/developers/gitignore/api/python
171 |
172 | # Code editor files
173 | .vscode
174 | .idea
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | Please read our wiki here:
2 | https://github.com/bee-san/pyWhat/wiki/Adding-your-own-Regex
3 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM python:3.10-alpine
2 | RUN apk add --no-cache git \
3 | && pip install --no-cache-dir git+https://github.com/bee-san/pyWhat \
4 | && apk del git \
5 | && rm -rf /var/cache/apk/*
6 | WORKDIR /workdir
7 | ENTRYPOINT [ "python", "-m", "pywhat" ]
8 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 - Present @bee-san
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
➡️ Discord ⬅️
4 | The easiest way to identify anything
5 | pip3 install pywhat && pywhat --help
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | # 🤔 `What` is this?
14 |
15 | 
16 |
17 | Imagine this: You come across some mysterious text 🧙♂️ `0x52908400098527886E0F7030069857D2E4169EE7` or `dQw4w9WgXcQ` and you wonder what it is. What do you do?
18 |
19 | Well, with `what` all you have to do is ask `what "0x52908400098527886E0F7030069857D2E4169EE7"` and `what` will tell you!
20 |
21 | `what`'s job is to **identify _what_ something is.** Whether it be a file or text! Or even the hex of a file! What about text _within_ files? We have that too! `what` is recursive, it will identify **everything** in text and more!
22 |
23 | # Installation
24 |
25 | ## 🔨 Using pip
26 |
27 | ```$ pip3 install pywhat```
28 |
29 | or
30 |
31 | ```shell
32 | # installs optional dependencies that may improve the speed
33 | $ pip3 install pywhat[optimize]
34 | ```
35 |
36 | ## 🔨 On Mac?
37 |
38 | ```$ brew install pywhat```
39 |
40 | Or for our MacPorts fans:
41 |
42 | ```$ sudo port install pywhat```
43 |
44 | # ⚙ Use Cases
45 |
46 | ## 🦠 Wannacry
47 |
48 | 
49 |
50 | You come across a new piece of malware called WantToCry. You think back to Wannacry and remember it was stopped because a researcher found a kill-switch in the code.
51 |
52 | When a domain, hardcoded into Wannacry, was registered the virus would stop.
53 |
54 | You use `What` to identify all the domains in the malware, and use a domain registrar API to register all the domains.
55 |
56 | ## 🦈 Faster Analysis of Pcap files
57 |
58 | 
59 |
60 | Say you have a `.pcap` file from a network attack. `What` can identify this and quickly find you:
61 |
62 | - All URLs
63 | - Emails
64 | - Phone numbers
65 | - Credit card numbers
66 | - Cryptocurrency addresses
67 | - Social Security Numbers
68 | - and much more.
69 |
70 | With `what`, you can identify the important things in the pcap in seconds, not minutes.
71 |
72 | ## 🐞 Bug Bounties
73 |
74 | You can use PyWhat to scan for things that'll make you money via bug bounties like:
75 | * API Keys
76 | * Webhooks
77 | * Credentials
78 | * and more
79 |
80 | Run PyWhat with:
81 |
82 | ```
83 | pywhat --include "Bug Bounty" TEXT
84 | ```
85 |
86 | To do this.
87 |
88 | Here are some examples 👇
89 |
90 | ### 🐙 GitHub Repository API Key Leaks
91 |
92 | 1. Download all GitHub repositories of an organisation
93 | 2. Search for anything that you can submit as a bounty, like API keys
94 |
95 | ```shell
96 | # Download all repositories
97 | GHUSER=CHANGEME; curl "https://api.github.com/users/$GHUSER/repos?per_page=1000" | grep -o 'git@[^"]*' | xargs -L1 git clone
98 |
99 | # Will print when it finds things.
100 | # Loops over all files in current directory.
101 | find . -type f -execdir pywhat --include 'Bug Bounty' {} \;
102 | ```
103 |
104 | ### 🕷 Scan all web pages for bounties
105 |
106 | ```shell
107 | # Recursively download all web pages of a site
108 | wget -r -np -k https://skerritt.blog
109 |
110 | # Will print when it finds things.
111 | # Loops over all files in current directory.
112 | find . -type f -execdir pywhat --include 'Bug Bounty' {} \;
113 | ```
114 |
115 | **PS**: We support more filters than just bug bounties! Run `pywhat --tags`
116 |
117 | ## 🌌 Other Features
118 |
119 | Anytime you have a file and you want to find structured data in it that's useful, `What` is for you.
120 |
121 | Or if you come across some piece of text and you don't know what it is, `What` will tell you.
122 |
123 | ### 📁 File & Directory Handling
124 |
125 | **File Opening** You can pass in a file path by `what 'this/is/a/file/path'`. `What` is smart enough to figure out it's a file!
126 |
127 | What about a whole **directory**? `What` can handle that too! It will **recursively** search for files and output everything you need!
128 |
129 | ### 🔍 Filtering your output
130 |
131 | Sometimes, you only care about seeing things which are related to AWS. Or bug bounties, or cryptocurrencies!
132 |
133 | You can filter output by using `what --rarity 0.2:0.8 --include Identifiers,URL https://skerritt.blog`. Use `what --help` to get more information.
134 |
135 | To see all filters, run `pywhat --tags`! You can also combine them, for example to see all cryptocurrency wallets minus Ripple you can do:
136 |
137 | ```console
138 | pywhat --include "Cryptocurrency Wallet" --exclude "Ripple Wallet" 1KFHE7w8BhaENAswwryaoccDb6qcT6DbYY
139 | ```
140 |
141 | ### 👽 Sorting, Exporting, and more!
142 |
143 | **Sorting** You can sort the output by using `what -k rarity --reverse TEXT`. Use `what --help` to get more information.
144 |
145 | **Exporting** You can export to json using `what --json` and results can be sent directly to a file using `what --json > file.json`.
146 |
147 | **Boundaryless mode** `What` has a special mode to match identifiable information within strings. By default, it is enabled in CLI but disabled in API. Use `what --help` or refer to [API Documentation](https://github.com/bee-san/pyWhat/wiki/API) for more information.
148 |
149 |
150 | # 🍕 API
151 |
152 | PyWhat has an API! Click here [https://github.com/bee-san/pyWhat/wiki/API](https://github.com/bee-san/pyWhat/wiki/API) to read about it.
153 |
154 | # 👾 Contributing
155 |
156 | `what` not only thrives on contributors, but can't exist without them! If you want to add a new regex to check for things, you can read our documentation [here](https://github.com/bee-san/what/wiki/Adding-your-own-Regex)
157 |
158 | We ask contributors to join the Discord for quicker discussions, but it's not needed:
159 |
160 |
161 | # 🙏 Thanks
162 |
163 | We would like to thank [Dora](https://github.com/sdushantha/dora) for their work on a bug bounty specific regex database which we have used.
--------------------------------------------------------------------------------
/conftest.py:
--------------------------------------------------------------------------------
1 | import logging
2 |
3 |
4 | def pytest_configure(config):
5 | # Silence Flake8 warnings
6 | logging.getLogger("flake8").setLevel(logging.ERROR)
7 |
--------------------------------------------------------------------------------
/fixtures/file:
--------------------------------------------------------------------------------
1 | 0x52908400098527886E0F7030069857D2E4169EE7
2 | DANHz6EQVoWyZ9rER56DwTXHWUxfkv9k2o
3 | print("hello)
4 |
5 | thm{"Can you guess what this is, now?"}
6 | THM{this is a flag}
7 | 0x52908400098527886E0F7030069857D2E4169EE730000000000004
8 | 0x52908400098527886E0F7030069857D2E4169EE7
9 | @pytest.mark.skip(reason="Fails Regex due to http://")
10 | "1KFHE7w8BhaENAswwryaoccDb6qcT6DbYY"
11 | 16ftSEQ4ctQFDtVZiUBusQUjRrGhM3JYwe
12 | 4462030000000000
13 | thm{"uh hello?"}
14 | 001-01-0001
15 | flag{"helo jenny dwi'n gwybod eich bod chi'n darllen hwn diolch am fod yn ffrind i mi "}
16 | 340000000000009
17 | 30569309025904
18 | http://10.1.1.1
19 | https://www.youtube.com/watch?v=ScOAntcCa78
20 | adsadasdasdhttps://www.youtube.com/watch?v=trj15fjXWDwasdasdasd
21 | 6011000000000004
22 | htb{4111111111111111}
23 | 3000 0000 0000 04
24 | 5500000000000004
25 |
26 | james:S3cr37_P@$$W0rd
27 | ScOAntcCa78
28 | hello
29 | 127.0.0.1
30 | github@skerritt.blog
31 |
32 | Access-Control-Allow-Headers: *
33 |
34 | 47DF8D9NwtmefhFUghynYRMqrexiZTsm48T1hhi2jZcbfcwoPbkhMrrED6zqJRfeYpXFfdaqAT3jnBEwoMwCx6BYDJ1W3ub
35 | LRX8rSPVjifTxoLeoJtLf2JYdJFTQFcE7m
36 | bitcoincash:qzlg6uvceehgzgtz6phmvy8gtdqyt6vf359at4n3lq
37 | rBPAQmwMrt7FDDPNyjwFgwSqbWZPf6SLkk
38 | 2001:0db8:85a3:0000:0000:8a2e:0370:7334
39 | de:ad:be:ef:ca:fe
40 | DE:AD:BE:EF:CA:FE
41 |
42 | eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
43 | fajfdk;fa+91 (385) 985 2821kl;fajf;la
44 |
45 | ssh-rsa AAAAB3NzaC1tc2EAAAADAQABAAACAQDrnjkGtf3iA46rtwsvRiscvMTCw30l5Mmln/sf8Wohg4RPc7nuIx3/fB86K9jzBNoQk6Fb00p2cSW0dX6c3OTL5R5Q0rBjOFy6GV07MkS7rXa7WYh4ObxBh+M+LEzxVIw29anzQFZkR0TAf6x2rBoErK7JYU4fyqFBDFupTt3coQDPEEmVwtLLUCEnJrurbbnJKcWJ+/FbItLxYyMLPl8TwEn0iqiJ97onCU2DuBtiYv3hp1WoEH08b5WDF0F04zEPRdJT+WisxlEFRgaj51o2BtjOC+D2qZQDb4LHaAfJ0WcO4nu7YocdlcLp2JPfXKKgu9P5J8UDsmXbR3KCJ1oddFa2R6TbHc6d2hKyG4amBzMX5ltxXu7D6FLPZlFqua8YooY7A2zwIVirOUH/cfx+5O9o0CtspkNmj/iYzN0FPaOpELncWsuauy9hrGql/1cF4SUr20zHFoBoDQUtmvmBnWnKoGfpWXzuda449FVtmcrEjvBzCvCb3RStu0BbyOOybJagbKif3MkcYVO10pRbTveIUwgCD6F3ypD11XztoPNsgScmjme0sj/KWWNLyQkLWtpJEQ4k46745NAC5g+nP28TR2JM8doeqsxA8JovQkLWwDcR+WYZu2z/I8dfhOmalnoMRTJ2NzWDc0OSkKGYWjexR4fN6lAKCUOUptl9Nw== r00t@my-random_host
46 | ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBCE9Uli8bGnD4hOWdeo5KKQJ/P/vOazI4MgqJK54w37emP2JwOAOdMmXuwpxbKng3KZz27mz+nKWIlXJ3rzSGMo= r00t@my-random_host
47 | ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIK0wmN/Cr3JXqmLW7u+g9pTh+wyqDHpSQEIQczXkVx9q r00t@my-random_host
48 |
49 | -----BEGIN PGP PUBLIC KEY BLOCK-----
50 | Comment: Alice's OpenPGP certificate
51 | Comment: https://www.ietf.org/id/draft-bre-openpgp-samples-01.html
52 |
53 | mDMEXEcE6RYJKwYBBAHaRw8BAQdArjWwk3FAqyiFbFBKT4TzXcVBqPTB3gmzlC/U
54 | b7O1u120JkFsaWNlIExvdmVsYWNlIDxhbGljZUBvcGVucGdwLmV4YW1wbGU+iJAE
55 | ExYIADgCGwMFCwkIBwIGFQoJCAsCBBYCAwECHgECF4AWIQTrhbtfozp14V6UTmPy
56 | MVUMT0fjjgUCXaWfOgAKCRDyMVUMT0fjjukrAPoDnHBSogOmsHOsd9qGsiZpgRnO
57 | dypvbm+QtXZqth9rvwD9HcDC0tC+PHAsO7OTh1S1TC9RiJsvawAfCPaQZoed8gK4
58 | OARcRwTpEgorBgEEAZdVAQUBAQdAQv8GIa2rSTzgqbXCpDDYMiKRVitCsy203x3s
59 | E9+eviIDAQgHiHgEGBYIACAWIQTrhbtfozp14V6UTmPyMVUMT0fjjgUCXEcE6QIb
60 | DAAKCRDyMVUMT0fjjlnQAQDFHUs6TIcxrNTtEZFjUFm1M0PJ1Dng/cDW4xN80fsn
61 | 0QEA22Kr7VkCjeAEC08VSTeV+QFsmz55/lntWkwYWhmvOgE=
62 | =iIGO
63 | -----END PGP PUBLIC KEY BLOCK-----
64 |
65 | -----BEGIN PGP PRIVATE KEY BLOCK-----
66 | Comment: Alice's OpenPGP Transferable Secret Key
67 | Comment: https://www.ietf.org/id/draft-bre-openpgp-samples-01.html
68 |
69 | lFgEXEcE6RYJKwYBBAHaRw8BAQdArjWwk3FAqyiFbFBKT4TzXcVBqPTB3gmzlC/U
70 | b7O1u10AAP9XBeW6lzGOLx7zHH9AsUDUTb2pggYGMzd0P3ulJ2AfvQ4RtCZBbGlj
71 | ZSBMb3ZlbGFjZSA8YWxpY2VAb3BlbnBncC5leGFtcGxlPoiQBBMWCAA4AhsDBQsJ
72 | CAcCBhUKCQgLAgQWAgMBAh4BAheAFiEE64W7X6M6deFelE5j8jFVDE9H444FAl2l
73 | nzoACgkQ8jFVDE9H447pKwD6A5xwUqIDprBzrHfahrImaYEZzncqb25vkLV2arYf
74 | a78A/R3AwtLQvjxwLDuzk4dUtUwvUYibL2sAHwj2kGaHnfICnF0EXEcE6RIKKwYB
75 | BAGXVQEFAQEHQEL/BiGtq0k84Km1wqQw2DIikVYrQrMttN8d7BPfnr4iAwEIBwAA
76 | /3/xFPG6U17rhTuq+07gmEvaFYKfxRB6sgAYiW6TMTpQEK6IeAQYFggAIBYhBOuF
77 | u1+jOnXhXpROY/IxVQxPR+OOBQJcRwTpAhsMAAoJEPIxVQxPR+OOWdABAMUdSzpM
78 | hzGs1O0RkWNQWbUzQ8nUOeD9wNbjE3zR+yfRAQDbYqvtWQKN4AQLTxVJN5X5AWyb
79 | Pnn+We1aTBhaGa86AQ==
80 | =n8OM
81 | -----END PGP PRIVATE KEY BLOCK-----
82 | =======
83 | B07ND5BB8V
84 |
85 | 34A2344
86 | 13-08-1987
87 | 12345678902
88 | 1234567890
89 |
90 | nano_1c46rz7xnk98ozhzdjq7thwty844sgnqxk9496yysit1bnio1rcdzshc5ymn
91 |
92 | b2ced6f5-2542-4f7d-b131-e3ada95d8b75
93 | 5fc7c33a7ef88b139122a38a
94 | 01ERJ58HMWDN3VTRRHZQV2T5R5
95 |
96 | otpauth://totp/Example:alice@google.com?secret=JBSWY3DPEHPK3PXP&issuer=Example
97 |
98 | sshpass -p MyPassw0RD! ssh root@10.0.0.10
99 |
100 | https://hooks.slack.com/services/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
101 |
102 | doi:10.1392/BC1.0
103 | 10.1000/123
104 |
105 | a80122b2565c3e26a61cbf58d1d1aad7-us5
106 |
107 | https://discord.com/api/webhooks/949053171232276500/V4xxtMKjN9_xH_L6ipXkNRjUqZSAiYQ2l64-L0Z4-3ciPc6tsDh25zLaEEjp97U5wXN2
108 |
109 | https://www.guilded.gg/api/webhooks/1fa5fe35-74e7-4f17-bf53-52d02293fea6/zhXzVecRvaMCWEcOCIuIMYQyeeKemUCswca24Q68cCQCgg4oYKeawamAiEkaI2uCS8Q2sgwy2qUOe2c4yE2em6
110 |
--------------------------------------------------------------------------------
/fixtures/test/file:
--------------------------------------------------------------------------------
1 | https://google.com
--------------------------------------------------------------------------------
/images/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bee-san/pyWhat/75a1592cbc4151acdaaeab78b71dd65ea9a9230e/images/logo.png
--------------------------------------------------------------------------------
/images/main_demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bee-san/pyWhat/75a1592cbc4151acdaaeab78b71dd65ea9a9230e/images/main_demo.gif
--------------------------------------------------------------------------------
/images/pcap_demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bee-san/pyWhat/75a1592cbc4151acdaaeab78b71dd65ea9a9230e/images/pcap_demo.gif
--------------------------------------------------------------------------------
/images/subcategories.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bee-san/pyWhat/75a1592cbc4151acdaaeab78b71dd65ea9a9230e/images/subcategories.png
--------------------------------------------------------------------------------
/images/wannacry_demo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bee-san/pyWhat/75a1592cbc4151acdaaeab78b71dd65ea9a9230e/images/wannacry_demo.png
--------------------------------------------------------------------------------
/noxfile.py:
--------------------------------------------------------------------------------
1 | """Nox sessions."""
2 | from os import environ
3 | from typing import Any
4 |
5 | import nox
6 | from nox.sessions import Session
7 |
8 | nox.options.sessions = ["tests"]
9 | if environ.get("CI", None) == "true":
10 | nox.options.sessions.append("coverage")
11 | locations = "src", "tests", "noxfile.py", "docs/conf.py"
12 |
13 |
14 | def install_with_constraints(session: Session, *args: str, **kwargs: Any) -> None:
15 | """Install packages constrained by Poetry's lock file.
16 | This function is a wrapper for nox.sessions.Session.install. It
17 | invokes pip to install packages inside of the session's virtualenv.
18 | Additionally, pip is passed a constraints file generated from
19 | Poetry's lock file, to ensure that the packages are pinned to the
20 | versions specified in poetry.lock. This allows you to manage the
21 | packages as Poetry development dependencies.
22 | Arguments:
23 | session: The Session object.
24 | args: Command-line arguments for pip.
25 | kwargs: Additional keyword arguments for Session.install.
26 | """
27 | session.run(
28 | "poetry",
29 | "export",
30 | "--without-hashes",
31 | "--dev",
32 | "--format=requirements.txt",
33 | "--output=requirements.txt",
34 | external=True,
35 | )
36 | session.install("--constraint=requirements.txt", *args, **kwargs)
37 |
38 |
39 | @nox.session
40 | def tests(session: Session) -> None:
41 | """Run the test suite."""
42 | session.run("poetry", "install", "--no-dev", external=True)
43 | install_with_constraints(
44 | session,
45 | "pytest",
46 | "pytest-black",
47 | "pytest-cov",
48 | "pytest-isort",
49 | "pytest-flake8",
50 | "pytest-mypy",
51 | "types-requests",
52 | "types-orjson",
53 | )
54 | session.run("pytest", "--cov=./", "--cov-report=xml")
55 |
56 |
57 | @nox.session
58 | def coverage(session: Session) -> None:
59 | """Upload coverage data."""
60 | install_with_constraints(session, "codecov")
61 | session.run("codecov", "--env", "OS", "PYTHON")
62 |
--------------------------------------------------------------------------------
/poetry.lock:
--------------------------------------------------------------------------------
1 | [[package]]
2 | name = "atomicwrites"
3 | version = "1.4.0"
4 | description = "Atomic file writes."
5 | category = "dev"
6 | optional = false
7 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
8 |
9 | [[package]]
10 | name = "attrs"
11 | version = "21.4.0"
12 | description = "Classes Without Boilerplate"
13 | category = "dev"
14 | optional = false
15 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
16 |
17 | [package.extras]
18 | dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit", "cloudpickle"]
19 | docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"]
20 | tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "cloudpickle"]
21 | tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "cloudpickle"]
22 |
23 | [[package]]
24 | name = "black"
25 | version = "22.3.0"
26 | description = "The uncompromising code formatter."
27 | category = "dev"
28 | optional = false
29 | python-versions = ">=3.6.2"
30 |
31 | [package.dependencies]
32 | click = ">=8.0.0"
33 | mypy-extensions = ">=0.4.3"
34 | pathspec = ">=0.9.0"
35 | platformdirs = ">=2"
36 | tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""}
37 | typed-ast = {version = ">=1.4.2", markers = "python_version < \"3.8\" and implementation_name == \"cpython\""}
38 | typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""}
39 |
40 | [package.extras]
41 | colorama = ["colorama (>=0.4.3)"]
42 | d = ["aiohttp (>=3.7.4)"]
43 | jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"]
44 | uvloop = ["uvloop (>=0.15.2)"]
45 |
46 | [[package]]
47 | name = "certifi"
48 | version = "2021.10.8"
49 | description = "Python package for providing Mozilla's CA Bundle."
50 | category = "dev"
51 | optional = false
52 | python-versions = "*"
53 |
54 | [[package]]
55 | name = "charset-normalizer"
56 | version = "2.0.12"
57 | description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
58 | category = "dev"
59 | optional = false
60 | python-versions = ">=3.5.0"
61 |
62 | [package.extras]
63 | unicode_backport = ["unicodedata2"]
64 |
65 | [[package]]
66 | name = "click"
67 | version = "8.1.2"
68 | description = "Composable command line interface toolkit"
69 | category = "main"
70 | optional = false
71 | python-versions = ">=3.7"
72 |
73 | [package.dependencies]
74 | colorama = {version = "*", markers = "platform_system == \"Windows\""}
75 | importlib-metadata = {version = "*", markers = "python_version < \"3.8\""}
76 |
77 | [[package]]
78 | name = "colorama"
79 | version = "0.4.4"
80 | description = "Cross-platform colored terminal text."
81 | category = "main"
82 | optional = false
83 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
84 |
85 | [[package]]
86 | name = "commonmark"
87 | version = "0.9.1"
88 | description = "Python parser for the CommonMark Markdown spec"
89 | category = "main"
90 | optional = false
91 | python-versions = "*"
92 |
93 | [package.extras]
94 | test = ["flake8 (==3.7.8)", "hypothesis (==3.55.3)"]
95 |
96 | [[package]]
97 | name = "filelock"
98 | version = "3.6.0"
99 | description = "A platform independent file lock."
100 | category = "dev"
101 | optional = false
102 | python-versions = ">=3.7"
103 |
104 | [package.extras]
105 | docs = ["furo (>=2021.8.17b43)", "sphinx (>=4.1)", "sphinx-autodoc-typehints (>=1.12)"]
106 | testing = ["covdefaults (>=1.2.0)", "coverage (>=4)", "pytest (>=4)", "pytest-cov", "pytest-timeout (>=1.4.2)"]
107 |
108 | [[package]]
109 | name = "flake8"
110 | version = "4.0.1"
111 | description = "the modular source code checker: pep8 pyflakes and co"
112 | category = "dev"
113 | optional = false
114 | python-versions = ">=3.6"
115 |
116 | [package.dependencies]
117 | importlib-metadata = {version = "<4.3", markers = "python_version < \"3.8\""}
118 | mccabe = ">=0.6.0,<0.7.0"
119 | pycodestyle = ">=2.8.0,<2.9.0"
120 | pyflakes = ">=2.4.0,<2.5.0"
121 |
122 | [[package]]
123 | name = "idna"
124 | version = "3.3"
125 | description = "Internationalized Domain Names in Applications (IDNA)"
126 | category = "dev"
127 | optional = false
128 | python-versions = ">=3.5"
129 |
130 | [[package]]
131 | name = "importlib-metadata"
132 | version = "4.2.0"
133 | description = "Read metadata from Python packages"
134 | category = "main"
135 | optional = false
136 | python-versions = ">=3.6"
137 |
138 | [package.dependencies]
139 | typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""}
140 | zipp = ">=0.5"
141 |
142 | [package.extras]
143 | docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"]
144 | testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pep517", "pyfakefs", "flufl.flake8", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"]
145 |
146 | [[package]]
147 | name = "iniconfig"
148 | version = "1.1.1"
149 | description = "iniconfig: brain-dead simple config-ini parsing"
150 | category = "dev"
151 | optional = false
152 | python-versions = "*"
153 |
154 | [[package]]
155 | name = "isort"
156 | version = "5.10.1"
157 | description = "A Python utility / library to sort Python imports."
158 | category = "dev"
159 | optional = false
160 | python-versions = ">=3.6.1,<4.0"
161 |
162 | [package.extras]
163 | pipfile_deprecated_finder = ["pipreqs", "requirementslib"]
164 | requirements_deprecated_finder = ["pipreqs", "pip-api"]
165 | colors = ["colorama (>=0.4.3,<0.5.0)"]
166 | plugins = ["setuptools"]
167 |
168 | [[package]]
169 | name = "mccabe"
170 | version = "0.6.1"
171 | description = "McCabe checker, plugin for flake8"
172 | category = "dev"
173 | optional = false
174 | python-versions = "*"
175 |
176 | [[package]]
177 | name = "mypy"
178 | version = "0.942"
179 | description = "Optional static typing for Python"
180 | category = "dev"
181 | optional = false
182 | python-versions = ">=3.6"
183 |
184 | [package.dependencies]
185 | mypy-extensions = ">=0.4.3"
186 | tomli = ">=1.1.0"
187 | typed-ast = {version = ">=1.4.0,<2", markers = "python_version < \"3.8\""}
188 | typing-extensions = ">=3.10"
189 |
190 | [package.extras]
191 | dmypy = ["psutil (>=4.0)"]
192 | python2 = ["typed-ast (>=1.4.0,<2)"]
193 | reports = ["lxml"]
194 |
195 | [[package]]
196 | name = "mypy-extensions"
197 | version = "0.4.3"
198 | description = "Experimental type system extensions for programs checked with the mypy typechecker."
199 | category = "dev"
200 | optional = false
201 | python-versions = "*"
202 |
203 | [[package]]
204 | name = "orjson"
205 | version = "3.6.8"
206 | description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy"
207 | category = "main"
208 | optional = true
209 | python-versions = ">=3.7"
210 |
211 | [[package]]
212 | name = "packaging"
213 | version = "21.3"
214 | description = "Core utilities for Python packages"
215 | category = "dev"
216 | optional = false
217 | python-versions = ">=3.6"
218 |
219 | [package.dependencies]
220 | pyparsing = ">=2.0.2,<3.0.5 || >3.0.5"
221 |
222 | [[package]]
223 | name = "pathspec"
224 | version = "0.9.0"
225 | description = "Utility library for gitignore style pattern matching of file paths."
226 | category = "dev"
227 | optional = false
228 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
229 |
230 | [[package]]
231 | name = "platformdirs"
232 | version = "2.5.2"
233 | description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
234 | category = "dev"
235 | optional = false
236 | python-versions = ">=3.7"
237 |
238 | [package.extras]
239 | docs = ["furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx-autodoc-typehints (>=1.12)", "sphinx (>=4)"]
240 | test = ["appdirs (==1.4.4)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)", "pytest (>=6)"]
241 |
242 | [[package]]
243 | name = "pluggy"
244 | version = "1.0.0"
245 | description = "plugin and hook calling mechanisms for python"
246 | category = "dev"
247 | optional = false
248 | python-versions = ">=3.6"
249 |
250 | [package.dependencies]
251 | importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""}
252 |
253 | [package.extras]
254 | dev = ["pre-commit", "tox"]
255 | testing = ["pytest", "pytest-benchmark"]
256 |
257 | [[package]]
258 | name = "py"
259 | version = "1.11.0"
260 | description = "library with cross-python path, ini-parsing, io, code, log facilities"
261 | category = "dev"
262 | optional = false
263 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
264 |
265 | [[package]]
266 | name = "pycodestyle"
267 | version = "2.8.0"
268 | description = "Python style guide checker"
269 | category = "dev"
270 | optional = false
271 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
272 |
273 | [[package]]
274 | name = "pyflakes"
275 | version = "2.4.0"
276 | description = "passive checker of Python programs"
277 | category = "dev"
278 | optional = false
279 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
280 |
281 | [[package]]
282 | name = "pygments"
283 | version = "2.12.0"
284 | description = "Pygments is a syntax highlighting package written in Python."
285 | category = "main"
286 | optional = false
287 | python-versions = ">=3.6"
288 |
289 | [[package]]
290 | name = "pyparsing"
291 | version = "3.0.8"
292 | description = "pyparsing module - Classes and methods to define and execute parsing grammars"
293 | category = "dev"
294 | optional = false
295 | python-versions = ">=3.6.8"
296 |
297 | [package.extras]
298 | diagrams = ["railroad-diagrams", "jinja2"]
299 |
300 | [[package]]
301 | name = "pytest"
302 | version = "7.1.2"
303 | description = "pytest: simple powerful testing with Python"
304 | category = "dev"
305 | optional = false
306 | python-versions = ">=3.7"
307 |
308 | [package.dependencies]
309 | atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""}
310 | attrs = ">=19.2.0"
311 | colorama = {version = "*", markers = "sys_platform == \"win32\""}
312 | importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""}
313 | iniconfig = "*"
314 | packaging = "*"
315 | pluggy = ">=0.12,<2.0"
316 | py = ">=1.8.2"
317 | tomli = ">=1.0.0"
318 |
319 | [package.extras]
320 | testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"]
321 |
322 | [[package]]
323 | name = "pytest-black"
324 | version = "0.3.12"
325 | description = "A pytest plugin to enable format checking with black"
326 | category = "dev"
327 | optional = false
328 | python-versions = ">=2.7"
329 |
330 | [package.dependencies]
331 | black = {version = "*", markers = "python_version >= \"3.6\""}
332 | pytest = ">=3.5.0"
333 | toml = "*"
334 |
335 | [[package]]
336 | name = "pytest-flake8"
337 | version = "1.1.1"
338 | description = "pytest plugin to check FLAKE8 requirements"
339 | category = "dev"
340 | optional = false
341 | python-versions = "*"
342 |
343 | [package.dependencies]
344 | flake8 = ">=4.0"
345 | pytest = ">=7.0"
346 |
347 | [[package]]
348 | name = "pytest-isort"
349 | version = "2.0.0"
350 | description = "py.test plugin to check import ordering using isort"
351 | category = "dev"
352 | optional = false
353 | python-versions = "*"
354 |
355 | [package.dependencies]
356 | isort = ">=4.0"
357 |
358 | [package.extras]
359 | tests = ["mock"]
360 |
361 | [[package]]
362 | name = "pytest-mypy"
363 | version = "0.8.1"
364 | description = "Mypy static type checker plugin for Pytest"
365 | category = "dev"
366 | optional = false
367 | python-versions = ">=3.5"
368 |
369 | [package.dependencies]
370 | attrs = ">=19.0"
371 | filelock = ">=3.0"
372 | mypy = [
373 | {version = ">=0.500", markers = "python_version < \"3.8\""},
374 | {version = ">=0.700", markers = "python_version >= \"3.8\" and python_version < \"3.9\""},
375 | {version = ">=0.780", markers = "python_version >= \"3.9\""},
376 | ]
377 | pytest = ">=3.5"
378 |
379 | [[package]]
380 | name = "requests"
381 | version = "2.27.1"
382 | description = "Python HTTP for Humans."
383 | category = "dev"
384 | optional = false
385 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*"
386 |
387 | [package.dependencies]
388 | certifi = ">=2017.4.17"
389 | charset-normalizer = {version = ">=2.0.0,<2.1.0", markers = "python_version >= \"3\""}
390 | idna = {version = ">=2.5,<4", markers = "python_version >= \"3\""}
391 | urllib3 = ">=1.21.1,<1.27"
392 |
393 | [package.extras]
394 | socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"]
395 | use_chardet_on_py3 = ["chardet (>=3.0.2,<5)"]
396 |
397 | [[package]]
398 | name = "rich"
399 | version = "12.2.0"
400 | description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal"
401 | category = "main"
402 | optional = false
403 | python-versions = ">=3.6.3,<4.0.0"
404 |
405 | [package.dependencies]
406 | commonmark = ">=0.9.0,<0.10.0"
407 | pygments = ">=2.6.0,<3.0.0"
408 | typing-extensions = {version = ">=4.0.0,<5.0", markers = "python_version < \"3.9\""}
409 |
410 | [package.extras]
411 | jupyter = ["ipywidgets (>=7.5.1,<8.0.0)"]
412 |
413 | [[package]]
414 | name = "toml"
415 | version = "0.10.2"
416 | description = "Python Library for Tom's Obvious, Minimal Language"
417 | category = "dev"
418 | optional = false
419 | python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
420 |
421 | [[package]]
422 | name = "tomli"
423 | version = "2.0.1"
424 | description = "A lil' TOML parser"
425 | category = "dev"
426 | optional = false
427 | python-versions = ">=3.7"
428 |
429 | [[package]]
430 | name = "typed-ast"
431 | version = "1.5.3"
432 | description = "a fork of Python 2 and 3 ast modules with type comment support"
433 | category = "dev"
434 | optional = false
435 | python-versions = ">=3.6"
436 |
437 | [[package]]
438 | name = "types-orjson"
439 | version = "3.6.2"
440 | description = "Typing stubs for orjson"
441 | category = "dev"
442 | optional = false
443 | python-versions = "*"
444 |
445 | [[package]]
446 | name = "types-requests"
447 | version = "2.27.20"
448 | description = "Typing stubs for requests"
449 | category = "dev"
450 | optional = false
451 | python-versions = "*"
452 |
453 | [package.dependencies]
454 | types-urllib3 = "<1.27"
455 |
456 | [[package]]
457 | name = "types-urllib3"
458 | version = "1.26.13"
459 | description = "Typing stubs for urllib3"
460 | category = "dev"
461 | optional = false
462 | python-versions = "*"
463 |
464 | [[package]]
465 | name = "typing-extensions"
466 | version = "4.2.0"
467 | description = "Backported and Experimental Type Hints for Python 3.7+"
468 | category = "main"
469 | optional = false
470 | python-versions = ">=3.7"
471 |
472 | [[package]]
473 | name = "urllib3"
474 | version = "1.26.9"
475 | description = "HTTP library with thread-safe connection pooling, file post, and more."
476 | category = "dev"
477 | optional = false
478 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4"
479 |
480 | [package.extras]
481 | brotli = ["brotlicffi (>=0.8.0)", "brotli (>=1.0.9)", "brotlipy (>=0.6.0)"]
482 | secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"]
483 | socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"]
484 |
485 | [[package]]
486 | name = "zipp"
487 | version = "3.8.0"
488 | description = "Backport of pathlib-compatible object wrapper for zip files"
489 | category = "main"
490 | optional = false
491 | python-versions = ">=3.7"
492 |
493 | [package.extras]
494 | docs = ["sphinx", "jaraco.packaging (>=9)", "rst.linker (>=1.9)"]
495 | testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy (>=0.9.1)"]
496 |
497 | [extras]
498 | optimize = ["orjson"]
499 |
500 | [metadata]
501 | lock-version = "1.1"
502 | python-versions = "^3.7"
503 | content-hash = "c7df16c9b4c5c23eb5259af6d9d30561ebd28eb8f201a748f73580d1f3811245"
504 |
505 | [metadata.files]
506 | atomicwrites = [
507 | {file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"},
508 | {file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"},
509 | ]
510 | attrs = [
511 | {file = "attrs-21.4.0-py2.py3-none-any.whl", hash = "sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4"},
512 | {file = "attrs-21.4.0.tar.gz", hash = "sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd"},
513 | ]
514 | black = [
515 | {file = "black-22.3.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2497f9c2386572e28921fa8bec7be3e51de6801f7459dffd6e62492531c47e09"},
516 | {file = "black-22.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5795a0375eb87bfe902e80e0c8cfaedf8af4d49694d69161e5bd3206c18618bb"},
517 | {file = "black-22.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e3556168e2e5c49629f7b0f377070240bd5511e45e25a4497bb0073d9dda776a"},
518 | {file = "black-22.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67c8301ec94e3bcc8906740fe071391bce40a862b7be0b86fb5382beefecd968"},
519 | {file = "black-22.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:fd57160949179ec517d32ac2ac898b5f20d68ed1a9c977346efbac9c2f1e779d"},
520 | {file = "black-22.3.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:cc1e1de68c8e5444e8f94c3670bb48a2beef0e91dddfd4fcc29595ebd90bb9ce"},
521 | {file = "black-22.3.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d2fc92002d44746d3e7db7cf9313cf4452f43e9ea77a2c939defce3b10b5c82"},
522 | {file = "black-22.3.0-cp36-cp36m-win_amd64.whl", hash = "sha256:a6342964b43a99dbc72f72812bf88cad8f0217ae9acb47c0d4f141a6416d2d7b"},
523 | {file = "black-22.3.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:328efc0cc70ccb23429d6be184a15ce613f676bdfc85e5fe8ea2a9354b4e9015"},
524 | {file = "black-22.3.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:06f9d8846f2340dfac80ceb20200ea5d1b3f181dd0556b47af4e8e0b24fa0a6b"},
525 | {file = "black-22.3.0-cp37-cp37m-win_amd64.whl", hash = "sha256:ad4efa5fad66b903b4a5f96d91461d90b9507a812b3c5de657d544215bb7877a"},
526 | {file = "black-22.3.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e8477ec6bbfe0312c128e74644ac8a02ca06bcdb8982d4ee06f209be28cdf163"},
527 | {file = "black-22.3.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:637a4014c63fbf42a692d22b55d8ad6968a946b4a6ebc385c5505d9625b6a464"},
528 | {file = "black-22.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:863714200ada56cbc366dc9ae5291ceb936573155f8bf8e9de92aef51f3ad0f0"},
529 | {file = "black-22.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10dbe6e6d2988049b4655b2b739f98785a884d4d6b85bc35133a8fb9a2233176"},
530 | {file = "black-22.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:cee3e11161dde1b2a33a904b850b0899e0424cc331b7295f2a9698e79f9a69a0"},
531 | {file = "black-22.3.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5891ef8abc06576985de8fa88e95ab70641de6c1fca97e2a15820a9b69e51b20"},
532 | {file = "black-22.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:30d78ba6bf080eeaf0b7b875d924b15cd46fec5fd044ddfbad38c8ea9171043a"},
533 | {file = "black-22.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ee8f1f7228cce7dffc2b464f07ce769f478968bfb3dd1254a4c2eeed84928aad"},
534 | {file = "black-22.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ee227b696ca60dd1c507be80a6bc849a5a6ab57ac7352aad1ffec9e8b805f21"},
535 | {file = "black-22.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:9b542ced1ec0ceeff5b37d69838106a6348e60db7b8fdd245294dc1d26136265"},
536 | {file = "black-22.3.0-py3-none-any.whl", hash = "sha256:bc58025940a896d7e5356952228b68f793cf5fcb342be703c3a2669a1488cb72"},
537 | {file = "black-22.3.0.tar.gz", hash = "sha256:35020b8886c022ced9282b51b5a875b6d1ab0c387b31a065b84db7c33085ca79"},
538 | ]
539 | certifi = [
540 | {file = "certifi-2021.10.8-py2.py3-none-any.whl", hash = "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569"},
541 | {file = "certifi-2021.10.8.tar.gz", hash = "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872"},
542 | ]
543 | charset-normalizer = [
544 | {file = "charset-normalizer-2.0.12.tar.gz", hash = "sha256:2857e29ff0d34db842cd7ca3230549d1a697f96ee6d3fb071cfa6c7393832597"},
545 | {file = "charset_normalizer-2.0.12-py3-none-any.whl", hash = "sha256:6881edbebdb17b39b4eaaa821b438bf6eddffb4468cf344f09f89def34a8b1df"},
546 | ]
547 | click = [
548 | {file = "click-8.1.2-py3-none-any.whl", hash = "sha256:24e1a4a9ec5bf6299411369b208c1df2188d9eb8d916302fe6bf03faed227f1e"},
549 | {file = "click-8.1.2.tar.gz", hash = "sha256:479707fe14d9ec9a0757618b7a100a0ae4c4e236fac5b7f80ca68028141a1a72"},
550 | ]
551 | colorama = [
552 | {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"},
553 | {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"},
554 | ]
555 | commonmark = [
556 | {file = "commonmark-0.9.1-py2.py3-none-any.whl", hash = "sha256:da2f38c92590f83de410ba1a3cbceafbc74fee9def35f9251ba9a971d6d66fd9"},
557 | {file = "commonmark-0.9.1.tar.gz", hash = "sha256:452f9dc859be7f06631ddcb328b6919c67984aca654e5fefb3914d54691aed60"},
558 | ]
559 | filelock = [
560 | {file = "filelock-3.6.0-py3-none-any.whl", hash = "sha256:f8314284bfffbdcfa0ff3d7992b023d4c628ced6feb957351d4c48d059f56bc0"},
561 | {file = "filelock-3.6.0.tar.gz", hash = "sha256:9cd540a9352e432c7246a48fe4e8712b10acb1df2ad1f30e8c070b82ae1fed85"},
562 | ]
563 | flake8 = [
564 | {file = "flake8-4.0.1-py2.py3-none-any.whl", hash = "sha256:479b1304f72536a55948cb40a32dce8bb0ffe3501e26eaf292c7e60eb5e0428d"},
565 | {file = "flake8-4.0.1.tar.gz", hash = "sha256:806e034dda44114815e23c16ef92f95c91e4c71100ff52813adf7132a6ad870d"},
566 | ]
567 | idna = [
568 | {file = "idna-3.3-py3-none-any.whl", hash = "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff"},
569 | {file = "idna-3.3.tar.gz", hash = "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"},
570 | ]
571 | importlib-metadata = [
572 | {file = "importlib_metadata-4.2.0-py3-none-any.whl", hash = "sha256:057e92c15bc8d9e8109738a48db0ccb31b4d9d5cfbee5a8670879a30be66304b"},
573 | {file = "importlib_metadata-4.2.0.tar.gz", hash = "sha256:b7e52a1f8dec14a75ea73e0891f3060099ca1d8e6a462a4dff11c3e119ea1b31"},
574 | ]
575 | iniconfig = [
576 | {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"},
577 | {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"},
578 | ]
579 | isort = [
580 | {file = "isort-5.10.1-py3-none-any.whl", hash = "sha256:6f62d78e2f89b4500b080fe3a81690850cd254227f27f75c3a0c491a1f351ba7"},
581 | {file = "isort-5.10.1.tar.gz", hash = "sha256:e8443a5e7a020e9d7f97f1d7d9cd17c88bcb3bc7e218bf9cf5095fe550be2951"},
582 | ]
583 | mccabe = [
584 | {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"},
585 | {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"},
586 | ]
587 | mypy = [
588 | {file = "mypy-0.942-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5bf44840fb43ac4074636fd47ee476d73f0039f4f54e86d7265077dc199be24d"},
589 | {file = "mypy-0.942-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dcd955f36e0180258a96f880348fbca54ce092b40fbb4b37372ae3b25a0b0a46"},
590 | {file = "mypy-0.942-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6776e5fa22381cc761df53e7496a805801c1a751b27b99a9ff2f0ca848c7eca0"},
591 | {file = "mypy-0.942-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:edf7237137a1a9330046dbb14796963d734dd740a98d5e144a3eb1d267f5f9ee"},
592 | {file = "mypy-0.942-cp310-cp310-win_amd64.whl", hash = "sha256:64235137edc16bee6f095aba73be5334677d6f6bdb7fa03cfab90164fa294a17"},
593 | {file = "mypy-0.942-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:b840cfe89c4ab6386c40300689cd8645fc8d2d5f20101c7f8bd23d15fca14904"},
594 | {file = "mypy-0.942-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2b184db8c618c43c3a31b32ff00cd28195d39e9c24e7c3b401f3db7f6e5767f5"},
595 | {file = "mypy-0.942-cp36-cp36m-win_amd64.whl", hash = "sha256:1a0459c333f00e6a11cbf6b468b870c2b99a906cb72d6eadf3d1d95d38c9352c"},
596 | {file = "mypy-0.942-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4c3e497588afccfa4334a9986b56f703e75793133c4be3a02d06a3df16b67a58"},
597 | {file = "mypy-0.942-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6f6ad963172152e112b87cc7ec103ba0f2db2f1cd8997237827c052a3903eaa6"},
598 | {file = "mypy-0.942-cp37-cp37m-win_amd64.whl", hash = "sha256:0e2dd88410937423fba18e57147dd07cd8381291b93d5b1984626f173a26543e"},
599 | {file = "mypy-0.942-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:246e1aa127d5b78488a4a0594bd95f6d6fb9d63cf08a66dafbff8595d8891f67"},
600 | {file = "mypy-0.942-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d8d3ba77e56b84cd47a8ee45b62c84b6d80d32383928fe2548c9a124ea0a725c"},
601 | {file = "mypy-0.942-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2bc249409a7168d37c658e062e1ab5173300984a2dada2589638568ddc1db02b"},
602 | {file = "mypy-0.942-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:9521c1265ccaaa1791d2c13582f06facf815f426cd8b07c3a485f486a8ffc1f3"},
603 | {file = "mypy-0.942-cp38-cp38-win_amd64.whl", hash = "sha256:e865fec858d75b78b4d63266c9aff770ecb6a39dfb6d6b56c47f7f8aba6baba8"},
604 | {file = "mypy-0.942-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:6ce34a118d1a898f47def970a2042b8af6bdcc01546454726c7dd2171aa6dfca"},
605 | {file = "mypy-0.942-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:10daab80bc40f84e3f087d896cdb53dc811a9f04eae4b3f95779c26edee89d16"},
606 | {file = "mypy-0.942-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3841b5433ff936bff2f4dc8d54cf2cdbfea5d8e88cedfac45c161368e5770ba6"},
607 | {file = "mypy-0.942-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6f7106cbf9cc2f403693bf50ed7c9fa5bb3dfa9007b240db3c910929abe2a322"},
608 | {file = "mypy-0.942-cp39-cp39-win_amd64.whl", hash = "sha256:7742d2c4e46bb5017b51c810283a6a389296cda03df805a4f7869a6f41246534"},
609 | {file = "mypy-0.942-py3-none-any.whl", hash = "sha256:a1b383fe99678d7402754fe90448d4037f9512ce70c21f8aee3b8bf48ffc51db"},
610 | {file = "mypy-0.942.tar.gz", hash = "sha256:17e44649fec92e9f82102b48a3bf7b4a5510ad0cd22fa21a104826b5db4903e2"},
611 | ]
612 | mypy-extensions = [
613 | {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"},
614 | {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"},
615 | ]
616 | orjson = [
617 | {file = "orjson-3.6.8-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:3a287a650458de2211db03681b71c3e5cb2212b62f17a39df8ad99fc54855d0f"},
618 | {file = "orjson-3.6.8-cp310-cp310-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:5204e25c12cea58e524fc82f7c27ed0586f592f777b33075a92ab7b3eb3687c2"},
619 | {file = "orjson-3.6.8-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:77e8386393add64f959c044e0fb682364fd0e611a6f477aa13f0e6a733bd6a28"},
620 | {file = "orjson-3.6.8-cp310-cp310-manylinux_2_24_aarch64.whl", hash = "sha256:279f2d2af393fdf8601020744cb206b91b54ad60fb8401e0761819c7bda1f4e4"},
621 | {file = "orjson-3.6.8-cp310-cp310-manylinux_2_24_x86_64.whl", hash = "sha256:c31c9f389be7906f978ed4192eb58a4b74a37ad60556a0b88ddc47c576697770"},
622 | {file = "orjson-3.6.8-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0db5c5a0c5b89f092d52f6e5a3701660a9d6ffa9e2968b3ce17c2bc4f5eb0414"},
623 | {file = "orjson-3.6.8-cp310-none-win_amd64.whl", hash = "sha256:eb22485847b9a0c4bbedc668df860126ac931edbed1d456cf41a59f3cb961ed8"},
624 | {file = "orjson-3.6.8-cp37-cp37m-macosx_10_7_x86_64.whl", hash = "sha256:1a5fe569310bc819279bd4d5f2c349910b104ed3207936246dd5d5e0b085e74a"},
625 | {file = "orjson-3.6.8-cp37-cp37m-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:ccb356a47ab1067cd3549847e9db1d279a63fe0482d315b3ffd6e7abef35ef77"},
626 | {file = "orjson-3.6.8-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ab29c069c222248ce302a25855b4e1664f9436e8ae5a131fb0859daf31676d2b"},
627 | {file = "orjson-3.6.8-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d2b5e4cba9e774ac011071d9d27760f97f4b8cd46003e971d122e712f971345"},
628 | {file = "orjson-3.6.8-cp37-cp37m-manylinux_2_24_aarch64.whl", hash = "sha256:c311ec504414d22834d5b972a209619925b48263856a11a14d90230f9682d49c"},
629 | {file = "orjson-3.6.8-cp37-cp37m-manylinux_2_24_x86_64.whl", hash = "sha256:a3dfec7950b90fb8d143743503ee53fa06b32e6068bdea792fc866284da3d71d"},
630 | {file = "orjson-3.6.8-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:b890dbbada2cbb26eb29bd43a848426f007f094bb0758df10dfe7a438e1cb4b4"},
631 | {file = "orjson-3.6.8-cp37-none-win_amd64.whl", hash = "sha256:9143ae2c52771525be9ad11a7a8cc8e7fd75391b107e7e644a9e0050496f6b4f"},
632 | {file = "orjson-3.6.8-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:33a82199fd42f6436f833e210ae5129c922a5c355629356ca7a8e82964da7285"},
633 | {file = "orjson-3.6.8-cp38-cp38-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:90159ea8b9a5a2a98fa33dc7b421cfac4d2ae91ba5e1058f5909e7f059f6b467"},
634 | {file = "orjson-3.6.8-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:656fbe15d9ef0733e740d9def78f4fdb4153102f4836ee774a05123499005931"},
635 | {file = "orjson-3.6.8-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7be3be6153843e0f01351b1313a5ad4723595427680dac2dfff22a37e652ce02"},
636 | {file = "orjson-3.6.8-cp38-cp38-manylinux_2_24_aarch64.whl", hash = "sha256:dd24f66b6697ee7424f7da575ec6cbffc8ede441114d53470949cda4d97c6e56"},
637 | {file = "orjson-3.6.8-cp38-cp38-manylinux_2_24_x86_64.whl", hash = "sha256:b07c780f7345ecf5901356dc21dee0669defc489c38ce7b9ab0f5e008cc0385c"},
638 | {file = "orjson-3.6.8-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:ea32015a5d8a4ce00d348a0de5dc7040e0ad58f970a8fcbb5713a1eac129e493"},
639 | {file = "orjson-3.6.8-cp38-none-win_amd64.whl", hash = "sha256:c5a3e382194c838988ec128a26b08aa92044e5e055491cc4056142af0c1c54d7"},
640 | {file = "orjson-3.6.8-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:83a8424e857ae1bf53530e88b4eb2f16ca2b489073b924e655f1575cacd7f52a"},
641 | {file = "orjson-3.6.8-cp39-cp39-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:81e1a6a2d67f15007dadacbf9ba5d3d79237e5e33786c028557fe5a2b72f1c9a"},
642 | {file = "orjson-3.6.8-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:137b539881c77866eba86ff6a11df910daf2eb9ab8f1acae62f879e83d7c38af"},
643 | {file = "orjson-3.6.8-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2cbd358f3b3ad539a27e36900e8e7d172d0e1b72ad9dd7d69544dcbc0f067ee7"},
644 | {file = "orjson-3.6.8-cp39-cp39-manylinux_2_24_aarch64.whl", hash = "sha256:6ab94701542d40b90903ecfc339333f458884979a01cb9268bc662cc67a5f6d8"},
645 | {file = "orjson-3.6.8-cp39-cp39-manylinux_2_24_x86_64.whl", hash = "sha256:32b6f26593a9eb606b40775826beb0dac152e3d224ea393688fced036045a821"},
646 | {file = "orjson-3.6.8-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:afd9e329ebd3418cac3cd747769b1d52daa25fa672bbf414ab59f0e0881b32b9"},
647 | {file = "orjson-3.6.8-cp39-none-win_amd64.whl", hash = "sha256:0c89b419914d3d1f65a1b0883f377abe42a6e44f6624ba1c63e8846cbfc2fa60"},
648 | {file = "orjson-3.6.8.tar.gz", hash = "sha256:e19d23741c5de13689bb316abfccea15a19c264e3ec8eb332a5319a583595ace"},
649 | ]
650 | packaging = [
651 | {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"},
652 | {file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"},
653 | ]
654 | pathspec = [
655 | {file = "pathspec-0.9.0-py2.py3-none-any.whl", hash = "sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a"},
656 | {file = "pathspec-0.9.0.tar.gz", hash = "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1"},
657 | ]
658 | platformdirs = [
659 | {file = "platformdirs-2.5.2-py3-none-any.whl", hash = "sha256:027d8e83a2d7de06bbac4e5ef7e023c02b863d7ea5d079477e722bb41ab25788"},
660 | {file = "platformdirs-2.5.2.tar.gz", hash = "sha256:58c8abb07dcb441e6ee4b11d8df0ac856038f944ab98b7be6b27b2a3c7feef19"},
661 | ]
662 | pluggy = [
663 | {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"},
664 | {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"},
665 | ]
666 | py = [
667 | {file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"},
668 | {file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"},
669 | ]
670 | pycodestyle = [
671 | {file = "pycodestyle-2.8.0-py2.py3-none-any.whl", hash = "sha256:720f8b39dde8b293825e7ff02c475f3077124006db4f440dcbc9a20b76548a20"},
672 | {file = "pycodestyle-2.8.0.tar.gz", hash = "sha256:eddd5847ef438ea1c7870ca7eb78a9d47ce0cdb4851a5523949f2601d0cbbe7f"},
673 | ]
674 | pyflakes = [
675 | {file = "pyflakes-2.4.0-py2.py3-none-any.whl", hash = "sha256:3bb3a3f256f4b7968c9c788781e4ff07dce46bdf12339dcda61053375426ee2e"},
676 | {file = "pyflakes-2.4.0.tar.gz", hash = "sha256:05a85c2872edf37a4ed30b0cce2f6093e1d0581f8c19d7393122da7e25b2b24c"},
677 | ]
678 | pygments = [
679 | {file = "Pygments-2.12.0-py3-none-any.whl", hash = "sha256:dc9c10fb40944260f6ed4c688ece0cd2048414940f1cea51b8b226318411c519"},
680 | {file = "Pygments-2.12.0.tar.gz", hash = "sha256:5eb116118f9612ff1ee89ac96437bb6b49e8f04d8a13b514ba26f620208e26eb"},
681 | ]
682 | pyparsing = [
683 | {file = "pyparsing-3.0.8-py3-none-any.whl", hash = "sha256:ef7b523f6356f763771559412c0d7134753f037822dad1b16945b7b846f7ad06"},
684 | {file = "pyparsing-3.0.8.tar.gz", hash = "sha256:7bf433498c016c4314268d95df76c81b842a4cb2b276fa3312cfb1e1d85f6954"},
685 | ]
686 | pytest = [
687 | {file = "pytest-7.1.2-py3-none-any.whl", hash = "sha256:13d0e3ccfc2b6e26be000cb6568c832ba67ba32e719443bfe725814d3c42433c"},
688 | {file = "pytest-7.1.2.tar.gz", hash = "sha256:a06a0425453864a270bc45e71f783330a7428defb4230fb5e6a731fde06ecd45"},
689 | ]
690 | pytest-black = [
691 | {file = "pytest-black-0.3.12.tar.gz", hash = "sha256:1d339b004f764d6cd0f06e690f6dd748df3d62e6fe1a692d6a5500ac2c5b75a5"},
692 | ]
693 | pytest-flake8 = [
694 | {file = "pytest-flake8-1.1.1.tar.gz", hash = "sha256:ba4f243de3cb4c2486ed9e70752c80dd4b636f7ccb27d4eba763c35ed0cd316e"},
695 | {file = "pytest_flake8-1.1.1-py2.py3-none-any.whl", hash = "sha256:e0661a786f8cbf976c185f706fdaf5d6df0b1667c3bcff8e823ba263618627e7"},
696 | ]
697 | pytest-isort = [
698 | {file = "pytest-isort-2.0.0.tar.gz", hash = "sha256:821a8c5c9c4f3a3c52cfa9c541fbe89ac9e28728125125af53724c4c3f129117"},
699 | {file = "pytest_isort-2.0.0-py3-none-any.whl", hash = "sha256:ab949c593213dad38ba75db32a0ce361fcddd11d4152be4a2c93b85104cc4376"},
700 | ]
701 | pytest-mypy = [
702 | {file = "pytest-mypy-0.8.1.tar.gz", hash = "sha256:1fa55723a4bf1d054fcba1c3bd694215a2a65cc95ab10164f5808afd893f3b11"},
703 | {file = "pytest_mypy-0.8.1-py3-none-any.whl", hash = "sha256:6e68e8eb7ceeb7d1c83a1590912f784879f037b51adfb9c17b95c6b2fc57466b"},
704 | ]
705 | requests = [
706 | {file = "requests-2.27.1-py2.py3-none-any.whl", hash = "sha256:f22fa1e554c9ddfd16e6e41ac79759e17be9e492b3587efa038054674760e72d"},
707 | {file = "requests-2.27.1.tar.gz", hash = "sha256:68d7c56fd5a8999887728ef304a6d12edc7be74f1cfa47714fc8b414525c9a61"},
708 | ]
709 | rich = [
710 | {file = "rich-12.2.0-py3-none-any.whl", hash = "sha256:c50f3d253bc6a9bb9c79d61a26d510d74abdf1b16881260fab5edfc3edfb082f"},
711 | {file = "rich-12.2.0.tar.gz", hash = "sha256:ea74bc9dad9589d8eea3e3fd0b136d8bf6e428888955f215824c2894f0da8b47"},
712 | ]
713 | toml = [
714 | {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"},
715 | {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"},
716 | ]
717 | tomli = [
718 | {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"},
719 | {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"},
720 | ]
721 | typed-ast = [
722 | {file = "typed_ast-1.5.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9ad3b48cf2b487be140072fb86feff36801487d4abb7382bb1929aaac80638ea"},
723 | {file = "typed_ast-1.5.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:542cd732351ba8235f20faa0fc7398946fe1a57f2cdb289e5497e1e7f48cfedb"},
724 | {file = "typed_ast-1.5.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5dc2c11ae59003d4a26dda637222d9ae924387f96acae9492df663843aefad55"},
725 | {file = "typed_ast-1.5.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:fd5df1313915dbd70eaaa88c19030b441742e8b05e6103c631c83b75e0435ccc"},
726 | {file = "typed_ast-1.5.3-cp310-cp310-win_amd64.whl", hash = "sha256:e34f9b9e61333ecb0f7d79c21c28aa5cd63bec15cb7e1310d7d3da6ce886bc9b"},
727 | {file = "typed_ast-1.5.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f818c5b81966d4728fec14caa338e30a70dfc3da577984d38f97816c4b3071ec"},
728 | {file = "typed_ast-1.5.3-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3042bfc9ca118712c9809201f55355479cfcdc17449f9f8db5e744e9625c6805"},
729 | {file = "typed_ast-1.5.3-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:4fff9fdcce59dc61ec1b317bdb319f8f4e6b69ebbe61193ae0a60c5f9333dc49"},
730 | {file = "typed_ast-1.5.3-cp36-cp36m-win_amd64.whl", hash = "sha256:8e0b8528838ffd426fea8d18bde4c73bcb4167218998cc8b9ee0a0f2bfe678a6"},
731 | {file = "typed_ast-1.5.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8ef1d96ad05a291f5c36895d86d1375c0ee70595b90f6bb5f5fdbee749b146db"},
732 | {file = "typed_ast-1.5.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed44e81517364cb5ba367e4f68fca01fba42a7a4690d40c07886586ac267d9b9"},
733 | {file = "typed_ast-1.5.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f60d9de0d087454c91b3999a296d0c4558c1666771e3460621875021bf899af9"},
734 | {file = "typed_ast-1.5.3-cp37-cp37m-win_amd64.whl", hash = "sha256:9e237e74fd321a55c90eee9bc5d44be976979ad38a29bbd734148295c1ce7617"},
735 | {file = "typed_ast-1.5.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ee852185964744987609b40aee1d2eb81502ae63ee8eef614558f96a56c1902d"},
736 | {file = "typed_ast-1.5.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:27e46cdd01d6c3a0dd8f728b6a938a6751f7bd324817501c15fb056307f918c6"},
737 | {file = "typed_ast-1.5.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d64dabc6336ddc10373922a146fa2256043b3b43e61f28961caec2a5207c56d5"},
738 | {file = "typed_ast-1.5.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:8cdf91b0c466a6c43f36c1964772918a2c04cfa83df8001ff32a89e357f8eb06"},
739 | {file = "typed_ast-1.5.3-cp38-cp38-win_amd64.whl", hash = "sha256:9cc9e1457e1feb06b075c8ef8aeb046a28ec351b1958b42c7c31c989c841403a"},
740 | {file = "typed_ast-1.5.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e20d196815eeffb3d76b75223e8ffed124e65ee62097e4e73afb5fec6b993e7a"},
741 | {file = "typed_ast-1.5.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:37e5349d1d5de2f4763d534ccb26809d1c24b180a477659a12c4bde9dd677d74"},
742 | {file = "typed_ast-1.5.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9f1a27592fac87daa4e3f16538713d705599b0a27dfe25518b80b6b017f0a6d"},
743 | {file = "typed_ast-1.5.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:8831479695eadc8b5ffed06fdfb3e424adc37962a75925668deeb503f446c0a3"},
744 | {file = "typed_ast-1.5.3-cp39-cp39-win_amd64.whl", hash = "sha256:20d5118e494478ef2d3a2702d964dae830aedd7b4d3b626d003eea526be18718"},
745 | {file = "typed_ast-1.5.3.tar.gz", hash = "sha256:27f25232e2dd0edfe1f019d6bfaaf11e86e657d9bdb7b0956db95f560cceb2b3"},
746 | ]
747 | types-orjson = [
748 | {file = "types-orjson-3.6.2.tar.gz", hash = "sha256:cf9afcc79a86325c7aff251790338109ed6f6b1bab09d2d4262dd18c85a3c638"},
749 | {file = "types_orjson-3.6.2-py3-none-any.whl", hash = "sha256:22ee9a79236b6b0bfb35a0684eded62ad930a88a56797fa3c449b026cf7dbfe4"},
750 | ]
751 | types-requests = [
752 | {file = "types-requests-2.27.20.tar.gz", hash = "sha256:63344573cde6c4efd44d867c0158d9fb7e6beb95721cbe9882f3f857ee8a5398"},
753 | {file = "types_requests-2.27.20-py3-none-any.whl", hash = "sha256:68b8de86552116424ec23b77afc925e111afb6496d3821b183b7d151b3b834d4"},
754 | ]
755 | types-urllib3 = [
756 | {file = "types-urllib3-1.26.13.tar.gz", hash = "sha256:40f8fb5e8cd7d57e8aefdee3fdd5e930aa1a1bb4179cdadd55226cea588af790"},
757 | {file = "types_urllib3-1.26.13-py3-none-any.whl", hash = "sha256:ff7500641824f881b2c7bde4cc57e6c3abf03d1e005bae83aca752e77213a5da"},
758 | ]
759 | typing-extensions = [
760 | {file = "typing_extensions-4.2.0-py3-none-any.whl", hash = "sha256:6657594ee297170d19f67d55c05852a874e7eb634f4f753dbd667855e07c1708"},
761 | {file = "typing_extensions-4.2.0.tar.gz", hash = "sha256:f1c24655a0da0d1b67f07e17a5e6b2a105894e6824b92096378bb3668ef02376"},
762 | ]
763 | urllib3 = [
764 | {file = "urllib3-1.26.9-py2.py3-none-any.whl", hash = "sha256:44ece4d53fb1706f667c9bd1c648f5469a2ec925fcf3a776667042d645472c14"},
765 | {file = "urllib3-1.26.9.tar.gz", hash = "sha256:aabaf16477806a5e1dd19aa41f8c2b7950dd3c746362d7e3223dbe6de6ac448e"},
766 | ]
767 | zipp = [
768 | {file = "zipp-3.8.0-py3-none-any.whl", hash = "sha256:c4f6e5bbf48e74f7a38e7cc5b0480ff42b0ae5178957d564d18932525d5cf099"},
769 | {file = "zipp-3.8.0.tar.gz", hash = "sha256:56bf8aadb83c24db6c4b577e13de374ccfb67da2078beba1d037c17980bf43ad"},
770 | ]
771 |
--------------------------------------------------------------------------------
/pyproject.toml:
--------------------------------------------------------------------------------
1 | [tool.poetry]
2 | name = "pywhat"
3 | version = "5.1.0"
4 | description = "What is that thing?"
5 | authors = ["Bee "]
6 | license = "MIT"
7 | documentation = "https://github.com/bee-san/pyWhat/wiki"
8 | readme = "README.md"
9 |
10 | [tool.poetry.dependencies]
11 | python = "^3.7"
12 | click = "^8.0.0"
13 | rich = ">=11.0.0"
14 | orjson = {version = "^3.6.1", optional = true}
15 |
16 | [tool.poetry.dev-dependencies]
17 | pytest = "^7.0"
18 | black = "^22.1.0"
19 | isort = "^5.9.3"
20 | flake8 = "^4.0"
21 | requests = "^2.26.0"
22 | pytest-black = "^0.3.12"
23 | pytest-isort = "^2.0.0"
24 | pytest-flake8 = "^1.0.7"
25 | pytest-mypy = "^0.8.1"
26 | types-requests = "^2.25.9"
27 | types-orjson = "^3.6.0"
28 |
29 | [tool.poetry.extras]
30 | optimize = ["orjson"]
31 |
32 | [build-system]
33 | requires = ["poetry-core>=1.0.0"]
34 | build-backend = "poetry.core.masonry.api"
35 |
36 | [tool.poetry.scripts]
37 | pywhat = "pywhat.what:main"
38 | what = "pywhat.what:main"
39 |
40 | [tool.isort]
41 | profile = "black"
42 | multi_line_output = 3
43 | include_trailing_comma = true
44 | force_grid_wrap = 0
45 | use_parentheses = true
46 | ensure_newline_before_comments = true
47 | line_length = 88
48 |
49 | [tool.mypy]
50 | ignore_missing_imports = true
51 |
52 | [tool.pytest.ini_options]
53 | addopts = "--black --isort --flake8 --mypy"
54 |
--------------------------------------------------------------------------------
/pywhat/Data/file_signatures.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "Hexadecimal File Signature": "2321",
4 | "ISO 8859-1": "23 21",
5 | "Filename Extension": null,
6 | "Description": "Script or data to be passed to the program following the Shebang (Unix)shebang (#!)",
7 | "Popular": 0
8 | },
9 | {
10 | "Hexadecimal File Signature": "a1b2c3d4d4c3b2a1",
11 | "ISO 8859-1": "a1 b2 c3 d4 d4 c3 b2 a1",
12 | "Filename Extension": "pcap",
13 | "URL": "https://wiki.wireshark.org/Development/LibpcapFileFormat#Global_Header",
14 | "Description": "Libpcap File Format",
15 | "Popular": 0
16 | },
17 | {
18 | "Hexadecimal File Signature": "0a0d0d0a",
19 | "ISO 8859-1": null,
20 | "Filename Extension": "pcapng",
21 | "URL": "https://www.winpcap.org/ntar/draft/PCAP-DumpFileFormat.html#sectionshb ",
22 | "Description": "PCAP Next Generation Dump File Format",
23 | "Popular": 0
24 | },
25 | {
26 | "Hexadecimal File Signature": "edabeedb",
27 | "ISO 8859-1": "ed ab ee db",
28 | "Filename Extension": "rpm",
29 | "URL": "ftp://ftp.tuwien.ac.at/.vhost/www.openpkg.org/doc/book/maximum-rpm.html/node26.html ",
30 | "Description": "RedHat Package Manager (RPM) package",
31 | "Popular": 0
32 | },
33 | {
34 | "Hexadecimal File Signature": "53514c69746520666f726d6174203300",
35 | "ISO 8859-1": "SQLite format 3.",
36 | "Filename Extension": "sqlitedbsqlitedb",
37 | "URL": "https://www.sqlite.org/fileformat.html ",
38 | "Description": "SQLite Database",
39 | "Popular": 0
40 | },
41 | {
42 | "Hexadecimal File Signature": "53503031",
43 | "ISO 8859-1": "SP01",
44 | "Filename Extension": "bin",
45 | "URL": "https://github.com/NiLuJe/KindleTool ",
46 | "Description": "Amazon Kindle Update Package",
47 | "Popular": 0
48 | },
49 | {
50 | "Hexadecimal File Signature": "00",
51 | "ISO 8859-1": null,
52 | "Filename Extension": "PICPIFSEAYTR",
53 | "Description": "IBM Storyboard bitmap file Windows Program information fileProgram Information File Mac StuffItStuffit Self-Extracting Archive IRIS Optical character recognitionOCR data file",
54 | "Popular": 0
55 | },
56 | {
57 | "Hexadecimal File Signature": "000000000000000000000000000000000000000000000000",
58 | "ISO 8859-1": null,
59 | "Filename Extension": "PDB",
60 | "Description": "PalmPilot Database/Document File",
61 | "Popular": 0
62 | },
63 | {
64 | "Hexadecimal File Signature": "BEBAFECA",
65 | "ISO 8859-1": "BE BA FE CA",
66 | "Filename Extension": "DBA",
67 | "Description": "Palm (PDA)Palm Desktop Calendar Archive",
68 | "Popular": 0
69 | },
70 | {
71 | "Hexadecimal File Signature": "00014244",
72 | "ISO 8859-1": "..BD",
73 | "Filename Extension": "DBA",
74 | "Description": "Palm Desktop To Do Archive",
75 | "Popular": 0
76 | },
77 | {
78 | "Hexadecimal File Signature": "00014454",
79 | "ISO 8859-1": "..DT",
80 | "Filename Extension": "TDA",
81 | "Description": "Palm Desktop Calendar Archive",
82 | "Popular": 0
83 | },
84 | {
85 | "Hexadecimal File Signature": "54444624",
86 | "ISO 8859-1": "TDF$",
87 | "Filename Extension": "TDF$",
88 | "Description": "Telegram Desktop File",
89 | "Popular": 0
90 | },
91 | {
92 | "Hexadecimal File Signature": "54444546",
93 | "ISO 8859-1": "TDEF",
94 | "Filename Extension": "TDEF",
95 | "Description": "Telegram Desktop Encrypted File",
96 | "Popular": 0
97 | },
98 | {
99 | "Hexadecimal File Signature": "00010000",
100 | "ISO 8859-1": "00 01 00 00",
101 | "Filename Extension": null,
102 | "Description": "Palm Desktop Data File (Microsoft AccessAccess format)",
103 | "Popular": 0
104 | },
105 | {
106 | "Hexadecimal File Signature": "00000100",
107 | "ISO 8859-1": null,
108 | "Filename Extension": "ico",
109 | "Description": "Computer icon encoded in ICO (file format)ICO file format[http://msdn.microsoft.com/en-us/library/ms997538.aspx Icons] (at MSDN)",
110 | "Popular": 0
111 | },
112 | {
113 | "Hexadecimal File Signature": "667479703367",
114 | "ISO 8859-1": "ftyp3g",
115 | "Filename Extension": "3gp3g2",
116 | "Description": "3rd Generation Partnership Project 3GPP and 3GPP2 multimedia files",
117 | "Popular": 0
118 | },
119 | {
120 | "Hexadecimal File Signature": "1F9D",
121 | "ISO 8859-1": null,
122 | "Filename Extension": "ztar.z",
123 | "Description": "compressed file (often Tar (file format)tar zip) using Lempel-Ziv-Welch algorithm",
124 | "Popular": 0
125 | },
126 | {
127 | "Hexadecimal File Signature": "1FA0",
128 | "ISO 8859-1": "1F A0",
129 | "Filename Extension": "ztar.z",
130 | "Description": "Compressed file (often tar zip) using LHA (file format)LZH algorithm",
131 | "Popular": 0
132 | },
133 | {
134 | "Hexadecimal File Signature": "4241434B4D494B454449534B",
135 | "ISO 8859-1": "BACKMIKE DISK",
136 | "Filename Extension": "bac",
137 | "Description": "File or Magnetic tape data storagetape containing a backup done with AmiBack on an Amiga. It typically is paired with an index file (idx) with the table of contents.",
138 | "Popular": 0
139 | },
140 | {
141 | "Hexadecimal File Signature": "425A68",
142 | "ISO 8859-1": "BZh",
143 | "Filename Extension": "bz2",
144 | "Description": "Compressed file using Bzip2 algorithm",
145 | "Popular": 0
146 | },
147 | {
148 | "Hexadecimal File Signature": "474946383761474946383961",
149 | "ISO 8859-1": "GIF87a GIF89a",
150 | "Filename Extension": "gif",
151 | "Description": "Image file encoded in the Graphics Interchange Format (GIF)[http://www.w3.org/Graphics/GIF/spec-gif89a.txt GRAPHICS INTERCHANGE FORMAT(sm) Version 89a]",
152 | "Popular": 0
153 | },
154 | {
155 | "Hexadecimal File Signature": "49492A00(Endianness#Little-endianlittle-endianformat)4D4D002A(Endianness#Big-endianbig-endianformat)",
156 | "ISO 8859-1": "II*. MM.*",
157 | "Filename Extension": "tiftiff",
158 | "Description": "Tagged Image File Format (TIFF)",
159 | "Popular": 0
160 | },
161 | {
162 | "Hexadecimal File Signature": "49492A00100000004352",
163 | "ISO 8859-1": "II*..... CR",
164 | "Filename Extension": "cr2",
165 | "URL": "http://filext.com/file-extension/CR2",
166 | "Description": "Canon RAW Format Version 2 weburl",
167 | "Popular": 0
168 | },
169 | {
170 | "Hexadecimal File Signature": "802A5FD7",
171 | "ISO 8859-1": ".*_.",
172 | "Filename Extension": "cin",
173 | "Description": "Eastman KodakKodak Cineon#Cineon file formatCineon image",
174 | "Popular": 0
175 | },
176 | {
177 | "Hexadecimal File Signature": "524E4301524E4302",
178 | "ISO 8859-1": "RNC.",
179 | "Filename Extension": null,
180 | "Description": "Compressed file using [http://segaretro.org/Rob_Northen_compression Rob Northen Compression] (version 1 and 2) algorithm",
181 | "Popular": 0
182 | },
183 | {
184 | "Hexadecimal File Signature": "53445058(Endianness#Big-endianbig-endianformat)58504453(Endianness#Little-endianlittle-endianformat)",
185 | "ISO 8859-1": "SDPX XPDS",
186 | "Filename Extension": "dpx",
187 | "Description": "SMPTE Digital Picture ExchangeDPX image",
188 | "Popular": 0
189 | },
190 | {
191 | "Hexadecimal File Signature": "762F3101",
192 | "ISO 8859-1": "v/1.",
193 | "Filename Extension": "exr",
194 | "Description": "OpenEXROpenEXR image",
195 | "Popular": 0
196 | },
197 | {
198 | "Hexadecimal File Signature": "425047FB",
199 | "ISO 8859-1": "BPG\u00fb",
200 | "Filename Extension": "bpg",
201 | "URL": "http://bellard.org/bpg/ ",
202 | "Description": "Better Portable Graphics format",
203 | "Popular": 0
204 | },
205 | {
206 | "Hexadecimal File Signature": "FFD8FFDBFFD8FFE000104A4649460001FFD8FFEEFFD8FFE1????457869660000",
207 | "ISO 8859-1": "\u00ff\u00d8\u00ff\u00db \u00ff\u00d8\u00ff\u00e0..JFIF.. \u00ff\u00d8\u00ff\u00ee \u00ff\u00d8\u00ff\u00e1..Exif..",
208 | "Filename Extension": "jpgjpeg",
209 | "Description": "JPEG raw or in the JFIF or Exif file format",
210 | "Popular": 0
211 | },
212 | {
213 | "Hexadecimal File Signature": "464F524D????????494C424D",
214 | "ISO 8859-1": "FORM.... ILBM",
215 | "Filename Extension": "ilbmlbmibmiff",
216 | "Description": "Interchange File FormatIFF ILBMInterleaved Bitmap Image",
217 | "Popular": 0
218 | },
219 | {
220 | "Hexadecimal File Signature": "464F524D????????38535658",
221 | "ISO 8859-1": "FORM.... 8SVX",
222 | "Filename Extension": "8svx8svsvxsndiff",
223 | "Description": "Interchange File FormatIFF 8SVX8-Bit Sampled Voice",
224 | "Popular": 0
225 | },
226 | {
227 | "Hexadecimal File Signature": "464F524D????????4143424D",
228 | "ISO 8859-1": "FORM.... ACBM",
229 | "Filename Extension": "acbmiff",
230 | "Description": "Amiga Contiguous Bitmap",
231 | "Popular": 0
232 | },
233 | {
234 | "Hexadecimal File Signature": "464F524D????????414E424D",
235 | "ISO 8859-1": "FORM.... ANBM",
236 | "Filename Extension": "anbmiff",
237 | "Description": "Interchange File FormatIFF IFF Animated BitmapAnimated Bitmap",
238 | "Popular": 0
239 | },
240 | {
241 | "Hexadecimal File Signature": "464F524D????????414E494D",
242 | "ISO 8859-1": "FORM.... ANIM",
243 | "Filename Extension": "animiff",
244 | "Description": "Interchange File FormatIFF IFF CEL AnimationCEL Animation",
245 | "Popular": 0
246 | },
247 | {
248 | "Hexadecimal File Signature": "464F524D????????46415858",
249 | "ISO 8859-1": "FORM.... FAXX",
250 | "Filename Extension": "faxxfaxiff",
251 | "Description": "Interchange File FormatIFF FaxFacsimile Image",
252 | "Popular": 0
253 | },
254 | {
255 | "Hexadecimal File Signature": "464F524D????????46545854",
256 | "ISO 8859-1": "FORM.... FTXT",
257 | "Filename Extension": "ftxtiff",
258 | "Description": "Interchange File FormatIFF Formatted textFormatted Text",
259 | "Popular": 0
260 | },
261 | {
262 | "Hexadecimal File Signature": "464F524D????????534D5553",
263 | "ISO 8859-1": "FORM.... SMUS",
264 | "Filename Extension": "smussmumusiff",
265 | "Description": "Interchange File FormatIFF IFF Simple Musical ScoreSimple Musical Score",
266 | "Popular": 0
267 | },
268 | {
269 | "Hexadecimal File Signature": "464F524D????????434D5553",
270 | "ISO 8859-1": "FORM.... CMUS",
271 | "Filename Extension": "cmusmusiff",
272 | "Description": "Interchange File FormatIFF IFF Musical ScoreMusical Score",
273 | "Popular": 0
274 | },
275 | {
276 | "Hexadecimal File Signature": "464F524D????????5955564E",
277 | "ISO 8859-1": "FORM.... YUVN",
278 | "Filename Extension": "yuvnyuviff",
279 | "Description": "Interchange File FormatIFF YUVYUV Image",
280 | "Popular": 0
281 | },
282 | {
283 | "Hexadecimal File Signature": "464F524D????????46414E54",
284 | "ISO 8859-1": "FORM.... FANT",
285 | "Filename Extension": "iff",
286 | "Description": "Amiga FantavisionFantavision Movie",
287 | "Popular": 0
288 | },
289 | {
290 | "Hexadecimal File Signature": "464F524D????????41494646",
291 | "ISO 8859-1": "FORM.... AIFF",
292 | "Filename Extension": "aiffaifaifcsndiff",
293 | "Description": "Audio Interchange File Format",
294 | "Popular": 0
295 | },
296 | {
297 | "Hexadecimal File Signature": "494E4458",
298 | "ISO 8859-1": "INDX",
299 | "Filename Extension": "idx",
300 | "Description": "Index file to a file or Magnetic tape data storagetape containing a backup done with AmiBack on an Amiga.",
301 | "Popular": 0
302 | },
303 | {
304 | "Hexadecimal File Signature": "4C5A4950",
305 | "ISO 8859-1": "LZIP",
306 | "Filename Extension": "lz",
307 | "Description": "lzip compressed file",
308 | "Popular": 0
309 | },
310 | {
311 | "Hexadecimal File Signature": "4D5A",
312 | "ISO 8859-1": null,
313 | "Filename Extension": "exedll",
314 | "Description": "DOS MZ executable file format and its descendants (including New ExecutableNE and Portable ExecutablePE)",
315 | "Popular": 0
316 | },
317 | {
318 | "Hexadecimal File Signature": "504B0304504B0506(emptyarchive)504B0708(spannedarchive)",
319 | "ISO 8859-1": "PK..",
320 | "Filename Extension": "zipaarapkdocxepub.ipaipajarkmzMozilla Archive Formatmaffodpodsodtpk3pk4pptxusdzvsdxxlsxXPInstallxpi",
321 | "Description": "ZIP (file format)zip file format and formats based on it, such as EPUB, JAR (file format)JAR, OpenDocumentODF, Office Open XMLOOXML",
322 | "Popular": 0
323 | },
324 | {
325 | "Hexadecimal File Signature": "526172211A0700",
326 | "ISO 8859-1": "Rar!...",
327 | "Filename Extension": "rar",
328 | "Description": "RAR (file format)RAR archive version 1.50 onwards web title=TechNote.txt: RAR version 4.00 - Technical information date=2010-12-01 quote=The marker block is actually considered as a fixed byte sequence: 0x52 0x61 0x72 0x21 0x1a 0x07 0x00",
329 | "Popular": 0
330 | },
331 | {
332 | "Hexadecimal File Signature": "526172211A070100",
333 | "ISO 8859-1": "Rar!....",
334 | "Filename Extension": "rar",
335 | "URL": "http://www.rarlab.com/technote.htm ",
336 | "Description": "RAR (file format)RAR archive version 5.0 onwards",
337 | "Popular": 0
338 | },
339 | {
340 | "Hexadecimal File Signature": "5A4D",
341 | "ISO 8859-1": null,
342 | "Filename Extension": "exe",
343 | "Description": "DOS ZM executable file format and its descendants (rare)",
344 | "Popular": 0
345 | },
346 | {
347 | "Hexadecimal File Signature": "7F454C46",
348 | "ISO 8859-1": ".ELF",
349 | "Filename Extension": null,
350 | "Description": "Executable and Linkable Format",
351 | "Popular": 0
352 | },
353 | {
354 | "Hexadecimal File Signature": "89504E470D0A1A0A",
355 | "ISO 8859-1": ".PNG....",
356 | "Filename Extension": "png",
357 | "URL": "http://tools.ietf.org/html/rfc2083",
358 | "Description": "Image encoded in the Portable Network Graphics format weburl",
359 | "Popular": 0
360 | },
361 | {
362 | "Hexadecimal File Signature": "C9",
363 | "ISO 8859-1": null,
364 | "Filename Extension": "com",
365 | "Description": "COM file (CP/M)CP/M 3 and higher with overlays",
366 | "Popular": 0
367 | },
368 | {
369 | "Hexadecimal File Signature": "CAFEBABE",
370 | "ISO 8859-1": "\u00ca\u00fe\u00ba\u00be",
371 | "Filename Extension": "class",
372 | "Description": "Java class file, Fat binary#AppleMach-O Fat Binary",
373 | "Popular": 0
374 | },
375 | {
376 | "Hexadecimal File Signature": "EFBBBF",
377 | "ISO 8859-1": "\u00ef\u00bb\u00bf",
378 | "Filename Extension": null,
379 | "Description": "UTF-8 encoded Unicode byte order mark, commonly seen in text files.",
380 | "Popular": 0
381 | },
382 | {
383 | "Hexadecimal File Signature": "FEEDFACE",
384 | "ISO 8859-1": null,
385 | "Filename Extension": null,
386 | "Description": "Mach-O binary (32-bit)",
387 | "Popular": 0
388 | },
389 | {
390 | "Hexadecimal File Signature": "FEEDFACF",
391 | "ISO 8859-1": null,
392 | "Filename Extension": null,
393 | "Description": "Mach-O binary (64-bit)",
394 | "Popular": 0
395 | },
396 | {
397 | "Hexadecimal File Signature": "FEEDFEED",
398 | "ISO 8859-1": null,
399 | "Filename Extension": null,
400 | "Description": "JKS [http://hg.openjdk.java.net/jdk10/jdk10/jdk/file/777356696811/src/java.base/share/classes/sun/security/provider/JavaKeyStore.java JavakeyStore]",
401 | "Popular": 0
402 | },
403 | {
404 | "Hexadecimal File Signature": "CEFAEDFE",
405 | "ISO 8859-1": null,
406 | "Filename Extension": null,
407 | "URL": "\"apple.com\">{{cite web",
408 | "Description": "Mach-O binary (reverse byte ordering scheme, 32-bit)ref name",
409 | "Popular": 0
410 | },
411 | {
412 | "Hexadecimal File Signature": "CFFAEDFE",
413 | "ISO 8859-1": null,
414 | "Filename Extension": null,
415 | "Description": "Mach-O binary (reverse byte ordering scheme, 64-bit)",
416 | "Popular": 0
417 | },
418 | {
419 | "Hexadecimal File Signature": "FFFE",
420 | "ISO 8859-1": null,
421 | "Filename Extension": null,
422 | "Description": "Byte-order mark for text file encoded in Endianness#Little-endianlittle-endian UTF-1616-bit Unicode Transfer Format",
423 | "Popular": 0
424 | },
425 | {
426 | "Hexadecimal File Signature": "FFFE0000",
427 | "ISO 8859-1": null,
428 | "Filename Extension": null,
429 | "Description": "Byte-order mark for text file encoded in little-endian UTF-3232-bit Unicode Transfer Format",
430 | "Popular": 0
431 | },
432 | {
433 | "Hexadecimal File Signature": "25215053",
434 | "ISO 8859-1": "%!PS",
435 | "Filename Extension": "ps",
436 | "Description": "PostScriptPostScript document",
437 | "Popular": 0
438 | },
439 | {
440 | "Hexadecimal File Signature": "495453460300000060000000",
441 | "ISO 8859-1": "ITSF....`...",
442 | "Filename Extension": "chm",
443 | "Description": "Microsoft_Compiled_HTML_HelpMS Windows HtmlHelp Data",
444 | "Popular": 0
445 | },
446 | {
447 | "Hexadecimal File Signature": "255044462d",
448 | "ISO 8859-1": "%PDF-",
449 | "Filename Extension": "pdf",
450 | "URL": "https://github.com/file/file/blob/master/magic/Magdir/pdf",
451 | "Description": "Portable Document FormatPDF document",
452 | "Popular": 0
453 | },
454 | {
455 | "Hexadecimal File Signature": "3026B2758E66CF11A6D900AA0062CE6C",
456 | "ISO 8859-1": "0&\u00b2u.f\u00cf .\u00a6\u00d9.\u00aa.b\u00cel",
457 | "Filename Extension": "asfwmawmv",
458 | "URL": "http://www.digitalpreservation.gov/formats/fdd/fdd000067.shtml ",
459 | "Description": "Advanced Systems Format",
460 | "Popular": 0
461 | },
462 | {
463 | "Hexadecimal File Signature": "2453444930303031",
464 | "ISO 8859-1": "$SDI0001",
465 | "Filename Extension": null,
466 | "Description": "System Deployment Image, a disk image format used by Microsoft",
467 | "Popular": 0
468 | },
469 | {
470 | "Hexadecimal File Signature": "4F676753",
471 | "ISO 8859-1": "OggS",
472 | "Filename Extension": "oggogaogv",
473 | "Description": "Ogg, an Open-source licenseopen source media container format",
474 | "Popular": 0
475 | },
476 | {
477 | "Hexadecimal File Signature": "38425053",
478 | "ISO 8859-1": "8BPS",
479 | "Filename Extension": "psd",
480 | "Description": "Photoshop Document file, Adobe Photoshop's native file format",
481 | "Popular": 0
482 | },
483 | {
484 | "Hexadecimal File Signature": "52494646????????57415645",
485 | "ISO 8859-1": "RIFF.... WAVE",
486 | "Filename Extension": "wav",
487 | "Description": "Waveform Audio File Format",
488 | "Popular": 0
489 | },
490 | {
491 | "Hexadecimal File Signature": "52494646????????41564920",
492 | "ISO 8859-1": "RIFF.... AVI.",
493 | "Filename Extension": "avi",
494 | "Description": "Audio Video Interleave video format",
495 | "Popular": 0
496 | },
497 | {
498 | "Hexadecimal File Signature": "FFFBFFF3FFF2",
499 | "ISO 8859-1": "\u00ff\u00fb \u00ff\u00f3 \u00ff\u00f2",
500 | "Filename Extension": "mp3",
501 | "Description": "MPEG-1 Layer 3 file without an ID3 tag or with an ID3v1 tag (which's appended at the end of the file)",
502 | "Popular": 0
503 | },
504 | {
505 | "Hexadecimal File Signature": "494433",
506 | "ISO 8859-1": "ID3",
507 | "Filename Extension": "mp3",
508 | "Description": "MP3 file with an ID3v2 container",
509 | "Popular": 0
510 | },
511 | {
512 | "Hexadecimal File Signature": "424D",
513 | "ISO 8859-1": null,
514 | "Filename Extension": "bmpdib",
515 | "Description": "BMP file formatBMP file, a bitmap format used mostly in the Windows world",
516 | "Popular": 0
517 | },
518 | {
519 | "Hexadecimal File Signature": "4344303031",
520 | "ISO 8859-1": "CD001",
521 | "Filename Extension": "iso",
522 | "URL": "http://www.garykessler.net/library/file_sigs.html",
523 | "Description": "ISO9660 CD/DVD image file weburl",
524 | "Popular": 0
525 | },
526 | {
527 | "Hexadecimal File Signature": "53494D504C4520203D202020202020202020202020202020202020202054",
528 | "ISO 8859-1": "SIMPLE = T",
529 | "Filename Extension": "fits",
530 | "URL": "http://www.digitalpreservation.gov/formats/fdd/fdd000317.shtml#sign",
531 | "Description": "Flexible Image Transport System (FITS) weburl",
532 | "Popular": 0
533 | },
534 | {
535 | "Hexadecimal File Signature": "664C6143",
536 | "ISO 8859-1": "fLaC",
537 | "Filename Extension": "flac",
538 | "URL": "http://flac.sourceforge.net/format.html#stream ",
539 | "Description": "Free Lossless Audio Codec weburl",
540 | "Popular": 0
541 | },
542 | {
543 | "Hexadecimal File Signature": "4D546864",
544 | "ISO 8859-1": "MThd",
545 | "Filename Extension": "midmidi",
546 | "URL": "http://filesignatures.net/index.php?search",
547 | "Description": "MIDI#Standard MIDI filesMIDI sound file weburl",
548 | "Popular": 0
549 | },
550 | {
551 | "Hexadecimal File Signature": "D0CF11E0A1B11AE1",
552 | "ISO 8859-1": null,
553 | "Filename Extension": "docxlspptmsg",
554 | "URL": "http://social.msdn.microsoft.com/Forums/en-US/343d09e3-5fdf-4b4a-9fa6-8ccb37a35930/developing-a-tool-to-recognise-ms-office-file-types-doc-xls-mdb-ppt-?forum",
555 | "Description": "Compound File Binary Format, a container format used for document by older versions of Microsoft Office. weburl",
556 | "Popular": 0
557 | },
558 | {
559 | "Hexadecimal File Signature": "6465780A30333500",
560 | "ISO 8859-1": "dex.035.",
561 | "Filename Extension": "dex",
562 | "Description": "Dalvik (software)Dalvik Executable",
563 | "Popular": 0
564 | },
565 | {
566 | "Hexadecimal File Signature": "4B444D",
567 | "ISO 8859-1": "KDM",
568 | "Filename Extension": "vmdk",
569 | "URL": "https://www.vmware.com/support/ws55/doc/ws_learning_files_in_a_vm.html",
570 | "Description": "VMDK files weburl",
571 | "Popular": 0
572 | },
573 | {
574 | "Hexadecimal File Signature": "43723234",
575 | "ISO 8859-1": "Cr24",
576 | "Filename Extension": "crx",
577 | "URL": "http://developer.chrome.com/extensions/crx.html",
578 | "Description": "Google Chrome extension weburl",
579 | "Popular": 0
580 | },
581 | {
582 | "Hexadecimal File Signature": "41474433",
583 | "ISO 8859-1": "AGD3",
584 | "Filename Extension": "fh8",
585 | "URL": "https://mail.python.org/pipermail/pythonmac-sig/2005-February/013028.html",
586 | "Description": "Adobe FreeHandFreeHand 8 document weburl",
587 | "Popular": 0
588 | },
589 | {
590 | "Hexadecimal File Signature": "05070000424F424F0507000000000000000000000001",
591 | "ISO 8859-1": "....BOBO ........ ....",
592 | "Filename Extension": "cwk",
593 | "Description": "AppleWorks 5 document",
594 | "Popular": 0
595 | },
596 | {
597 | "Hexadecimal File Signature": "0607E100424F424F0607E10000000000000000000001",
598 | "ISO 8859-1": "....BOBO ........ ....",
599 | "Filename Extension": "cwk",
600 | "Description": "AppleWorks 6 document",
601 | "Popular": 0
602 | },
603 | {
604 | "Hexadecimal File Signature": "4552020000008B455202000000",
605 | "ISO 8859-1": "ER.... \u00e3ER....",
606 | "Filename Extension": "toast",
607 | "Description": "Roxio Roxio ToastToast disc image file, also some .dmg-files begin with same bytes",
608 | "Popular": 0
609 | },
610 | {
611 | "Hexadecimal File Signature": "7801730D626260",
612 | "ISO 8859-1": "x.s.bb`",
613 | "Filename Extension": "dmg",
614 | "Description": "Apple Disk Image file",
615 | "Popular": 0
616 | },
617 | {
618 | "Hexadecimal File Signature": "78617221",
619 | "ISO 8859-1": "xar!",
620 | "Filename Extension": "xar",
621 | "URL": "https://code.google.com/p/xar/wiki/xarformat",
622 | "Description": "Xar (archiver)eXtensible ARchive format weburl",
623 | "Popular": 0
624 | },
625 | {
626 | "Hexadecimal File Signature": "504D4F43434D4F43",
627 | "ISO 8859-1": "PMOCCMOC",
628 | "Filename Extension": "dat",
629 | "URL": "http://www.howtogeek.com/79820/easily-restore-your-computer-with-file-and-settings-transfer-wizard-xp-part-1/",
630 | "Description": "Windows Files And Settings Transfer Repository weburl",
631 | "Popular": 0
632 | },
633 | {
634 | "Hexadecimal File Signature": "4E45531A",
635 | "ISO 8859-1": "NES",
636 | "Filename Extension": "nes",
637 | "URL": "http://sadistech.com/nesromtool/romdoc.html",
638 | "Description": "Nintendo Entertainment System ROM file weburl",
639 | "Popular": 0
640 | },
641 | {
642 | "Hexadecimal File Signature": "75737461720030307573746172202000",
643 | "ISO 8859-1": "ustar.00 ustar .",
644 | "Filename Extension": "tar",
645 | "URL": "https://www.gnu.org/software/tar/manual/html_node/Standard.html",
646 | "Description": "tar (computing)tar archive weburl",
647 | "Popular": 0
648 | },
649 | {
650 | "Hexadecimal File Signature": "4F4152??",
651 | "ISO 8859-1": "OAR.",
652 | "Filename Extension": "oar",
653 | "Description": "OAR file archive format, where ?? is the format version.",
654 | "Popular": 0
655 | },
656 | {
657 | "Hexadecimal File Signature": "746F7833",
658 | "ISO 8859-1": "TOX",
659 | "Filename Extension": "tox",
660 | "URL": "http://tox.land/uvox/man.html",
661 | "Description": "Open source portable voxel file weburl",
662 | "Popular": 0
663 | },
664 | {
665 | "Hexadecimal File Signature": "4D4C5649",
666 | "ISO 8859-1": "MLVI",
667 | "Filename Extension": "MLV",
668 | "URL": "https://docs.google.com/spreadsheet/ccc?key",
669 | "Description": "Magic Lantern (firmware)Magic Lantern Video file weburl",
670 | "Popular": 0
671 | },
672 | {
673 | "Hexadecimal File Signature": "44434D0150413330",
674 | "ISO 8859-1": "DCM PA30",
675 | "Filename Extension": null,
676 | "URL": "1562 Binary Delta Compression][{{Cite web",
677 | "Description": "Windows Update [http://www.microsoft.com/en-us/download/details.aspx?id",
678 | "Popular": 0
679 | },
680 | {
681 | "Hexadecimal File Signature": "377ABCAF271C",
682 | "ISO 8859-1": "7z\u00bc\u00af'",
683 | "Filename Extension": "7z",
684 | "Description": "7-Zip File Format",
685 | "Popular": 0
686 | },
687 | {
688 | "Hexadecimal File Signature": "1F8B",
689 | "ISO 8859-1": null,
690 | "Filename Extension": "gztar.gz",
691 | "URL": "https://tools.ietf.org/html/rfc1952#page-6",
692 | "Description": "GZIP compressed fileCite weburl",
693 | "Popular": 0
694 | },
695 | {
696 | "Hexadecimal File Signature": "FD377A585A00",
697 | "ISO 8859-1": "\u00b27zXZ..",
698 | "Filename Extension": "xztar.xz",
699 | "Description": "XZ UtilsXZ compression utility using Lempel\u2013Ziv\u2013Markov chain algorithmLZMA2 compression",
700 | "Popular": 0
701 | },
702 | {
703 | "Hexadecimal File Signature": "04224D18",
704 | "ISO 8859-1": ".\"M.",
705 | "Filename Extension": "lz4",
706 | "URL": "https://github.com/lz4/lz4/blob/dev/doc/lz4_Frame_format.md",
707 | "Description": "LZ4 (compression algorithm)LZ4 Frame Format weburl",
708 | "Popular": 0
709 | },
710 | {
711 | "Hexadecimal File Signature": "4D534346",
712 | "ISO 8859-1": "MSCF",
713 | "Filename Extension": "cab",
714 | "Description": "Microsoft Cabinet file",
715 | "Popular": 0
716 | },
717 | {
718 | "Hexadecimal File Signature": "535A444488F02733",
719 | "ISO 8859-1": "SZDD....",
720 | "Filename Extension": "Various. (Replacing the last character of the original filename extension with an underscore, e.g. setup.exe becomes setup.ex_)",
721 | "Description": "Microsoft compressed file in Quantum compressionQuantum format, used prior to Windows XP. File can be decompressed using Extract.exe or Expand.exe distributed with earlier versions of Windows.",
722 | "Popular": 0
723 | },
724 | {
725 | "Hexadecimal File Signature": "464C4946",
726 | "ISO 8859-1": "FLIF",
727 | "Filename Extension": "flif",
728 | "Description": "Free Lossless Image Format",
729 | "Popular": 0
730 | },
731 | {
732 | "Hexadecimal File Signature": "1A45DFA3",
733 | "ISO 8859-1": ".E\u00df\u00a3",
734 | "Filename Extension": "mkvmkamksmk3dwebm",
735 | "Description": "Matroska media container, including WebM",
736 | "Popular": 0
737 | },
738 | {
739 | "Hexadecimal File Signature": "4D494C20",
740 | "ISO 8859-1": "MIL",
741 | "Filename Extension": "stg",
742 | "Description": "\"SEAN : Session Analysis\" Training file. Also used in compatible software \"Rpw : Rowperfect for Windows\" and \"RP3W : ROWPERFECT3 for Windows\".",
743 | "Popular": 0
744 | },
745 | {
746 | "Hexadecimal File Signature": "41542654464F524D????????444A56",
747 | "ISO 8859-1": "AT&TFORM....DJV",
748 | "Filename Extension": "djvudjv",
749 | "Description": "DjVu documentThe following byte is either 55 (U) for single-page or 4D (M) for multi-page documents.",
750 | "Popular": 0
751 | },
752 | {
753 | "Hexadecimal File Signature": "3082",
754 | "ISO 8859-1": null,
755 | "Filename Extension": "der",
756 | "Description": "DER encoded X.509 certificate",
757 | "Popular": 0
758 | },
759 | {
760 | "Hexadecimal File Signature": "4449434D",
761 | "ISO 8859-1": "DICM",
762 | "Filename Extension": "dcm",
763 | "Description": "DICOMDICOM Medical File Format",
764 | "Popular": 0
765 | },
766 | {
767 | "Hexadecimal File Signature": "774F4646",
768 | "ISO 8859-1": "wOFF",
769 | "Filename Extension": "woff",
770 | "Description": "[https://www.w3.org/TR/2012/REC-WOFF-20121213/ WOFF File Format 1.0]",
771 | "Popular": 0
772 | },
773 | {
774 | "Hexadecimal File Signature": "774F4632",
775 | "ISO 8859-1": "wOF2",
776 | "Filename Extension": "woff2",
777 | "Description": "[https://www.w3.org/TR/WOFF2/ WOFF File Format 2.0]",
778 | "Popular": 0
779 | },
780 | {
781 | "Hexadecimal File Signature": "3c3f786d6c20",
782 | "ISO 8859-1": "?xml",
783 | "Filename Extension": "XML",
784 | "Description": "XMLeXtensible Markup Language when using the ASCII character encoding",
785 | "Popular": 0
786 | },
787 | {
788 | "Hexadecimal File Signature": "0061736d",
789 | "ISO 8859-1": ".asm",
790 | "Filename Extension": "wasm",
791 | "URL": "https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md#high-level-structure",
792 | "Description": "WebAssembly binary formatCite weburl",
793 | "Popular": 0
794 | },
795 | {
796 | "Hexadecimal File Signature": "cf8401",
797 | "ISO 8859-1": null,
798 | "Filename Extension": "lep",
799 | "URL": "https://blogs.dropbox.com/tech/2016/07/lepton-image-compression-saving-22-losslessly-from-images-at-15mbs/",
800 | "Description": "Lepton image compression formatLepton compressed JPEG imageCite weburl",
801 | "Popular": 0
802 | },
803 | {
804 | "Hexadecimal File Signature": "435753465753",
805 | "ISO 8859-1": "CWS FWS",
806 | "Filename Extension": "swf",
807 | "Description": "flash .swf",
808 | "Popular": 0
809 | },
810 | {
811 | "Hexadecimal File Signature": "213C617263683E",
812 | "ISO 8859-1": null,
813 | "Filename Extension": "deb",
814 | "Description": "linux deb file",
815 | "Popular": 0
816 | },
817 | {
818 | "Hexadecimal File Signature": "52494646????????57454250",
819 | "ISO 8859-1": "RIFF.... WEBP",
820 | "Filename Extension": "webp",
821 | "Description": "Google WebP image file, where ?? ?? ?? ?? is the file size. More information on [https://developers.google.com/speed/webp/docs/riff_container#webp_file_header WebP File Header]",
822 | "Popular": 0
823 | },
824 | {
825 | "Hexadecimal File Signature": "27051956",
826 | "ISO 8859-1": "'..V",
827 | "Filename Extension": null,
828 | "URL": "http://buffalo.nas-central.org/wiki/How_to_Extract_an_uImage",
829 | "Description": "U-Boot / uImage. Das U-Boot Universal Boot Loader.Cite weburl",
830 | "Popular": 0
831 | },
832 | {
833 | "Hexadecimal File Signature": "7B5C72746631",
834 | "ISO 8859-1": "\\rtf1",
835 | "Filename Extension": "rtf",
836 | "Description": "Rich Text Format",
837 | "Popular": 0
838 | },
839 | {
840 | "Hexadecimal File Signature": "54415045",
841 | "ISO 8859-1": "TAPE",
842 | "Filename Extension": null,
843 | "Description": "Microsoft Tape Format",
844 | "Popular": 0
845 | },
846 | {
847 | "Hexadecimal File Signature": "47",
848 | "ISO 8859-1": null,
849 | "Filename Extension": "ts tsv tsa",
850 | "Description": "MPEG Transport Stream (MPEG-2 Part 1)",
851 | "Popular": 0
852 | },
853 | {
854 | "Hexadecimal File Signature": "000001BA",
855 | "ISO 8859-1": null,
856 | "Filename Extension": "m2p vob",
857 | "Description": "MPEG Program Stream (MPEG-1 Part 1 (essentially identical) and MPEG-2 Part 1)",
858 | "Popular": 0
859 | },
860 | {
861 | "Hexadecimal File Signature": "000001BA47000001B3",
862 | "ISO 8859-1": null,
863 | "Filename Extension": "mpg mpeg",
864 | "Description": "MPEG Program Stream MPEG Transport Stream MPEG-1 video and MPEG-2 video (MPEG-1 Part 2 and MPEG-2 Part 2)",
865 | "Popular": 0
866 | },
867 | {
868 | "Hexadecimal File Signature": "000000186674797069736F6D",
869 | "ISO 8859-1": "ftypisom",
870 | "Filename Extension": "mp4",
871 | "Description": "ISO Base Media file (MPEG-4)",
872 | "Popular": 0
873 | },
874 | {
875 | "Hexadecimal File Signature": "7801785E789C78DA7820787D78BB78F9",
876 | "ISO 8859-1": null,
877 | "Filename Extension": "zlib",
878 | "Description": "No Compression (no preset dictionary) Best speed (no preset dictionary) Default Compression (no preset dictionary) Best Compression (no preset dictionary) No Compression (with preset dictionary) Best speed (with preset dictionary) Default Compression (with preset dictionary) Best Compression (with preset dictionary)",
879 | "Popular": 0
880 | },
881 | {
882 | "Hexadecimal File Signature": "62767832",
883 | "ISO 8859-1": "bvx2",
884 | "Filename Extension": "lzfse",
885 | "URL": "https://github.com/lzfse/lzfse",
886 | "Description": "LZFSE - Lempel-Ziv style data compression algorithm using Finite State Entropy coding. OSS by Apple.Cite weburl",
887 | "Popular": 0
888 | },
889 | {
890 | "Hexadecimal File Signature": "4F5243",
891 | "ISO 8859-1": "ORC",
892 | "Filename Extension": "orc",
893 | "Description": "Apache ORC (Optimized Row Columnar) file format",
894 | "Popular": 0
895 | },
896 | {
897 | "Hexadecimal File Signature": "4F626A01",
898 | "ISO 8859-1": "Obj.",
899 | "Filename Extension": "avro",
900 | "Description": "Apache Avro binary file format",
901 | "Popular": 0
902 | },
903 | {
904 | "Hexadecimal File Signature": "53455136",
905 | "ISO 8859-1": "SEQ6",
906 | "Filename Extension": "rc",
907 | "Description": "RCFile columnar file format",
908 | "Popular": 0
909 | },
910 | {
911 | "Hexadecimal File Signature": "65877856",
912 | "ISO 8859-1": "e.xV",
913 | "Filename Extension": "p25 obt",
914 | "Description": "PhotoCap Object Templates",
915 | "Popular": 0
916 | },
917 | {
918 | "Hexadecimal File Signature": "5555aaaa",
919 | "ISO 8859-1": null,
920 | "Filename Extension": "pcv",
921 | "Description": "PhotoCap Vector",
922 | "Popular": 0
923 | },
924 | {
925 | "Hexadecimal File Signature": "785634",
926 | "ISO 8859-1": "xV4",
927 | "Filename Extension": "pbt pdt pea peb pet pgt pict pjt pkt pmt",
928 | "Description": "PhotoCap Template",
929 | "Popular": 0
930 | },
931 | {
932 | "Hexadecimal File Signature": "50415231",
933 | "ISO 8859-1": "PAR1",
934 | "Filename Extension": null,
935 | "Description": "Apache Parquet columnar file format",
936 | "Popular": 0
937 | },
938 | {
939 | "Hexadecimal File Signature": "454D5832",
940 | "ISO 8859-1": "EMX2",
941 | "Filename Extension": "ez2",
942 | "Description": "E-mu_EmaxEmulator Emaxsynth samples",
943 | "Popular": 0
944 | },
945 | {
946 | "Hexadecimal File Signature": "454D5533",
947 | "ISO 8859-1": "EMU3",
948 | "Filename Extension": "ez3 iso",
949 | "Description": "E-mu_Emulator#The_Emulator_IIIEmulator III synth samples",
950 | "Popular": 0
951 | },
952 | {
953 | "Hexadecimal File Signature": "1B4C7561",
954 | "ISO 8859-1": ".Lua",
955 | "Filename Extension": "luac",
956 | "URL": "Lua 5.2 Bytecode and Virtual Machine ",
957 | "Description": "Lua (programming language)Lua bytecode web title",
958 | "Popular": 0
959 | },
960 | {
961 | "Hexadecimal File Signature": "626F6F6B000000006D61726B00000000",
962 | "ISO 8859-1": "62 6F 6F 6B 00 00 00 00 6D 61 72 6B 00 00 00 00",
963 | "Filename Extension": "alias",
964 | "URL": "https://www.forensicswiki.org/wiki/Mac_OS_X#Burn_Folder",
965 | "Description": "macOS file AliasCite weburl",
966 | "Popular": 0
967 | },
968 | {
969 | "Hexadecimal File Signature": "5B5A6F6E655472616E736665725D",
970 | "ISO 8859-1": "[ZoneTransfer]",
971 | "Filename Extension": "Identifier",
972 | "URL": "vs.60) URL Security Zones]][{{Cite web",
973 | "Description": "Microsoft Zone Identifier for [https://technet.microsoft.com/en-us/windows/ms537183(v",
974 | "Popular": 0
975 | },
976 | {
977 | "Hexadecimal File Signature": "5265636569766564",
978 | "ISO 8859-1": "Received:",
979 | "Filename Extension": "eml",
980 | "URL": "http://file-extension.net/seeker/program_extension_message",
981 | "Description": "Email Message var5Cite weburl",
982 | "Popular": 0
983 | },
984 | {
985 | "Hexadecimal File Signature": "20020162A01EAB0702000000",
986 | "ISO 8859-1": "20 02 01 62 A0 1E AB 07 02 00 00 00",
987 | "Filename Extension": "tde",
988 | "Description": "Tableau Datasource",
989 | "Popular": 0
990 | },
991 | {
992 | "Hexadecimal File Signature": "3748030200000000583530394B4559",
993 | "ISO 8859-1": "37 48 03 02 00 00 00 00 58 35 30 39 4B 45 59",
994 | "Filename Extension": "kdb",
995 | "Description": "KDB file",
996 | "Popular": 0
997 | },
998 | {
999 | "Hexadecimal File Signature": "85????03",
1000 | "ISO 8859-1": "85 ?? ?? 03",
1001 | "Filename Extension": "pgp",
1002 | "URL": "https://security.stackexchange.com/a/144555/12109",
1003 | "Description": "PGP file Cite weburl",
1004 | "Popular": 0
1005 | },
1006 | {
1007 | "Hexadecimal File Signature": "28B52FFD",
1008 | "ISO 8859-1": "28 B5 2F FD",
1009 | "Filename Extension": "zst",
1010 | "URL": "https://tools.ietf.org/html/rfc8478#section-3.1.1",
1011 | "Description": "Zstandard compressed fileCite weburl",
1012 | "Popular": 0
1013 | },
1014 | {
1015 | "Hexadecimal File Signature": "5253564B44415441",
1016 | "ISO 8859-1": "52 53 56 4B 44 41 54 41",
1017 | "Filename Extension": "rs",
1018 | "URL": "https://filext.com/file-extension/RS",
1019 | "Description": "QuickZip rs compressed archiveCite weburl",
1020 | "Popular": 0
1021 | },
1022 | {
1023 | "Hexadecimal File Signature": "3A290A",
1024 | "ISO 8859-1": "3A 29 0A",
1025 | "Filename Extension": "sml",
1026 | "Description": "Smile (data interchange format)Smile file",
1027 | "Popular": 0
1028 | },
1029 | {
1030 | "Hexadecimal File Signature": "4A6F7921",
1031 | "ISO 8859-1": "4A 6F 79 21",
1032 | "Filename Extension": null,
1033 | "Description": "Preferred Executable Format",
1034 | "Popular": 0
1035 | },
1036 | {
1037 | "Hexadecimal File Signature": "310A3030",
1038 | "ISO 8859-1": "31 0A 30 30",
1039 | "Filename Extension": "srt",
1040 | "Description": "SubRip File",
1041 | "Popular": 0
1042 | },
1043 | {
1044 | "Hexadecimal File Signature": "3412AA55",
1045 | "ISO 8859-1": "34 12 AA 55",
1046 | "Filename Extension": "vpk",
1047 | "Description": "VPK file, used to store game data for some Source Engine games",
1048 | "Popular": 0
1049 | },
1050 | {
1051 | "Hexadecimal File Signature": "58464952",
1052 | "ISO 8859-1": "58 46 49 52",
1053 | "Filename Extension": "dcr",
1054 | "Description": "Adobe Shockwave",
1055 | "Popular": 0
1056 | },
1057 | {
1058 | "Hexadecimal File Signature": "2A2A4143452A3A",
1059 | "ISO 8859-1": "2A 2A 41 43 45 2A 2A",
1060 | "Filename Extension": "ace",
1061 | "Description": "ACE (compressed file format)",
1062 | "Popular": 0
1063 | },
1064 | {
1065 | "Hexadecimal File Signature": "60EA",
1066 | "ISO 8859-1": "60 RA",
1067 | "Filename Extension": "arj",
1068 | "Description": "ARJ",
1069 | "Popular": 0
1070 | },
1071 | {
1072 | "Hexadecimal File Signature": "49536328",
1073 | "ISO 8859-1": "49 53 63 28",
1074 | "Filename Extension": "cab",
1075 | "Description": "InstallShield CAB Archive File",
1076 | "Popular": 0
1077 | },
1078 | {
1079 | "Hexadecimal File Signature": "4B57414A",
1080 | "ISO 8859-1": "4B 57 41 4A",
1081 | "Filename Extension": "??_",
1082 | "Description": "Windows 3.1x Compressed File",
1083 | "Popular": 0
1084 | },
1085 | {
1086 | "Hexadecimal File Signature": "535A4444",
1087 | "ISO 8859-1": "53 5A 44 44",
1088 | "Filename Extension": "??_",
1089 | "Description": "Windows 9x Compressed File",
1090 | "Popular": 0
1091 | },
1092 | {
1093 | "Hexadecimal File Signature": "5A4F4F",
1094 | "ISO 8859-1": "5A 4F 4F",
1095 | "Filename Extension": "zoo",
1096 | "Description": "Zoo (file format)",
1097 | "Popular": 0
1098 | },
1099 | {
1100 | "Hexadecimal File Signature": "50310A",
1101 | "ISO 8859-1": "50 31 0A",
1102 | "Filename Extension": "pbm",
1103 | "Description": "Portable bitmap",
1104 | "Popular": 0
1105 | },
1106 | {
1107 | "Hexadecimal File Signature": "50320A",
1108 | "ISO 8859-1": "50 32 0A",
1109 | "Filename Extension": "pgm",
1110 | "Description": "Portable Gray Map",
1111 | "Popular": 0
1112 | },
1113 | {
1114 | "Hexadecimal File Signature": "50330A",
1115 | "ISO 8859-1": "50 33 0A",
1116 | "Filename Extension": "ppm",
1117 | "Description": "Portable Pixmap",
1118 | "Popular": 0
1119 | },
1120 | {
1121 | "Hexadecimal File Signature": "D7CDC69A",
1122 | "ISO 8859-1": "D7 CD C6 9A",
1123 | "Filename Extension": "wmf",
1124 | "Description": "Windows Metafile",
1125 | "Popular": 0
1126 | },
1127 | {
1128 | "Hexadecimal File Signature": "67696D7020786366",
1129 | "ISO 8859-1": "67 69 6D 70 20 78 63 66",
1130 | "Filename Extension": "xcf",
1131 | "Description": "XCF (file format)",
1132 | "Popular": 0
1133 | },
1134 | {
1135 | "Hexadecimal File Signature": "2F2A2058504D202A2F",
1136 | "ISO 8859-1": "2F 2A 20 58 50 4D 20 2A 2F",
1137 | "Filename Extension": "xpm",
1138 | "Description": "X PixMap",
1139 | "Popular": 0
1140 | },
1141 | {
1142 | "Hexadecimal File Signature": "414646",
1143 | "ISO 8859-1": "41 46 46",
1144 | "Filename Extension": "aff",
1145 | "Description": "Advanced Forensics Format",
1146 | "Popular": 0
1147 | },
1148 | {
1149 | "Hexadecimal File Signature": "45564632",
1150 | "ISO 8859-1": "45 56 46 32",
1151 | "Filename Extension": "Ex01",
1152 | "Description": "EnCase EWF version 2 format",
1153 | "Popular": 0
1154 | },
1155 | {
1156 | "Hexadecimal File Signature": "455646",
1157 | "ISO 8859-1": "45 56 46",
1158 | "Filename Extension": "e01",
1159 | "Description": "EnCase EWF version 1 format",
1160 | "Popular": 0
1161 | },
1162 | {
1163 | "Hexadecimal File Signature": "514649",
1164 | "ISO 8859-1": "51 46 49",
1165 | "Filename Extension": "qcow",
1166 | "Description": "qcow file format",
1167 | "Popular": 0
1168 | },
1169 | {
1170 | "Hexadecimal File Signature": "52494646????????41434F4E",
1171 | "ISO 8859-1": "RIFF.... ACON",
1172 | "Filename Extension": "ani",
1173 | "Description": "Animated cursor",
1174 | "Popular": 0
1175 | },
1176 | {
1177 | "Hexadecimal File Signature": "52494646????????43444441",
1178 | "ISO 8859-1": "RIFF.... CDDA",
1179 | "Filename Extension": "cda",
1180 | "Description": "Compact Disc Digital Audio",
1181 | "Popular": 0
1182 | },
1183 | {
1184 | "Hexadecimal File Signature": "52494646????????514C434D",
1185 | "ISO 8859-1": "RIFF.... QLCM",
1186 | "Filename Extension": "qcp",
1187 | "Description": "Qualcomm PureVoice file format",
1188 | "Popular": 0
1189 | },
1190 | {
1191 | "Hexadecimal File Signature": "58464952????????3339564D",
1192 | "ISO 8859-1": "XFIR.... 39VM",
1193 | "Filename Extension": "dir",
1194 | "Description": "Macromedia Director file format",
1195 | "Popular": 0
1196 | },
1197 | {
1198 | "Hexadecimal File Signature": "464C56",
1199 | "ISO 8859-1": "46 4C 56",
1200 | "Filename Extension": "flv",
1201 | "Description": "Flash Video file",
1202 | "Popular": 0
1203 | },
1204 | {
1205 | "Hexadecimal File Signature": "3C3C3C204F7261636C6520564D205669727475616C426F78204469736B20496D616765203E3E3E",
1206 | "ISO 8859-1": "3C 3C 3C 20 4F 72 61 63 6C 65 20 56 4D 20 56 69 72 74 75 61 6C 42 6F 78 20 44 69 73 6B 20 49 6D 61 67 65 20 3E 3E 3E",
1207 | "Filename Extension": "vdi",
1208 | "Description": "VirtualBox Virtual Hard Disk file format",
1209 | "Popular": 0
1210 | },
1211 | {
1212 | "Hexadecimal File Signature": "636F6E6E6563746978",
1213 | "ISO 8859-1": "63 6F 6E 6E 65 63 74 69 78",
1214 | "Filename Extension": "vhd",
1215 | "Description": "Windows Virtual PC Virtual Hard Disk file format",
1216 | "Popular": 0
1217 | },
1218 | {
1219 | "Hexadecimal File Signature": "7668647866696C65",
1220 | "ISO 8859-1": "76 68 64 78 66 69 6C 65",
1221 | "Filename Extension": "vhdx",
1222 | "Description": "Windows Virtual PC Windows 8 Virtual Hard Disk file format",
1223 | "Popular": 0
1224 | },
1225 | {
1226 | "Hexadecimal File Signature": "49735A21",
1227 | "ISO 8859-1": "49 73 5A 21",
1228 | "Filename Extension": "isz",
1229 | "Description": "Compressed ISO image",
1230 | "Popular": 0
1231 | },
1232 | {
1233 | "Hexadecimal File Signature": "444141",
1234 | "ISO 8859-1": "44 41 41",
1235 | "Filename Extension": "daa",
1236 | "Description": "Direct Access Archive PowerISO",
1237 | "Popular": 0
1238 | },
1239 | {
1240 | "Hexadecimal File Signature": "4C664C65",
1241 | "ISO 8859-1": "4C 66 4C 65",
1242 | "Filename Extension": "evt",
1243 | "Description": "Windows Event Viewer file format",
1244 | "Popular": 0
1245 | },
1246 | {
1247 | "Hexadecimal File Signature": "504D4343",
1248 | "ISO 8859-1": "50 4D 43 43",
1249 | "Filename Extension": "grp",
1250 | "Description": "Windows 3.x Program Manager Program Group file format",
1251 | "Popular": 0
1252 | },
1253 | {
1254 | "Hexadecimal File Signature": "4B434D53",
1255 | "ISO 8859-1": "4B 43 4D 53",
1256 | "Filename Extension": "icm",
1257 | "Description": "ICC profile",
1258 | "Popular": 0
1259 | },
1260 | {
1261 | "Hexadecimal File Signature": "72656766",
1262 | "ISO 8859-1": "72 65 67 66",
1263 | "Filename Extension": "dat",
1264 | "Description": "Windows Registry file",
1265 | "Popular": 0
1266 | },
1267 | {
1268 | "Hexadecimal File Signature": "2142444E",
1269 | "ISO 8859-1": "21 42 44 4E",
1270 | "Filename Extension": "pst",
1271 | "Description": "Microsoft Outlook Personal Storage Table file",
1272 | "Popular": 0
1273 | },
1274 | {
1275 | "Hexadecimal File Signature": "445241434F",
1276 | "ISO 8859-1": "44 52 41 43 4F",
1277 | "Filename Extension": "drc",
1278 | "URL": "",
1279 | "Description": "3D model compressed with Google DracoCite weblast",
1280 | "Popular": 0
1281 | },
1282 | {
1283 | "Hexadecimal File Signature": "47524942",
1284 | "ISO 8859-1": "47 52 49 42",
1285 | "Filename Extension": "grib grib2",
1286 | "Description": "Gridded data (commonly weather observations or forecasts) in the World Meteorological OrganizationWMO GRIB or GRIB2 formathttps://www.wmo.int/pages/prog/www/WDM/Guides/Guide-binary-2.html",
1287 | "Popular": 0
1288 | },
1289 | {
1290 | "Hexadecimal File Signature": "424C454E444552",
1291 | "ISO 8859-1": "BLENDER",
1292 | "Filename Extension": "blend",
1293 | "URL": "2015-04-18",
1294 | "Description": "Blender File FormatCite webdate",
1295 | "Popular": 0
1296 | }
1297 | ]
--------------------------------------------------------------------------------
/pywhat/Data/phone_codes.json:
--------------------------------------------------------------------------------
1 | {
2 | "+93": "Afghanistan",
3 | "+358": "Finland",
4 | "+355": "Albania",
5 | "+213": "Algeria",
6 | "+1 684": "AmericanSamoa",
7 | "+376": "Andorra",
8 | "+244": "Angola",
9 | "+1 264": "Anguilla",
10 | "+672": "Norfolk Island",
11 | "+1268": "Antigua and Barbuda",
12 | "+54": "Argentina",
13 | "+374": "Armenia",
14 | "+297": "Aruba",
15 | "+61": "Cocos (Keeling) Islands",
16 | "+43": "Austria",
17 | "+994": "Azerbaijan",
18 | "+1 242": "Bahamas",
19 | "+973": "Bahrain",
20 | "+880": "Bangladesh",
21 | "+1 246": "Barbados",
22 | "+375": "Belarus",
23 | "+32": "Belgium",
24 | "+501": "Belize",
25 | "+229": "Benin",
26 | "+1 441": "Bermuda",
27 | "+975": "Bhutan",
28 | "+591": "Bolivia, Plurinational State of",
29 | "+387": "Bosnia and Herzegovina",
30 | "+267": "Botswana",
31 | "+55": "Brazil",
32 | "+246": "British Indian Ocean Territory",
33 | "+673": "Brunei Darussalam",
34 | "+359": "Bulgaria",
35 | "+226": "Burkina Faso",
36 | "+257": "Burundi",
37 | "+855": "Cambodia",
38 | "+237": "Cameroon",
39 | "+1": "United States",
40 | "+238": "Cape Verde",
41 | "+ 345": "Cayman Islands",
42 | "+236": "Central African Republic",
43 | "+235": "Chad",
44 | "+56": "Chile",
45 | "+86": "China",
46 | "+57": "Colombia",
47 | "+269": "Comoros",
48 | "+242": "Congo",
49 | "+243": "Congo, The Democratic Republic of the Congo",
50 | "+682": "Cook Islands",
51 | "+506": "Costa Rica",
52 | "+225": "Cote d'Ivoire",
53 | "+385": "Croatia",
54 | "+53": "Cuba",
55 | "+357": "Cyprus",
56 | "+420": "Czech Republic",
57 | "+45": "Denmark",
58 | "+253": "Djibouti",
59 | "+1 767": "Dominica",
60 | "+1 849": "Dominican Republic",
61 | "+593": "Ecuador",
62 | "+20": "Egypt",
63 | "+503": "El Salvador",
64 | "+240": "Equatorial Guinea",
65 | "+291": "Eritrea",
66 | "+372": "Estonia",
67 | "+251": "Ethiopia",
68 | "+500": "South Georgia and the South Sandwich Islands",
69 | "+298": "Faroe Islands",
70 | "+679": "Fiji",
71 | "+33": "France",
72 | "+594": "French Guiana",
73 | "+689": "French Polynesia",
74 | "+241": "Gabon",
75 | "+220": "Gambia",
76 | "+995": "Georgia",
77 | "+49": "Germany",
78 | "+233": "Ghana",
79 | "+350": "Gibraltar",
80 | "+30": "Greece",
81 | "+299": "Greenland",
82 | "+1 473": "Grenada",
83 | "+590": "Saint Martin",
84 | "+1 671": "Guam",
85 | "+502": "Guatemala",
86 | "+44": "United Kingdom",
87 | "+224": "Guinea",
88 | "+245": "Guinea-Bissau",
89 | "+595": "Paraguay",
90 | "+509": "Haiti",
91 | "+379": "Holy See (Vatican City State)",
92 | "+504": "Honduras",
93 | "+852": "Hong Kong",
94 | "+36": "Hungary",
95 | "+354": "Iceland",
96 | "+91": "India",
97 | "+62": "Indonesia",
98 | "+98": "Iran, Islamic Republic of Persian Gulf",
99 | "+964": "Iraq",
100 | "+353": "Ireland",
101 | "+972": "Israel",
102 | "+39": "Italy",
103 | "+1 876": "Jamaica",
104 | "+81": "Japan",
105 | "+962": "Jordan",
106 | "+7 7": "Kazakhstan",
107 | "+254": "Kenya",
108 | "+686": "Kiribati",
109 | "+850": "Korea, Democratic People's Republic of Korea",
110 | "+82": "Korea, Republic of South Korea",
111 | "+383": "Kosovo",
112 | "+965": "Kuwait",
113 | "+996": "Kyrgyzstan",
114 | "+856": "Laos",
115 | "+371": "Latvia",
116 | "+961": "Lebanon",
117 | "+266": "Lesotho",
118 | "+231": "Liberia",
119 | "+218": "Libyan Arab Jamahiriya",
120 | "+423": "Liechtenstein",
121 | "+370": "Lithuania",
122 | "+352": "Luxembourg",
123 | "+853": "Macao",
124 | "+389": "Macedonia",
125 | "+261": "Madagascar",
126 | "+265": "Malawi",
127 | "+60": "Malaysia",
128 | "+960": "Maldives",
129 | "+223": "Mali",
130 | "+356": "Malta",
131 | "+692": "Marshall Islands",
132 | "+596": "Martinique",
133 | "+222": "Mauritania",
134 | "+230": "Mauritius",
135 | "+262": "Reunion",
136 | "+52": "Mexico",
137 | "+691": "Micronesia, Federated States of Micronesia",
138 | "+373": "Moldova",
139 | "+377": "Monaco",
140 | "+976": "Mongolia",
141 | "+382": "Montenegro",
142 | "+1664": "Montserrat",
143 | "+212": "Morocco",
144 | "+258": "Mozambique",
145 | "+95": "Myanmar",
146 | "+264": "Namibia",
147 | "+674": "Nauru",
148 | "+977": "Nepal",
149 | "+31": "Netherlands",
150 | "+599": "Netherlands Antilles",
151 | "+687": "New Caledonia",
152 | "+64": "New Zealand",
153 | "+505": "Nicaragua",
154 | "+227": "Niger",
155 | "+234": "Nigeria",
156 | "+683": "Niue",
157 | "+1 670": "Northern Mariana Islands",
158 | "+47": "Svalbard and Jan Mayen",
159 | "+968": "Oman",
160 | "+92": "Pakistan",
161 | "+680": "Palau",
162 | "+970": "Palestinian Territory, Occupied",
163 | "+507": "Panama",
164 | "+675": "Papua New Guinea",
165 | "+51": "Peru",
166 | "+63": "Philippines",
167 | "+872": "Pitcairn",
168 | "+48": "Poland",
169 | "+351": "Portugal",
170 | "+1 939": "Puerto Rico",
171 | "+974": "Qatar",
172 | "+40": "Romania",
173 | "+7": "Russia",
174 | "+250": "Rwanda",
175 | "+290": "Saint Helena, Ascension and Tristan Da Cunha",
176 | "+1 869": "Saint Kitts and Nevis",
177 | "+1 758": "Saint Lucia",
178 | "+508": "Saint Pierre and Miquelon",
179 | "+1 784": "Saint Vincent and the Grenadines",
180 | "+685": "Samoa",
181 | "+378": "San Marino",
182 | "+239": "Sao Tome and Principe",
183 | "+966": "Saudi Arabia",
184 | "+221": "Senegal",
185 | "+381": "Serbia",
186 | "+248": "Seychelles",
187 | "+232": "Sierra Leone",
188 | "+65": "Singapore",
189 | "+421": "Slovakia",
190 | "+386": "Slovenia",
191 | "+677": "Solomon Islands",
192 | "+252": "Somalia",
193 | "+27": "South Africa",
194 | "+34": "Spain",
195 | "+94": "Sri Lanka",
196 | "+249": "Sudan",
197 | "+597": "SuriName",
198 | "+268": "Swaziland",
199 | "+46": "Sweden",
200 | "+41": "Switzerland",
201 | "+963": "Syrian Arab Republic",
202 | "+886": "Taiwan",
203 | "+992": "Tajikistan",
204 | "+255": "Tanzania, United Republic of Tanzania",
205 | "+66": "Thailand",
206 | "+670": "Timor-Leste",
207 | "+228": "Togo",
208 | "+690": "Tokelau",
209 | "+676": "Tonga",
210 | "+1 868": "Trinidad and Tobago",
211 | "+216": "Tunisia",
212 | "+90": "Turkey",
213 | "+993": "Turkmenistan",
214 | "+1 649": "Turks and Caicos Islands",
215 | "+688": "Tuvalu",
216 | "+256": "Uganda",
217 | "+380": "Ukraine",
218 | "+971": "United Arab Emirates",
219 | "+598": "Uruguay",
220 | "+998": "Uzbekistan",
221 | "+678": "Vanuatu",
222 | "+58": "Venezuela, Bolivarian Republic of Venezuela",
223 | "+84": "Vietnam",
224 | "+1 284": "Virgin Islands, British",
225 | "+1 340": "Virgin Islands, U.S.",
226 | "+681": "Wallis and Futuna",
227 | "+967": "Yemen",
228 | "+260": "Zambia",
229 | "+263": "Zimbabwe"
230 | }
--------------------------------------------------------------------------------
/pywhat/__init__.py:
--------------------------------------------------------------------------------
1 | from pywhat.filter import Distribution, Filter
2 | from pywhat.helper import AvailableTags, Keys
3 | from pywhat.identifier import Identifier
4 |
5 | __version__ = "5.0.0"
6 |
7 | tags = AvailableTags().get_tags()
8 | pywhat_tags = tags # left for backward compatibility purposes
9 |
10 | __all__ = ["Identifier", "Distribution", "tags", "pywhat_tags", "Keys", "Filter"]
11 |
12 |
13 | del AvailableTags, filter
14 |
15 |
16 | def __dir__():
17 | return __all__ + ["__version__"]
18 |
--------------------------------------------------------------------------------
/pywhat/__main__.py:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env python3
2 |
3 | """
4 | pyWhat: Identify Anything.
5 | """
6 |
7 | import platform
8 | import sys
9 |
10 | if __name__ == "__main__":
11 | if sys.version_info < (3, 6):
12 | print(
13 | f"What requires Python 3.6+, you are using {platform.python_version()}. Please install a higher Python version."
14 | )
15 | sys.exit(1)
16 |
17 | from pywhat import what
18 |
19 | if len(sys.argv) == 1:
20 | what.main(["--help"])
21 |
22 | what.main()
23 |
--------------------------------------------------------------------------------
/pywhat/filter.py:
--------------------------------------------------------------------------------
1 | from collections.abc import Mapping
2 | from typing import Optional
3 |
4 | from pywhat.helper import AvailableTags, CaseInsensitiveSet, InvalidTag, load_regexes
5 |
6 |
7 | class Filter(Mapping):
8 | """
9 | A filter is an object containing the filtration information.
10 | The difference from Distribution object is
11 | that Filter object does not store regexes.
12 |
13 | Example filters:
14 | * {"Tags": ["Networking"]}
15 | * {"Tags": ["Identifiers"], "ExcludeTags": ["Credentials"], "MinRarity": 0.6}
16 | """
17 |
18 | def __init__(self, filters_dict=None):
19 | tags = CaseInsensitiveSet(AvailableTags().get_tags())
20 | self._dict = {}
21 | if filters_dict is None:
22 | filters_dict = {}
23 |
24 | self._dict["Tags"] = CaseInsensitiveSet(filters_dict.setdefault("Tags", tags))
25 | self._dict["ExcludeTags"] = CaseInsensitiveSet(
26 | filters_dict.setdefault("ExcludeTags", set())
27 | )
28 | # We have regex with 0 rarity which trip false positive alarms all the time
29 | self._dict["MinRarity"] = filters_dict.setdefault("MinRarity", 0.1)
30 | self._dict["MaxRarity"] = filters_dict.setdefault("MaxRarity", 1)
31 | if not self._dict["Tags"].issubset(tags) or not self._dict[
32 | "ExcludeTags"
33 | ].issubset(tags):
34 | raise InvalidTag("Passed filter contains tags that are not used by 'what'")
35 |
36 | def get_filter(self):
37 | return dict(self._dict)
38 |
39 | def __repr__(self):
40 | return f"{self.__class__.__name__}({self._dict})"
41 |
42 | def __and__(self, other):
43 | if type(self) != type(other):
44 | return NotImplemented
45 | tags = self._dict["Tags"] & other._dict["Tags"]
46 | exclude_tags = self._dict["ExcludeTags"] & other._dict["ExcludeTags"]
47 | min_rarity = max(self._dict["MinRarity"], other._dict["MinRarity"])
48 | max_rarity = min(self._dict["MaxRarity"], other._dict["MaxRarity"])
49 | return self.__class__(
50 | {
51 | "Tags": tags,
52 | "ExcludeTags": exclude_tags,
53 | "MinRarity": min_rarity,
54 | "MaxRarity": max_rarity,
55 | }
56 | )
57 |
58 | def __or__(self, other):
59 | if type(self) != type(other):
60 | return NotImplemented
61 | tags = self._dict["Tags"] | other._dict["Tags"]
62 | exclude_tags = self._dict["ExcludeTags"] | other._dict["ExcludeTags"]
63 | min_rarity = min(self._dict["MinRarity"], other._dict["MinRarity"])
64 | max_rarity = max(self._dict["MaxRarity"], other._dict["MaxRarity"])
65 | return self.__class__(
66 | {
67 | "Tags": tags,
68 | "ExcludeTags": exclude_tags,
69 | "MinRarity": min_rarity,
70 | "MaxRarity": max_rarity,
71 | }
72 | )
73 |
74 | def __iand__(self, other):
75 | if type(self) != type(other):
76 | return NotImplemented
77 | return self & other
78 |
79 | def __ior__(self, other):
80 | if type(self) != type(other):
81 | return NotImplemented
82 | return self | other
83 |
84 | def __getitem__(self, key):
85 | return self._dict[key]
86 |
87 | def __iter__(self):
88 | return iter(self._dict)
89 |
90 | def __len__(self):
91 | return len(self._dict)
92 |
93 | def __contains__(self, item):
94 | return (
95 | self["MinRarity"] <= item["Rarity"] <= self["MaxRarity"]
96 | and set(item["Tags"]) & self["Tags"]
97 | and not set(item["Tags"]) & self["ExcludeTags"]
98 | )
99 |
100 | def setdefault(self, key, default=None):
101 | return self._dict.setdefault(key, default)
102 |
103 |
104 | class Distribution(Filter):
105 | """
106 | A distribution is an object containing the regex
107 | But the regex has gone through a filter process.
108 |
109 | Example filters:
110 | * {"Tags": ["Networking"]}
111 | * {"Tags": ["Identifiers"], "ExcludeTags": ["Credentials"], "MinRarity": 0.6}
112 | """
113 |
114 | def __init__(self, filter: Optional[Filter] = None):
115 | super().__init__(filter)
116 | self._filter()
117 |
118 | def _filter(self):
119 | self._regexes = load_regexes()
120 | temp_regexes = [regex for regex in self._regexes if regex in self]
121 | self._regexes = temp_regexes
122 |
123 | def get_regexes(self):
124 | return list(self._regexes)
125 |
--------------------------------------------------------------------------------
/pywhat/helper.py:
--------------------------------------------------------------------------------
1 | """Helper utilities"""
2 | import collections.abc
3 | import os.path
4 | import re
5 | from enum import Enum, auto
6 | from functools import lru_cache
7 |
8 | try:
9 | import orjson as json
10 | except ImportError:
11 | import json # type: ignore
12 |
13 |
14 | class AvailableTags:
15 | def __init__(self):
16 | self.tags = set()
17 | regexes = load_regexes()
18 | for regex in regexes:
19 | self.tags.update(regex["Tags"])
20 |
21 | def get_tags(self):
22 | return self.tags
23 |
24 |
25 | class InvalidTag(Exception):
26 | """
27 | This exception should be raised when Distribution() gets a filter
28 | containing non-existent tags.
29 | """
30 |
31 | pass
32 |
33 |
34 | @lru_cache()
35 | def read_json(path: str):
36 | fullpath = os.path.join(os.path.dirname(os.path.abspath(__file__)), "Data/" + path)
37 | with open(fullpath, "rb") as myfile:
38 | return json.loads(myfile.read())
39 |
40 |
41 | @lru_cache()
42 | def load_regexes() -> list:
43 | regexes = read_json("regex.json")
44 | for regex in regexes:
45 | regex["Boundaryless Regex"] = re.sub(
46 | r"(? dict:
39 | if dist is None:
40 | dist = self.distribution
41 | if key is None:
42 | key = self._key
43 | if reverse is None:
44 | reverse = self._reverse
45 | if boundaryless is None:
46 | boundaryless = self.boundaryless
47 |
48 | identify_obj: dict = {"File Signatures": {}, "Regexes": {}}
49 | search = []
50 |
51 | if not only_text and os.path.isdir(text):
52 | # if input is a directory, recursively search for all of the files
53 | for myfile in glob.iglob(text + "/**", recursive=True):
54 | if os.path.isfile(myfile):
55 | search.append(os.path.abspath(myfile))
56 | else:
57 | search = [text]
58 |
59 | for string in search:
60 | if not only_text and os.path.isfile(string):
61 | if os.path.isdir(text):
62 | short_name = string.replace(os.path.abspath(text), "")
63 | else:
64 | short_name = os.path.basename(string)
65 |
66 | magic_numbers = pywhat.magic_numbers.get_magic_nums(string)
67 | with open(string, "r", encoding="utf-8", errors="ignore") as file:
68 | contents = [file.read()]
69 |
70 | if include_filenames:
71 | contents.append(os.path.basename(string))
72 |
73 | regex = self._regex_id.check(
74 | contents, dist=dist, boundaryless=boundaryless
75 | )
76 |
77 | if not magic_numbers:
78 | magic_numbers = pywhat.magic_numbers.check_magic_nums(string)
79 |
80 | if magic_numbers:
81 | identify_obj["File Signatures"][short_name] = magic_numbers
82 | else:
83 | short_name = "text"
84 | regex = self._regex_id.check(
85 | search, dist=dist, boundaryless=boundaryless
86 | )
87 |
88 | if regex:
89 | identify_obj["Regexes"][short_name] = regex
90 |
91 | for key_, value in identify_obj.items():
92 | # if there are zero regex or file signature matches, set it to None
93 | if not value:
94 | identify_obj[key_] = None
95 |
96 | if key != Keys.NONE:
97 | identify_obj["Regexes"][short_name] = sorted(
98 | identify_obj["Regexes"][short_name], key=key, reverse=reverse
99 | )
100 |
101 | return identify_obj
102 |
--------------------------------------------------------------------------------
/pywhat/magic_numbers.py:
--------------------------------------------------------------------------------
1 | import binascii
2 |
3 | from pywhat.helper import read_json
4 |
5 |
6 | def get_magic_nums(file_loc):
7 | with open(file_loc, "rb") as myfile:
8 | header = myfile.read(24)
9 | header = str(binascii.hexlify(header))[2:-1]
10 | return check_magic_nums(header)
11 |
12 |
13 | def check_magic_nums(text):
14 | for i in read_json("file_signatures.json"):
15 | to_check = i["Hexadecimal File Signature"]
16 | if text.lower().startswith(to_check.lower()):
17 | # A file can only be one type
18 | return i
19 | return None
20 |
--------------------------------------------------------------------------------
/pywhat/printer.py:
--------------------------------------------------------------------------------
1 | import json
2 | import os
3 | import re
4 |
5 | from rich.console import Console
6 | from rich.table import Table
7 |
8 |
9 | class Printing:
10 | def __init__(self):
11 | self.console = Console(highlight=False)
12 | self.bug_bounty_mode = False
13 |
14 | def pretty_print(self, text: dict, text_input, print_tags=False):
15 | to_out = ""
16 |
17 | if text["File Signatures"]:
18 | for key, value in text["File Signatures"].items():
19 | if value:
20 | to_out += "\n"
21 | to_out += f"[bold #D7Afff]File Identified[/bold #D7Afff]: [bold]{key}[/bold] with Magic Numbers {value['ISO 8859-1']}."
22 | to_out += f"\n[bold #D7Afff]File Description: [/bold #D7Afff] {value['Description']}."
23 | to_out += "\n\n"
24 |
25 | if text["Regexes"]:
26 | to_out += "\n[bold #D7Afff]Possible Identification[/bold #D7Afff]\n"
27 | table = Table(
28 | show_header=True, header_style="bold #D7Afff", show_lines=True
29 | )
30 | table.add_column("Matched Text", overflow="fold")
31 | table.add_column("Identified as", overflow="fold")
32 | table.add_column("Description", overflow="fold")
33 |
34 | if self._check_if_directory(text_input):
35 | # if input is a folder, add a filename column
36 | table.add_column("File", overflow="fold")
37 |
38 | # Check if there are any bug bounties with exploits
39 | # in the regex
40 | self._check_if_exploit_in_json(text)
41 | if self.bug_bounty_mode:
42 | table.add_column("Exploit", overflow="fold")
43 |
44 | for key, value in text["Regexes"].items():
45 | for i in value:
46 | matched = i["Matched"]
47 | name = i["Regex Pattern"]["Name"]
48 | description = None
49 | filename = key
50 | exploit = None
51 |
52 | if "URL" in i["Regex Pattern"] and i["Regex Pattern"]["URL"]:
53 | description = (
54 | "Click here to analyse in the browser\n"
55 | + i["Regex Pattern"]["URL"]
56 | + matched.replace(" ", "")
57 | )
58 |
59 | if i["Regex Pattern"]["Description"]:
60 | if description:
61 | description = (
62 | description + "\n" + i["Regex Pattern"]["Description"]
63 | )
64 | else:
65 | description = i["Regex Pattern"]["Description"]
66 |
67 | if (
68 | "Exploit" in i["Regex Pattern"]
69 | and i["Regex Pattern"]["Exploit"]
70 | ):
71 | exploit = i["Regex Pattern"]["Exploit"]
72 |
73 | if print_tags:
74 | tags = f"Tags: {', '.join(i['Regex Pattern']['Tags'])}"
75 | if description is None:
76 | description = tags
77 | else:
78 | description += "\n" + tags
79 |
80 | if description is None:
81 | description = "None"
82 |
83 | # FIXME this is quite messy
84 | if self.bug_bounty_mode:
85 | if self._check_if_directory(text_input):
86 | table.add_row(
87 | matched,
88 | name,
89 | description,
90 | filename,
91 | exploit,
92 | )
93 | else:
94 | table.add_row(
95 | matched,
96 | name,
97 | description,
98 | exploit,
99 | )
100 | elif self._check_if_directory(text_input):
101 | table.add_row(
102 | matched,
103 | name,
104 | description,
105 | filename,
106 | )
107 | else:
108 | table.add_row(
109 | matched,
110 | name,
111 | description,
112 | )
113 |
114 | self.console.print(to_out.strip(), table)
115 |
116 | elif not self.bug_bounty_mode:
117 | self.console.print((to_out + "\nNothing found!").lstrip())
118 |
119 | def print_json(self, text: dict):
120 | print(json.dumps(text))
121 |
122 | """
123 | Does not create a table, prints it as raw text
124 | Returns the printable object
125 | """
126 |
127 | def print_raw(self, text: dict, text_input, print_tags=False):
128 | output_str = ""
129 |
130 | if text["File Signatures"] and text["Regexes"]:
131 | for key, value in text["File Signatures"].items():
132 | if value:
133 | output_str += "\n"
134 | output_str += f"[bold #D7Afff]File Identified[/bold #D7Afff]: [bold]{key}[/bold] with Magic Numbers {value['ISO 8859-1']}."
135 | output_str += f"\n[bold #D7Afff]File Description:[/bold #D7Afff] {value['Description']}."
136 | output_str += "\n"
137 |
138 | if text["Regexes"]:
139 | for key, value in text["Regexes"].items():
140 | for i in value:
141 | description = None
142 | matched = i["Matched"]
143 | if self._check_if_directory(text_input):
144 | output_str += f"[bold #D7Afff]File: {key}[/bold #D7Afff]\n"
145 | output_str += (
146 | "[bold #D7Afff]Matched on: [/bold #D7Afff]" + i["Matched"]
147 | )
148 | output_str += (
149 | "\n[bold #D7Afff]Name: [/bold #D7Afff]"
150 | + i["Regex Pattern"]["Name"]
151 | )
152 |
153 | link = None
154 | if "URL" in i["Regex Pattern"] and i["Regex Pattern"]["URL"]:
155 | link = (
156 | "\n[bold #D7Afff]Link: [/bold #D7Afff] "
157 | + i["Regex Pattern"]["URL"]
158 | + matched.replace(" ", "")
159 | )
160 |
161 | if link:
162 | output_str += link
163 |
164 | if i["Regex Pattern"]["Description"]:
165 | description = (
166 | "\n[bold #D7Afff]Description: [/bold #D7Afff]"
167 | + i["Regex Pattern"]["Description"]
168 | )
169 |
170 | if description:
171 | output_str += description
172 |
173 | if (
174 | "Exploit" in i["Regex Pattern"]
175 | and i["Regex Pattern"]["Exploit"]
176 | ):
177 | output_str += (
178 | "\n[bold #D7Afff]Exploit: [/bold #D7Afff]"
179 | + i["Regex Pattern"]["Exploit"]
180 | )
181 |
182 | if print_tags:
183 | output_str += f"\n[bold #D7Afff]Tags: [/bold #D7Afff]{', '.join(i['Regex Pattern']['Tags'])}"
184 |
185 | output_str += "\n\n"
186 |
187 | if output_str == "" and not self.bug_bounty_mode:
188 | self.console.print("Nothing found!")
189 |
190 | if output_str.strip():
191 | self.console.print(output_str.rstrip())
192 |
193 | return output_str
194 |
195 | def format_print(self, text: dict, format_str: str):
196 | if text["Regexes"]:
197 | output = []
198 | format_list = []
199 |
200 | # Split format_str so that format_list's item will either be r'\\' or something else
201 | start = 0
202 | i = format_str.find(r"\\", start)
203 | while i != -1:
204 | if format_str[start:i]:
205 | format_list.append(format_str[start:i])
206 | format_list.append("\\")
207 | start = i + 2
208 | i = format_str.find(r"\\", start)
209 | format_list.append(format_str[start:])
210 |
211 | for key, value in text["Regexes"].items():
212 | for match in value:
213 | temp = ""
214 | for s in format_list:
215 | formats = {
216 | "%m": match["Matched"],
217 | "%n": match["Regex Pattern"]["Name"],
218 | "%d": match["Regex Pattern"]["Description"],
219 | "%e": match["Regex Pattern"].get("Exploit"),
220 | "%r": str(match["Regex Pattern"]["Rarity"]),
221 | "%l": match["Regex Pattern"]["URL"] + match["Matched"]
222 | if match["Regex Pattern"]["URL"] is not None
223 | else None,
224 | "%t": ", ".join(match["Regex Pattern"]["Tags"]),
225 | }
226 | for format, value in formats.items():
227 | value = str() if value is None else value
228 | s = re.sub(r"(? bool:
238 | if "File Signatures" in text and text["File Signatures"]:
239 | # loops files
240 | for file in text["Regexes"].keys():
241 | for i in text["Regexes"][file]:
242 | if "Exploit" in i.keys():
243 | self.bug_bounty_mode = True
244 | else:
245 | for value in text["Regexes"]["text"]:
246 | if "Exploit" in value["Regex Pattern"].keys():
247 | self.bug_bounty_mode = True
248 |
249 | return self.bug_bounty_mode
250 |
251 | def _check_if_directory(self, text_input):
252 | return os.path.isdir(text_input)
253 |
--------------------------------------------------------------------------------
/pywhat/regex_identifier.py:
--------------------------------------------------------------------------------
1 | import re
2 | from typing import Optional
3 |
4 | from pywhat.filter import Distribution, Filter
5 |
6 |
7 | class RegexIdentifier:
8 | def __init__(self):
9 | self.distribution = Distribution()
10 |
11 | def check(
12 | self,
13 | text,
14 | dist: Optional[Distribution] = None,
15 | *,
16 | boundaryless: Optional[Filter] = None
17 | ):
18 | if dist is None:
19 | dist = self.distribution
20 | if boundaryless is None:
21 | boundaryless = Filter({"Tags": []})
22 | matches = []
23 |
24 | for string in text:
25 | for reg in dist.get_regexes():
26 | regex = (
27 | reg["Boundaryless Regex"] if reg in boundaryless else reg["Regex"]
28 | )
29 | for matched_regex in re.finditer(regex, string, re.MULTILINE):
30 | reg_match = dict(reg)
31 | matched = self.clean_text(matched_regex.group(0))
32 |
33 | if (
34 | reg_match.get("Exploit") is not None
35 | and "curl" in reg_match["Exploit"]
36 | ):
37 | # Replace anything like XXXXX_XXXXXX_HERE with the match
38 | reg_match["Exploit"] = re.sub(
39 | r"[A-Z_]+_HERE", matched, reg_match["Exploit"]
40 | )
41 |
42 | children = reg_match.get("Children")
43 | if children is not None:
44 | processed_match = re.sub(
45 | children.get("deletion_pattern", ""), "", matched
46 | )
47 | matched_children = []
48 | if children["method"] == "hashmap":
49 | for length in children["lengths"]:
50 | try:
51 | matched_children.append(
52 | children["Items"][processed_match[:length]]
53 | )
54 | except KeyError:
55 | continue
56 | else:
57 | for element in children["Items"]:
58 | if (
59 | children["method"] == "regex"
60 | and re.search(
61 | element, processed_match, re.MULTILINE
62 | )
63 | ) or (
64 | children["method"] == "startswith"
65 | and processed_match.startswith(element)
66 | ):
67 | matched_children.append(children["Items"][element])
68 |
69 | if matched_children:
70 | reg_match["Description"] = children.get(
71 | "entry", ""
72 | ) + ", ".join(matched_children)
73 | reg_match.pop("Children", None)
74 |
75 | matches.append(
76 | {
77 | "Matched": matched,
78 | "Regex Pattern": reg_match,
79 | }
80 | )
81 |
82 | return matches
83 |
84 | def clean_text(self, text):
85 | return re.sub(r"[\x00-\x1f\x7f-\x9f]", "", text)
86 |
--------------------------------------------------------------------------------
/pywhat/what.py:
--------------------------------------------------------------------------------
1 | import sys
2 |
3 | import click
4 | from rich.console import Console
5 |
6 | from pywhat import __version__, identifier, printer
7 | from pywhat.filter import Distribution, Filter
8 | from pywhat.helper import AvailableTags, InvalidTag, Keys, str_to_key
9 |
10 |
11 | def print_tags(ctx, opts, value):
12 | if value:
13 | tags = sorted(AvailableTags().get_tags())
14 | console = Console()
15 | console.print("[bold #D7AFFF]" + "\n".join(tags) + "[/bold #D7AFFF]")
16 | sys.exit()
17 |
18 |
19 | def print_version(ctx, opts, value):
20 | if value:
21 | console = Console()
22 | console.print(f"PyWhat version [bold #49C3CE]{__version__}[/bold #49C3CE]")
23 | sys.exit()
24 |
25 |
26 | def create_filter(rarity, include, exclude):
27 | filters_dict = {}
28 | if rarity is not None:
29 | rarities = rarity.split(":")
30 | if len(rarities) != 2:
31 | print("Invalid rarity range format ('min:max' expected)")
32 | sys.exit(1)
33 | try:
34 | if not rarities[0].isspace() and rarities[0]:
35 | filters_dict["MinRarity"] = float(rarities[0])
36 | if not rarities[1].isspace() and rarities[1]:
37 | filters_dict["MaxRarity"] = float(rarities[1])
38 | except ValueError:
39 | print("Invalid rarity argument (float expected)")
40 | sys.exit(1)
41 | if include is not None:
42 | filters_dict["Tags"] = list(map(str.strip, include.split(",")))
43 | if exclude is not None:
44 | filters_dict["ExcludeTags"] = list(map(str.strip, exclude.split(",")))
45 |
46 | try:
47 | filter = Filter(filters_dict)
48 | except InvalidTag:
49 | print(
50 | "Passed tags are not valid.\n"
51 | "You can check available tags by using: 'pywhat --tags'"
52 | )
53 | sys.exit(1)
54 |
55 | return filter
56 |
57 |
58 | def get_text(ctx, opts, value):
59 | if not value and not click.get_text_stream("stdin").isatty():
60 | return click.get_text_stream("stdin").read().strip()
61 | return value
62 |
63 |
64 | @click.command(
65 | context_settings=dict(
66 | ignore_unknown_options=True,
67 | )
68 | )
69 | @click.argument("text_input", callback=get_text, required=False)
70 | @click.option(
71 | "-t",
72 | "--tags",
73 | is_flag=True,
74 | expose_value=False,
75 | callback=print_tags,
76 | help="Show available tags and exit.",
77 | )
78 | @click.option(
79 | "-r",
80 | "--rarity",
81 | help="Filter by rarity. Rarity is how unlikely something is to be a false-positive. The higher the number, the more unlikely. This is in the range of 0:1. To filter only items past 0.5, use 0.5: with the colon on the end. Default 0.1:1",
82 | default="0.1:1",
83 | )
84 | @click.option("-i", "--include", help="Only show matches with these tags.")
85 | @click.option("-e", "--exclude", help="Exclude matches with these tags.")
86 | @click.option("-o", "--only-text", is_flag=True, help="Do not scan files or folders.")
87 | @click.option("-k", "--key", help="Sort by the specified key.")
88 | @click.option("--reverse", is_flag=True, help="Sort in reverse order.")
89 | @click.option(
90 | "-br",
91 | "--boundaryless-rarity",
92 | help="Same as --rarity but for boundaryless mode (toggles what regexes will not have boundaries).",
93 | default="0.1:1",
94 | )
95 | @click.option(
96 | "-bi", "--boundaryless-include", help="Same as --include but for boundaryless mode."
97 | )
98 | @click.option(
99 | "-be", "--boundaryless-exclude", help="Same as --exclude but for boundaryless mode."
100 | )
101 | @click.option(
102 | "-db", "--disable-boundaryless", is_flag=True, help="Disable boundaryless mode."
103 | )
104 | @click.option("--json", is_flag=True, help="Return results in json format.")
105 | @click.option(
106 | "-v",
107 | "--version",
108 | is_flag=True,
109 | callback=print_version,
110 | help="Display the version of pywhat.",
111 | )
112 | @click.option(
113 | "-if",
114 | "--include-filenames",
115 | is_flag=True,
116 | help="Search filenames for possible matches.",
117 | )
118 | @click.option(
119 | "--format",
120 | required=False,
121 | help="Format output according to specified rules.",
122 | )
123 | @click.option("-pt", "--print-tags", is_flag=True, help="Add flags to output")
124 | def main(**kwargs):
125 | """
126 | pyWhat - Identify what something is.
127 |
128 | Made by Bee https://twitter.com/bee_sec_san
129 |
130 | https://github.com/bee-san
131 |
132 | Filtration:
133 |
134 | --rarity min:max
135 |
136 | Rarity is how unlikely something is to be a false-positive. The higher the number, the more unlikely.
137 |
138 | Only print entries with rarity in range [min,max]. min and max can be omitted.
139 |
140 | Note: PyWhat by default has a rarity of 0.1. To see all matches, with many potential false positives use `0:`.
141 |
142 | --include list
143 |
144 | Only include entries containing at least one tag in a list. List is a comma separated list.
145 |
146 | --exclude list
147 |
148 | Exclude specified tags. List is a comma separated list.
149 |
150 | Sorting:
151 |
152 | --key key_name
153 |
154 | Sort by the given key.
155 |
156 | --reverse
157 |
158 | Sort in reverse order.
159 |
160 | Available keys:
161 |
162 | name - Sort by the name of regex pattern
163 |
164 | rarity - Sort by rarity
165 |
166 | matched - Sort by a matched string
167 |
168 | none - No sorting is done (the default)
169 |
170 | Exporting:
171 |
172 | --json
173 |
174 | Return results in json format.
175 |
176 | Boundaryless mode:
177 |
178 | CLI tool matches strings like 'abcdTHM{hello}plze' by default because the boundaryless mode is enabled for regexes with a rarity of 0.1 and higher.
179 |
180 | Since boundaryless mode may produce a lot of false-positive matches, it is possible to disable it, either fully or partially.
181 |
182 | '--disable-boundaryless' flag can be used to fully disable this mode.
183 |
184 | In addition, '-br', '-bi', and '-be' options can be used to tweak which regexes should be in boundaryless mode.
185 |
186 | Refer to the Filtration section for more information.
187 |
188 | Formatting the output:
189 |
190 | --format format_str
191 |
192 | format_str can be equal to:
193 |
194 | pretty - Output data in the table
195 |
196 | json - Output data in json format
197 |
198 | CUSTOM_STRING - Print data in the way you want. For every match CUSTOM_STRING will be printed and '%x' (See below for possible x values) will be substituted with a match value.
199 |
200 | For example:
201 |
202 | pywhat --format '%m - %n' 'google.com htb{flag}'
203 |
204 | will print:
205 |
206 | htb{flag} - HackTheBox Flag Format
207 | google.com - Uniform Resource Locator (URL)
208 |
209 | Possible '%x' values:
210 |
211 | %m - matched text
212 |
213 | %n - name of regex
214 |
215 | %d - description (will not output if absent)
216 |
217 | %e - exploit (will not output if absent)
218 |
219 | %r - rarity
220 |
221 | %l - link (will not output if absent)
222 |
223 | %t - tags (in 'tag1, tag2 ...' format)
224 |
225 | If you want to print '%' or '\\' character - escape it: '\\%', '\\\\'.
226 |
227 | Examples:
228 |
229 | * what 'HTB{this is a flag}'
230 |
231 | * what '0x52908400098527886E0F7030069857D2E4169EE7'
232 |
233 | * what -- '52.6169586, -1.9779857'
234 |
235 | * what --rarity 0.6: 'myEmail@host.org'
236 |
237 | * what --rarity 0: --include "credentials" --exclude "aws" 'James:SecretPassword'
238 |
239 | * what -br 0.6: -be URL '123myEmail@host.org456'
240 |
241 | Your text must either be in quotation marks, or use the POSIX standard of "--" to mean "anything after -- is textual input".
242 |
243 |
244 | pyWhat can also search files or even a whole directory with recursion:
245 |
246 | * what 'secret.txt'
247 |
248 | * what 'this/is/a/path'
249 |
250 | """
251 | if kwargs["text_input"] is None:
252 | sys.exit("Text input expected. Run 'pywhat --help' for help")
253 | dist = Distribution(
254 | create_filter(kwargs["rarity"], kwargs["include"], kwargs["exclude"])
255 | )
256 | if kwargs["disable_boundaryless"]:
257 | boundaryless = Filter({"Tags": []}) # use empty filter
258 | else:
259 | boundaryless = create_filter(
260 | kwargs["boundaryless_rarity"],
261 | kwargs["boundaryless_include"],
262 | kwargs["boundaryless_exclude"],
263 | )
264 | what_obj = What_Object(dist)
265 | if kwargs["key"] is None:
266 | key = Keys.NONE
267 | else:
268 | try:
269 | key = str_to_key(kwargs["key"])
270 | except ValueError:
271 | print("Invalid key")
272 | sys.exit(1)
273 | identified_output = what_obj.what_is_this(
274 | kwargs["text_input"],
275 | kwargs["only_text"],
276 | key,
277 | kwargs["reverse"],
278 | boundaryless,
279 | kwargs["include_filenames"],
280 | )
281 |
282 | p = printer.Printing()
283 |
284 | if kwargs["json"] or str(kwargs["format"]).strip() == "json":
285 | p.print_json(identified_output)
286 | elif str(kwargs["format"]).strip() == "pretty":
287 | p.pretty_print(identified_output, kwargs["text_input"], kwargs["print_tags"])
288 | elif kwargs["format"] is not None:
289 | p.format_print(identified_output, kwargs["format"])
290 | else:
291 | p.print_raw(identified_output, kwargs["text_input"], kwargs["print_tags"])
292 |
293 |
294 | class What_Object:
295 | def __init__(self, distribution):
296 | self.id = identifier.Identifier(dist=distribution)
297 |
298 | def what_is_this(
299 | self,
300 | text: str,
301 | only_text: bool,
302 | key,
303 | reverse: bool,
304 | boundaryless: Filter,
305 | include_filenames: bool,
306 | ) -> dict:
307 | """
308 | Returns a Python dictionary of everything that has been identified
309 | """
310 | return self.id.identify(
311 | text,
312 | only_text=only_text,
313 | key=key,
314 | reverse=reverse,
315 | boundaryless=boundaryless,
316 | include_filenames=include_filenames,
317 | )
318 |
319 |
320 | if __name__ == "__main__":
321 | main()
322 |
--------------------------------------------------------------------------------
/scripts/format_regex.py:
--------------------------------------------------------------------------------
1 | import json
2 |
3 | with open("pywhat/Data/regex.json") as file:
4 | database = json.load(file)
5 |
6 |
7 | with open("pywhat/Data/regex.json", "w") as file:
8 | json.dump(database, file, indent=3)
9 |
--------------------------------------------------------------------------------
/scripts/get_file_sigs.py:
--------------------------------------------------------------------------------
1 | import json
2 | import re
3 |
4 | import requests
5 | import wikitextparser as wtp
6 |
7 |
8 | def cleanhtml(raw_html):
9 | cleanr = re.compile("<.*?>")
10 | cleantext = re.sub(cleanr, "", raw_html)
11 | return (
12 | cleantext.replace("\n", " ")
13 | .replace("\t", " ")
14 | .replace("{", "")
15 | .replace("}", "")
16 | .replace("|", "")
17 | .replace("<", "")
18 | .replace(">", "")
19 | .replace("show file signature", "")
20 | .replace("[[", "")
21 | .replace("]]", "")
22 | .replace("web url", "")
23 | .replace("cite", "")
24 | .strip()
25 | )
26 |
27 |
28 | r = requests.get(
29 | "https://en.wikipedia.org/w/index.php?title=" + "List_of_file_signatures&action=raw"
30 | )
31 | wt = wtp.parse(r.text)
32 | # prints first 3 items of json, delete [0:3] to print all.
33 |
34 | sig_dict = {"root": wt.tables[0].data()}
35 | to_iter = sig_dict["root"]
36 | to_dump = []
37 |
38 | populars = {"23 21"}
39 |
40 | for i in range(1, len(to_iter)):
41 | to_insert = {}
42 | to_insert["Hexadecimal File Signature"] = cleanhtml(to_iter[i][0]).replace(" ", "")
43 | check_iso = cleanhtml(to_iter[i][1])
44 | if len(set(check_iso)) <= 2:
45 | to_insert["ISO 8859-1"] = None
46 | else:
47 | to_insert["ISO 8859-1"] = check_iso
48 | check = to_iter[i][3]
49 | if check == "":
50 | to_insert["Filename Extension"] = None
51 | else:
52 | to_insert["Filename Extension"] = cleanhtml(check)
53 |
54 | des = to_iter[i][4]
55 | if "url" in des:
56 | splits = des.split("=")
57 | if "|" in splits[1]:
58 | # https://wiki.wireshark.org/Development/LibpcapFileFormat#Global_Header|title
59 | split_more = splits[1].split("|")
60 | print(split_more)
61 | to_insert["URL"] = split_more[0]
62 | else:
63 | to_insert["URL"] = splits[1]
64 | to_insert["Description"] = cleanhtml(splits[0])
65 | else:
66 | to_insert["Description"] = cleanhtml(to_iter[i][4])
67 |
68 | if to_insert["Hexadecimal File Signature"] in populars:
69 | to_insert["Popular"] = 1
70 | else:
71 | to_insert["Popular"] = 0
72 | to_dump.append(to_insert)
73 |
74 | with open("file_signatures.json", "w") as outfile:
75 | json.dump(to_dump, outfile, indent=4)
76 |
77 | # https://en.wikipedia.org/api/rest_v1/page/html/List_of_file_signatures
78 |
79 | """
80 | {
81 | "root": [
82 | [
83 | "[[Hexadecimal|Hex]] signature",
84 | "ISO 8859-1",
85 | "[[Offset (computer science)|Offset]]",
86 | "[[Filename extension]]",
87 | "Description"
88 | ],
89 | [
90 | "]23 21
",
91 | "{{show file signature|23 21}}",
92 | "0",
93 | "",
94 | "Script or data to be passed to the program following the [[Shebang (Unix)|shebang]] (#!)"
95 | ],
96 | [
97 | "a1 b2 c3 d4
\nd4 c3 b2 a1
",
98 | "{{show file signature|a1 b2 c3 d4}}\n{{show file signature|d4 c3 b2 a1}}",
99 | "0",
100 | "pcap",
101 | "Libpcap File Format[{{cite web |url=https://wiki.wireshark.org/Development/LibpcapFileFormat#Global_Header|title=Libpcap File Format|access-date=2018-06-19}}]"
102 | ]
103 | ]
104 | }
105 | """
106 |
--------------------------------------------------------------------------------
/scripts/get_tlds.py:
--------------------------------------------------------------------------------
1 | import re
2 |
3 | import requests
4 |
5 | tlds = requests.get("https://data.iana.org/TLD/tlds-alpha-by-domain.txt")
6 | final_string = "|".join(sorted(tlds.text.split("\n")[1:-1], key=len, reverse=True))
7 |
8 |
9 | with open("pywhat/Data/regex.json", "r") as file:
10 | database = file.read()
11 |
12 | database = re.sub(
13 | r"(?:[A-Z0-9-]+\|){500,}[A-Z0-9-]+",
14 | final_string,
15 | database,
16 | )
17 |
18 | with open("pywhat/Data/regex.json", "w") as file:
19 | file.write(database)
20 |
--------------------------------------------------------------------------------
/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bee-san/pyWhat/75a1592cbc4151acdaaeab78b71dd65ea9a9230e/tests/__init__.py
--------------------------------------------------------------------------------
/tests/test_click.py:
--------------------------------------------------------------------------------
1 | import json
2 | import re
3 |
4 | import pytest
5 | from click.testing import CliRunner
6 |
7 | from pywhat import pywhat_tags
8 | from pywhat.what import main
9 |
10 |
11 | def test_nothing_found():
12 | runner = CliRunner()
13 | result = runner.invoke(main, ["-db", ""])
14 | assert result.exit_code == 0
15 | assert "Nothing found!" in result.output
16 |
17 |
18 | def test_hello_world():
19 | runner = CliRunner()
20 | result = runner.invoke(main, ["-db", "THM{this is a flag}"])
21 | assert result.exit_code == 0
22 | assert "THM{" in result.output
23 |
24 |
25 | def test_filtration():
26 | runner = CliRunner()
27 | result = runner.invoke(
28 | main,
29 | ["--rarity", "0.5:", "--include", "Identifiers,Media", "-db", "fixtures/file"],
30 | )
31 | assert result.exit_code == 0
32 | assert "THM{" not in result.output
33 | assert "ETH" not in result.output
34 | assert "Email Address" in result.output
35 | assert "IP" in result.output
36 | assert "URL" in result.output
37 |
38 |
39 | def test_tag_printing():
40 | runner = CliRunner()
41 | result = runner.invoke(main, "--tags")
42 | assert result.exit_code == 0
43 | for tag in pywhat_tags:
44 | assert tag in result.output
45 |
46 |
47 | def test_json_printing():
48 | """Test for valid json"""
49 | runner = CliRunner()
50 | result = runner.invoke(main, ["-db", "10.0.0.1", "--json"])
51 | assert json.loads(result.output.replace("\n", ""))
52 |
53 |
54 | def test_json_printing2():
55 | """Test for empty json return"""
56 | runner = CliRunner()
57 | result = runner.invoke(main, ["-db", "", "--json"])
58 | assert result.output.strip("\n") == '{"File Signatures": null, "Regexes": null}'
59 |
60 |
61 | def test_json_printing3():
62 | runner = CliRunner()
63 | result = runner.invoke(main, ["-db", "fixtures/file", "--json"])
64 | assert json.loads(result.output.replace("\n", ""))
65 |
66 |
67 | def test_file_fixture():
68 | runner = CliRunner()
69 | result = runner.invoke(main, ["-db", "fixtures/file"])
70 | assert result.exit_code == 0
71 | assert re.findall("thm", str(result.output))
72 | assert re.findall("Ethereum", str(result.output))
73 | assert "Dogecoin" in result.output
74 |
75 |
76 | def test_file_fixture2():
77 | runner = CliRunner()
78 | result = runner.invoke(main, ["-db", "fixtures/file"])
79 | assert result.exit_code == 0
80 | assert "Dogecoin" in result.output
81 |
82 |
83 | def test_file_fixture3():
84 | runner = CliRunner()
85 | result = runner.invoke(main, ["-db", "fixtures/file"])
86 | assert result.exit_code == 0
87 | assert re.findall("thm", str(result.output))
88 |
89 |
90 | def test_file_fixture4():
91 | runner = CliRunner()
92 | result = runner.invoke(main, ["-db", "fixtures/file"])
93 | assert result.exit_code == 0
94 | assert re.findall("Ethereum", str(result.output))
95 |
96 |
97 | def test_file_fixture5():
98 | runner = CliRunner()
99 | result = runner.invoke(main, ["-db", "fixtures/file"])
100 | assert result.exit_code == 0
101 | assert re.findall("thm{", str(result.output))
102 |
103 |
104 | def test_file_fixture7():
105 | runner = CliRunner()
106 | result = runner.invoke(main, ["-db", "fixtures/file"])
107 | assert result.exit_code == 0
108 | assert re.findall('thm{"', str(result.output))
109 |
110 |
111 | def test_file_fixture8():
112 | runner = CliRunner()
113 | result = runner.invoke(main, ["-db", "fixtures/file"])
114 | assert result.exit_code == 0
115 | assert re.findall("URL", str(result.output))
116 |
117 |
118 | def test_file_fixture9():
119 | runner = CliRunner()
120 | result = runner.invoke(main, ["-db", "fixtures/file"])
121 | assert result.exit_code == 0
122 | assert re.findall("etherscan", str(result.output))
123 |
124 |
125 | def test_file_fixture10():
126 | runner = CliRunner()
127 | result = runner.invoke(main, ["-db", "fixtures/file"])
128 | assert result.exit_code == 0
129 | assert re.findall("dogechain", str(result.output))
130 |
131 |
132 | def test_file_fixture11():
133 | runner = CliRunner()
134 | result = runner.invoke(main, ["-db", "fixtures/file"])
135 | assert result.exit_code == 0
136 | assert re.findall("Dogecoin", str(result.output))
137 |
138 |
139 | def test_file_fixture12():
140 | runner = CliRunner()
141 | result = runner.invoke(main, ["-db", "fixtures/file"])
142 | assert result.exit_code == 0
143 | assert re.findall("Ethereum", str(result.output))
144 |
145 |
146 | def test_file_fixture13():
147 | runner = CliRunner()
148 | result = runner.invoke(main, ["-db", "fixtures/file"])
149 | assert result.exit_code == 0
150 | assert re.findall("Bitcoin", str(result.output))
151 |
152 |
153 | def test_file_fixture14():
154 | runner = CliRunner()
155 | result = runner.invoke(main, ["-db", "fixtures/file"])
156 | assert result.exit_code == 0
157 | assert re.findall("Nano", str(result.output))
158 |
159 |
160 | def test_arg_parsing():
161 | runner = CliRunner()
162 | result = runner.invoke(main, ["-db", "1KFHE7w8BhaENAswwryaoccDb6qcT6DbYY"])
163 | assert result.exit_code == 0
164 | assert re.findall("blockchain", str(result.output))
165 |
166 |
167 | def test_arg_parsing2():
168 | runner = CliRunner()
169 | result = runner.invoke(main, ["http://10.1.1.1"])
170 | assert result.exit_code == 0
171 | assert re.findall("Internet Protocol", str(result.output))
172 |
173 |
174 | def test_file_fixture_visa():
175 | runner = CliRunner()
176 | result = runner.invoke(main, ["-db", "fixtures/file"])
177 | assert result.exit_code == 0
178 | assert re.findall("Visa", str(result.output))
179 |
180 |
181 | def test_file_fixture_master_card():
182 | runner = CliRunner()
183 | result = runner.invoke(main, ["-db", "fixtures/file"])
184 | assert result.exit_code == 0
185 | assert re.findall("MasterCard", str(result.output))
186 |
187 |
188 | def test_file_fixture_master_amex():
189 | runner = CliRunner()
190 | result = runner.invoke(main, ["-db", "fixtures/file"])
191 | assert result.exit_code == 0
192 | assert re.findall("American Express", str(result.output))
193 |
194 |
195 | def test_file_fixture_master_diners():
196 | runner = CliRunner()
197 | result = runner.invoke(main, ["-db", "fixtures/file"])
198 | assert result.exit_code == 0
199 | assert re.findall("Diners Club Card", str(result.output))
200 |
201 |
202 | def test_file_fixture_discover():
203 | runner = CliRunner()
204 | result = runner.invoke(main, ["-db", "fixtures/file"])
205 | assert result.exit_code == 0
206 | assert re.findall("Discover", str(result.output))
207 |
208 |
209 | @pytest.mark.skip("Key:value turned off")
210 | def test_file_fixture_usernamepassword():
211 | runner = CliRunner()
212 | result = runner.invoke(main, ["-db", "fixtures/file"])
213 | assert result.exit_code == 0
214 | assert re.findall("Key", str(result.output))
215 |
216 |
217 | def test_file_fixture_email():
218 | runner = CliRunner()
219 | result = runner.invoke(main, ["-db", "fixtures/file"])
220 | assert result.exit_code == 0
221 | assert re.findall("Email", str(result.output))
222 |
223 |
224 | def test_file_fixture_email2():
225 | runner = CliRunner()
226 | result = runner.invoke(main, ["-db", "firstname+lastname@example.com"])
227 | assert result.exit_code == 0
228 | assert re.findall("Email", str(result.output))
229 |
230 |
231 | def test_file_fixture_phone_number():
232 | runner = CliRunner()
233 | result = runner.invoke(main, ["fixtures/file"])
234 | assert result.exit_code == 0
235 | assert re.findall("Phone Number", str(result.output))
236 |
237 |
238 | def test_file_fixture_youtube():
239 | runner = CliRunner()
240 | result = runner.invoke(main, ["-db", "fixtures/file"])
241 | assert result.exit_code == 0
242 | assert re.findall("YouTube", str(result.output))
243 |
244 |
245 | def test_file_fixture_youtube_id():
246 | runner = CliRunner()
247 | result = runner.invoke(main, ["-db", "fixtures/file"])
248 | assert result.exit_code == 0
249 | assert re.findall("YouTube", str(result.output))
250 |
251 |
252 | def test_file_fixture_ip4():
253 | runner = CliRunner()
254 | result = runner.invoke(main, ["-db", "118.103.238.230"])
255 | assert result.exit_code == 0
256 | assert re.findall("Address Version 4", str(result.output))
257 |
258 |
259 | def test_file_fixture_ip4_shodan():
260 | runner = CliRunner()
261 | result = runner.invoke(main, ["-db", "118.103.238.230"])
262 | assert result.exit_code == 0
263 | assert re.findall("shodan", str(result.output))
264 |
265 |
266 | def test_file_fixture_ip6():
267 | runner = CliRunner()
268 | result = runner.invoke(main, ["-db", "2001:0db8:85a3:0000:0000:8a2e:0370:7334"])
269 | assert result.exit_code == 0
270 | assert re.findall("Address Version 6", str(result.output))
271 |
272 |
273 | def test_file_fixture_ip6_shodan():
274 | runner = CliRunner()
275 | result = runner.invoke(main, ["-db", "2001:0db8:85a3:0000:0000:8a2e:0370:7334"])
276 | assert result.exit_code == 0
277 | assert re.findall("shodan", str(result.output))
278 |
279 |
280 | def test_file_fixture_ssn():
281 | runner = CliRunner()
282 | result = runner.invoke(main, ["-db", "fixtures/file"])
283 | assert result.exit_code == 0
284 | assert re.findall("Social", str(result.output))
285 |
286 |
287 | @pytest.mark.skip("Key:value turned off")
288 | def test_file_pcap():
289 | runner = CliRunner()
290 | result = runner.invoke(main, ["-db", "fixtures/FollowTheLeader.pcap"])
291 | assert result.exit_code == 0
292 | assert re.findall("Host:", str(result.output))
293 |
294 |
295 | def test_file_coords():
296 | runner = CliRunner()
297 | result = runner.invoke(main, ["-db", "52.6169586, -1.9779857"])
298 | assert result.exit_code == 0
299 | assert re.findall("Latitude", str(result.output))
300 |
301 |
302 | def test_file_fixture_ltc():
303 | runner = CliRunner()
304 | result = runner.invoke(main, ["-db", "fixtures/file"])
305 | assert result.exit_code == 0
306 | assert re.findall("Litecoin", str(result.output))
307 |
308 |
309 | def test_file_fixture_ltc2():
310 | runner = CliRunner()
311 | result = runner.invoke(main, ["-db", "fixtures/file"])
312 | assert result.exit_code == 0
313 | assert re.findall("live.block", str(result.output))
314 |
315 |
316 | def test_file_fixture_bch():
317 | runner = CliRunner()
318 | result = runner.invoke(main, ["-db", "fixtures/file"])
319 | assert result.exit_code == 0
320 | assert re.findall("Bitcoin Cash", str(result.output))
321 |
322 |
323 | def test_file_fixture_bch2():
324 | runner = CliRunner()
325 | result = runner.invoke(
326 | main, ["-db", "bitcoincash:qzlg6uvceehgzgtz6phmvy8gtdqyt6vf359at4n3lq"]
327 | )
328 | assert result.exit_code == 0
329 | assert re.findall("blockchain", str(result.output))
330 |
331 |
332 | def test_file_fixture_xrp():
333 | runner = CliRunner()
334 | result = runner.invoke(main, ["-db", "fixtures/file"])
335 | assert result.exit_code == 0
336 | assert re.findall("Ripple", str(result.output))
337 |
338 |
339 | def test_file_fixture_xrp2():
340 | runner = CliRunner()
341 | result = runner.invoke(main, ["-db", "fixtures/file"])
342 | assert result.exit_code == 0
343 | assert re.findall("xrpscan", str(result.output))
344 |
345 |
346 | def test_file_fixture_xmr():
347 | runner = CliRunner()
348 | result = runner.invoke(main, ["-db", "fixtures/file"])
349 | assert result.exit_code == 0
350 | assert re.findall("Monero", str(result.output))
351 |
352 |
353 | def test_file_fixture_doi():
354 | runner = CliRunner()
355 | result = runner.invoke(main, ["-db", "fixtures/file"])
356 | assert result.exit_code == 0
357 | assert re.findall("DOI", str(result.output))
358 |
359 |
360 | def test_file_fixture_mailchimp():
361 | runner = CliRunner()
362 | result = runner.invoke(main, ["-db", "fixtures/file"])
363 | assert result.exit_code == 0
364 | assert re.findall("Mailchimp", str(result.output))
365 |
366 |
367 | def test_file_cors():
368 | runner = CliRunner()
369 | result = runner.invoke(main, ["-db", "Access-Control-Allow: *"])
370 | assert result.exit_code == 0
371 | assert re.findall("Access", str(result.output))
372 |
373 |
374 | def test_file_jwt():
375 | runner = CliRunner()
376 | result = runner.invoke(
377 | main,
378 | [
379 | "-db",
380 | "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c",
381 | ],
382 | )
383 | assert result.exit_code == 0
384 | assert re.findall("JWT", str(result.output))
385 |
386 |
387 | def test_file_s3():
388 | runner = CliRunner()
389 | result = runner.invoke(main, ["-db", "http://s3.amazonaws.com/bucket/"])
390 | assert result.exit_code == 0
391 | assert re.findall("S3", str(result.output))
392 |
393 |
394 | def test_file_s3_2():
395 | runner = CliRunner()
396 | result = runner.invoke(main, ["-db", "s3://bucket/path/key"])
397 | assert result.exit_code == 0
398 | assert re.findall("S3", str(result.output))
399 |
400 |
401 | def test_file_s3_3():
402 | runner = CliRunner()
403 | result = runner.invoke(main, ["-db", "s3://bucket/path/directory/"])
404 | assert result.exit_code == 0
405 | assert re.findall("S3", str(result.output))
406 |
407 |
408 | def test_file_arn():
409 | runner = CliRunner()
410 | result = runner.invoke(
411 | main, ["-db", "arn:partition:service:region:account-id:resource"]
412 | )
413 | assert result.exit_code == 0
414 | assert re.findall("ARN", str(result.output))
415 |
416 |
417 | def test_file_arn2():
418 | runner = CliRunner()
419 | result = runner.invoke(
420 | main, ["-db", "arn:partition:service:region:account-id:resourcetype/resource"]
421 | )
422 | assert result.exit_code == 0
423 | assert re.findall("ARN", str(result.output))
424 |
425 |
426 | def test_file_arn3():
427 | runner = CliRunner()
428 | result = runner.invoke(
429 | main, ["-db", "arn:partition:service:region:account-id:resourcetype:resource"]
430 | )
431 | assert result.exit_code == 0
432 | assert re.findall("ARN", str(result.output))
433 |
434 |
435 | def test_file_arn4():
436 | runner = CliRunner()
437 | result = runner.invoke(
438 | main, ["-db", "arn:aws:s3:::my_corporate_bucket/Development/*"]
439 | )
440 | assert result.exit_code == 0
441 | assert re.findall("ARN", str(result.output))
442 |
443 |
444 | def test_key_value_min_rarity_0():
445 | runner = CliRunner()
446 | result = runner.invoke(main, ["-db", "--rarity", "0:", "key:value"])
447 | assert result.exit_code == 0
448 | assert re.findall("Key:Value", str(result.output))
449 |
450 |
451 | def test_key_value_min_rarity_0_1():
452 | runner = CliRunner()
453 | result = runner.invoke(main, ["-db", "--rarity", "0:", "key : value"])
454 | assert result.exit_code == 0
455 | assert re.findall("Key:Value", str(result.output))
456 |
457 |
458 | def test_key_value_min_rarity_0_2():
459 | runner = CliRunner()
460 | result = runner.invoke(main, ["-db", "--rarity", "0:", "key: value"])
461 | assert result.exit_code == 0
462 | assert re.findall("Key:Value", str(result.output))
463 |
464 |
465 | def test_key_value_min_rarity_0_3():
466 | runner = CliRunner()
467 | result = runner.invoke(main, ["-db", "--rarity", "0:", ":a:"])
468 | assert result.exit_code == 0
469 | assert not re.findall("Key:Value", str(result.output))
470 |
471 |
472 | def test_key_value_min_rarity_0_4():
473 | runner = CliRunner()
474 | result = runner.invoke(main, ["-db", "--rarity", "0:", ":::::"])
475 | assert result.exit_code == 0
476 | assert not re.findall("Key:Value", str(result.output))
477 |
478 |
479 | def test_key_value_min_rarity_0_5():
480 | runner = CliRunner()
481 | result = runner.invoke(main, ["-db", "--rarity", "0:", "a:b:c"])
482 | assert result.exit_code == 0
483 | assert not re.findall("a:b:c", str(result.output))
484 |
485 |
486 | def test_key_value_min_rarity_0_6():
487 | runner = CliRunner()
488 | result = runner.invoke(
489 | main, ["--rarity", "0:", "--boundaryless-rarity", "0:", "a:b:c"]
490 | )
491 | assert result.exit_code == 0
492 | assert re.findall("a:b", str(result.output))
493 |
494 |
495 | def test_key_value_min_rarity_0_7():
496 | runner = CliRunner()
497 | result = runner.invoke(
498 | main, ["--rarity", "0:", "--boundaryless-rarity", "0:", "a : b:c"]
499 | )
500 | assert result.exit_code == 0
501 | assert re.findall("a : b", str(result.output))
502 |
503 |
504 | def test_only_text():
505 | runner = CliRunner()
506 | result = runner.invoke(main, ["-o", "-db", "fixtures/file"])
507 | assert result.exit_code == 0
508 | assert "Nothing found" in result.output
509 |
510 |
511 | def test_boundaryless():
512 | runner = CliRunner()
513 | result = runner.invoke(main, ["-be", "identifiers, token", "abc118.103.238.230abc"])
514 | assert result.exit_code == 0
515 | assert "Nothing found" in result.output
516 |
517 |
518 | def test_boundaryless2():
519 | runner = CliRunner()
520 | result = runner.invoke(main, ["-bi", "media", "abc118.103.238.230abc"])
521 | assert result.exit_code == 0
522 | assert "Nothing found" in result.output
523 |
524 |
525 | def test_boundaryless3():
526 | runner = CliRunner()
527 | result = runner.invoke(main, ["-db", "abc118.103.238.230abc"])
528 | assert result.exit_code == 0
529 | assert "Nothing found" in result.output
530 |
531 |
532 | def test_ssh_rsa_key():
533 | runner = CliRunner()
534 | result = runner.invoke(main, ["-db", "fixtures/file"])
535 | assert result.exit_code == 0
536 | assert re.findall("SSH RSA", str(result.output))
537 |
538 |
539 | def test_ssh_ecdsa_key():
540 | runner = CliRunner()
541 | result = runner.invoke(main, ["-db", "fixtures/file"])
542 | assert result.exit_code == 0
543 | assert re.findall("SSH ECDSA", str(result.output))
544 |
545 |
546 | def test_ssh_ed25519_key():
547 | runner = CliRunner()
548 | result = runner.invoke(main, ["-db", "fixtures/file"])
549 | assert result.exit_code == 0
550 | assert re.findall("SSH ED25519", str(result.output))
551 |
552 |
553 | def test_asin():
554 | runner = CliRunner()
555 | result = runner.invoke(main, ["-db", "fixtures/file"])
556 | assert result.exit_code == 0
557 | assert re.findall("ASIN", str(result.output))
558 |
559 |
560 | def test_mac():
561 | runner = CliRunner()
562 | result = runner.invoke(main, ["-db", "fixtures/file"])
563 | assert result.exit_code == 0
564 | assert re.findall("de:ad:be:ef:ca:fe", str(result.output))
565 | assert re.findall("DE:AD:BE:EF:CA:FE", str(result.output))
566 |
567 |
568 | def test_mac_tags():
569 | runner = CliRunner()
570 | result = runner.invoke(
571 | main,
572 | ["--include", "Identifiers,Networking", "-db", "fixtures/file"],
573 | )
574 | assert result.exit_code == 0
575 | assert "Ethernet" in result.output
576 | assert "IP" in result.output
577 |
578 |
579 | def test_pgp_public_key():
580 | runner = CliRunner()
581 | result = runner.invoke(main, ["-db", "fixtures/file"])
582 | assert result.exit_code == 0
583 | assert re.findall("PGP Public Key", str(result.output))
584 |
585 |
586 | def test_pgp_private_key():
587 | runner = CliRunner()
588 | result = runner.invoke(main, ["-db", "fixtures/file"])
589 | assert result.exit_code == 0
590 | assert re.findall("PGP Private Key", str(result.output))
591 |
592 |
593 | def test_file_fixture_turkish_car_plate():
594 | runner = CliRunner()
595 | result = runner.invoke(main, ["--rarity", "0:", "fixtures/file"])
596 | assert result.exit_code == 0
597 | assert re.findall("Turkish License Plate Number", str(result.output))
598 |
599 |
600 | def test_file_fixture_date_of_birth():
601 | runner = CliRunner()
602 | result = runner.invoke(main, ["-db", "fixtures/file"])
603 | assert result.exit_code == 0
604 | assert re.findall("Date of Birth", str(result.output))
605 |
606 |
607 | def test_file_fixture_turkish_id_number():
608 | runner = CliRunner()
609 | result = runner.invoke(main, ["-db", "fixtures/file"])
610 | assert result.exit_code == 0
611 | assert re.findall("Turkish Identification Number", str(result.output))
612 |
613 |
614 | def test_file_fixture_turkish_tax_number():
615 | runner = CliRunner()
616 | result = runner.invoke(main, ["--rarity", "0:", "fixtures/file"])
617 | assert result.exit_code == 0
618 | assert re.findall("Turkish Tax Number", str(result.output))
619 |
620 |
621 | def test_file_fixture_uuid():
622 | runner = CliRunner()
623 | result = runner.invoke(main, ["fixtures/file"])
624 | assert result.exit_code == 0
625 | assert re.findall("UUID", str(result.output))
626 |
627 |
628 | def test_file_fixture_objectid():
629 | runner = CliRunner()
630 | result = runner.invoke(main, ["--rarity", "0:", "fixtures/file"])
631 | assert result.exit_code == 0
632 | assert re.findall("ObjectID", str(result.output))
633 |
634 |
635 | def test_file_fixture_ulid():
636 | runner = CliRunner()
637 | result = runner.invoke(main, ["--rarity", "0:", "fixtures/file"])
638 | assert result.exit_code == 0
639 | assert re.findall("ULID", str(result.output))
640 |
641 |
642 | def test_file_fixture_totp_URI():
643 | runner = CliRunner()
644 | result = runner.invoke(main, ["fixtures/file"])
645 | assert result.exit_code == 0
646 | assert re.findall("Time-Based One-Time Password [(]TOTP[)] URI", str(result.output))
647 |
648 |
649 | def test_file_fixture_sshpass():
650 | runner = CliRunner()
651 | result = runner.invoke(main, ["fixtures/file"])
652 | assert result.exit_code == 0
653 | assert re.findall("SSHPass Clear Password Argument", str(result.output))
654 |
655 |
656 | def test_file_fixture_slack_webhook():
657 | runner = CliRunner()
658 | result = runner.invoke(main, ["fixtures/file"])
659 | assert result.exit_code == 0
660 | assert re.findall("Slack Webhook", str(result.output))
661 |
662 |
663 | def test_file_fixture_discord_webhook():
664 | runner = CliRunner()
665 | result = runner.invoke(main, ["fixtures/file"])
666 | assert result.exit_code == 0
667 | assert re.findall("Discord Webhook", str(result.output))
668 |
669 |
670 | def test_file_fixture_guilded_webhook():
671 | runner = CliRunner()
672 | result = runner.invoke(main, ["fixtures/file"])
673 | assert result.exit_code == 0
674 | assert re.findall("Guilded Webhook", str(result.output))
675 |
676 |
677 | def test_format():
678 | runner = CliRunner()
679 | result = runner.invoke(
680 | main, ["-db", "--format", " json ", "rBPAQmwMrt7FDDPNyjwFgwSqbWZPf6SLkk"]
681 | )
682 | assert result.exit_code == 0
683 | assert '"File Signatures":' in result.output
684 |
685 |
686 | def test_format2():
687 | runner = CliRunner()
688 | result = runner.invoke(
689 | main, ["-db", "--format", " pretty ", "rBPAQmwMrt7FDDPNyjwFgwSqbWZPf6SLkk"]
690 | )
691 | assert result.exit_code == 0
692 | assert "Possible Identification" in result.output
693 |
694 |
695 | def test_format3():
696 | runner = CliRunner()
697 | result = runner.invoke(
698 | main,
699 | [
700 | "-db",
701 | "--format",
702 | r"%m 2%n %d --- -%e%r %l %t \%d",
703 | "rBPAQmwMrt7FDDPNyjwFgwSqbWZPf6SLkk",
704 | ],
705 | )
706 | assert result.exit_code == 0
707 | assert (
708 | "rBPAQmwMrt7FDDPNyjwFgwSqbWZPf6SLkk 2Ripple (XRP) Wallet Address --- -0.3 https://xrpscan.com/account/rBPAQmwMrt7FDDPNyjwFgwSqbWZPf6SLkk Finance, Cryptocurrency Wallet, Ripple Wallet, Ripple, XRP %d"
709 | in result.output.replace("\n", "")
710 | )
711 |
712 |
713 | def test_format4():
714 | runner = CliRunner()
715 | result = runner.invoke(
716 | main,
717 | [
718 | "-db",
719 | "--include",
720 | "Bug Bounty",
721 | "--format",
722 | r"\\%e %l %z",
723 | "heroku00000000-0000-0000-0000-000000000000",
724 | ],
725 | )
726 | assert result.exit_code == 0
727 | assert (
728 | '\\Use the command below to verify that the API key is valid:\n $ curl -X POST https://api.heroku.com/apps -H "Accept: application/vnd.heroku+json; version=3" -H "Authorization: Bearer heroku00000000-0000-0000-0000-000000000000"\n %z'.split()
729 | == result.output.split()
730 | )
731 |
732 |
733 | def test_format5():
734 | runner = CliRunner()
735 | result = runner.invoke(main, ["-db", "--format", r"%e", "thm{2}"])
736 | assert result.exit_code == 0
737 | assert len(result.output) == 0
738 |
739 |
740 | def test_print_tags():
741 | runner = CliRunner()
742 | result = runner.invoke(main, ["-db", "-pt", "thm{2}"])
743 | assert result.exit_code == 0
744 | assert "Tags: CTF Flag" in result.output
745 |
746 |
747 | def test_print_tags2():
748 | runner = CliRunner()
749 | result = runner.invoke(
750 | main, ["-db", "--print-tags", "--format", "pretty", "thm{2}"]
751 | )
752 | assert result.exit_code == 0
753 | assert "Tags: CTF Flag" in result.output
754 |
--------------------------------------------------------------------------------
/tests/test_filtration.py:
--------------------------------------------------------------------------------
1 | import pytest
2 |
3 | from pywhat import Distribution, Filter, pywhat_tags
4 | from pywhat.helper import CaseInsensitiveSet, InvalidTag, load_regexes
5 |
6 | regexes = load_regexes()
7 |
8 |
9 | @pytest.mark.skip(
10 | "Dist.get_regexes() returns the regex list with the default filter of 0.1:1. \
11 | load_regexes() returns all regex without that filter. \
12 | This fails because one of them is filtered and the other is not."
13 | )
14 | def test_distribution():
15 | dist = Distribution()
16 | assert regexes == dist.get_regexes()
17 |
18 |
19 | def test_distribution2():
20 | filter = {
21 | "MinRarity": 0.3,
22 | "MaxRarity": 0.8,
23 | "Tags": ["Networking"],
24 | "ExcludeTags": ["Identifiers"],
25 | }
26 | dist = Distribution(filter)
27 | for regex in regexes:
28 | if (
29 | 0.3 <= regex["Rarity"] <= 0.8
30 | and "Networking" in regex["Tags"]
31 | and "Identifiers" not in regex["Tags"]
32 | ):
33 | assert regex in dist.get_regexes()
34 |
35 |
36 | def test_distribution3():
37 | filter1 = {"MinRarity": 0.3, "Tags": ["Networking"], "ExcludeTags": ["Identifiers"]}
38 | filter2 = {"MinRarity": 0.4, "MaxRarity": 0.8, "ExcludeTags": ["Media"]}
39 | dist = Distribution(filter1) & Distribution(filter2)
40 | assert dist._dict["MinRarity"] == 0.4
41 | assert dist._dict["MaxRarity"] == 0.8
42 | assert dist._dict["Tags"] == CaseInsensitiveSet(["Networking"])
43 | assert dist._dict["ExcludeTags"] == CaseInsensitiveSet()
44 |
45 | for regex in regexes:
46 | if 0.4 <= regex["Rarity"] <= 0.8 and "Networking" in regex["Tags"]:
47 | assert regex in dist.get_regexes()
48 |
49 |
50 | def test_distribution4():
51 | filter1 = {"MinRarity": 0.3, "Tags": ["Networking"], "ExcludeTags": ["Identifiers"]}
52 | filter2 = {"MinRarity": 0.4, "MaxRarity": 0.8, "ExcludeTags": ["Media"]}
53 | dist = Distribution(filter2)
54 | dist &= Distribution(filter1)
55 | assert dist._dict["MinRarity"] == 0.4
56 | assert dist._dict["MaxRarity"] == 0.8
57 | assert dist._dict["Tags"] == CaseInsensitiveSet(["Networking"])
58 | assert dist._dict["ExcludeTags"] == CaseInsensitiveSet()
59 |
60 | for regex in regexes:
61 | if 0.4 <= regex["Rarity"] <= 0.8 and "Networking" in regex["Tags"]:
62 | assert regex in dist.get_regexes()
63 |
64 |
65 | def test_distribution5():
66 | filter1 = {"MinRarity": 0.3, "Tags": ["Networking"], "ExcludeTags": ["Identifiers"]}
67 | filter2 = {"MinRarity": 0.4, "MaxRarity": 0.8, "ExcludeTags": ["Media"]}
68 | dist = Distribution(filter1) | Distribution(filter2)
69 | assert dist._dict["MinRarity"] == 0.3
70 | assert dist._dict["MaxRarity"] == 1
71 | assert dist._dict["Tags"] == CaseInsensitiveSet(pywhat_tags)
72 | assert dist._dict["ExcludeTags"] == CaseInsensitiveSet(["Identifiers", "Media"])
73 |
74 | for regex in regexes:
75 | if (
76 | 0.3 <= regex["Rarity"] <= 1
77 | and "Identifiers" not in regex["Tags"]
78 | and "Media" not in regex["Tags"]
79 | ):
80 | assert regex in dist.get_regexes()
81 |
82 |
83 | def test_distribution6():
84 | filter1 = {"MinRarity": 0.3, "Tags": ["Networking"], "ExcludeTags": ["Identifiers"]}
85 | filter2 = {"MinRarity": 0.4, "MaxRarity": 0.8, "ExcludeTags": ["Media"]}
86 | dist = Distribution(filter2)
87 | dist |= Distribution(filter1)
88 | assert dist._dict["MinRarity"] == 0.3
89 | assert dist._dict["MaxRarity"] == 1
90 | assert dist._dict["Tags"] == CaseInsensitiveSet(pywhat_tags)
91 | assert dist._dict["ExcludeTags"] == CaseInsensitiveSet(["Identifiers", "Media"])
92 |
93 | for regex in regexes:
94 | if (
95 | 0.3 <= regex["Rarity"] <= 1
96 | and "Identifiers" not in regex["Tags"]
97 | and "Media" not in regex["Tags"]
98 | ):
99 | assert regex in dist.get_regexes()
100 |
101 |
102 | def test_distribution7():
103 | with pytest.raises(InvalidTag):
104 | Distribution({"Tags": "Media", "MinRarity": 0.7})
105 |
106 |
107 | def test_filter():
108 | filter = {
109 | "MinRarity": 0.3,
110 | "MaxRarity": 0.8,
111 | "Tags": ["Networking"],
112 | "ExcludeTags": ["Identifiers"],
113 | }
114 | filt = Filter(filter)
115 | assert filt["MinRarity"] == 0.3
116 | assert filt["MaxRarity"] == 0.8
117 | assert filt["Tags"] == CaseInsensitiveSet(["networking"])
118 | assert filt["ExcludeTags"] == CaseInsensitiveSet(["identifiers"])
119 |
120 |
121 | def test_filter2():
122 | filter1 = {
123 | "MinRarity": 0.3,
124 | "MaxRarity": 0.8,
125 | "Tags": ["Networking"],
126 | "ExcludeTags": ["Identifiers"],
127 | }
128 | filter2 = {"MinRarity": 0.5, "Tags": ["Networking", "Identifiers"]}
129 | filt = Filter(filter1) & Filter(filter2)
130 | assert filt["MinRarity"] == 0.5
131 | assert filt["MaxRarity"] == 0.8
132 | assert filt["Tags"] == CaseInsensitiveSet(["networking"])
133 | assert filt["ExcludeTags"] == CaseInsensitiveSet([])
134 |
135 |
136 | def test_filter3():
137 | filter = {
138 | "MinRarity": 0.3,
139 | "MaxRarity": 0.8,
140 | "Tags": ["Networking"],
141 | "ExcludeTags": ["Identifiers"],
142 | }
143 | filt = Filter(filter)
144 | dist = Distribution(filt)
145 | for regex in regexes:
146 | if (
147 | 0.3 <= regex["Rarity"] <= 0.8
148 | and "Networking" in regex["Tags"]
149 | and "Identifiers" not in regex["Tags"]
150 | ):
151 | assert regex in dist.get_regexes()
152 |
--------------------------------------------------------------------------------
/tests/test_identifier.py:
--------------------------------------------------------------------------------
1 | import re
2 |
3 | from pywhat import identifier
4 | from pywhat.filter import Distribution, Filter
5 | from pywhat.helper import Keys
6 |
7 | r = identifier.Identifier()
8 |
9 |
10 | def test_identifier_works():
11 | out = r.identify("DANHz6EQVoWyZ9rER56DwTXHWUxfkv9k2o")
12 | assert (
13 | "Dogecoin (DOGE) Wallet Address"
14 | in out["Regexes"]["text"][0]["Regex Pattern"]["Name"]
15 | )
16 |
17 |
18 | def test_identifier_works2():
19 | out = r.identify("fixtures/file", only_text=False)
20 | assert "Ethereum (ETH) Wallet Address" in str(out)
21 |
22 |
23 | def test_identifier_works3():
24 | out = r.identify("fixtures/file", only_text=False)
25 | assert "Dogecoin (DOGE) Wallet Address" in str(out)
26 |
27 |
28 | def test_identifier_filtration():
29 | filter = {"Tags": ["Credentials"]}
30 | r = identifier.Identifier(dist=Distribution(filter))
31 | regexes = r.identify("fixtures/file", only_text=False)["Regexes"]["file"]
32 | for regex in regexes:
33 | assert "Credentials" in regex["Regex Pattern"]["Tags"]
34 |
35 |
36 | def test_identifier_filtration2():
37 | filter1 = {"ExcludeTags": ["Identifiers"]}
38 | filter2 = {"Tags": ["Identifiers"], "MinRarity": 0.6}
39 | r = identifier.Identifier(dist=Distribution(filter1))
40 | regexes = r.identify("fixtures/file", only_text=False, dist=Distribution(filter2))[
41 | "Regexes"
42 | ]["file"]
43 | for regex in regexes:
44 | assert "Identifiers" in regex["Regex Pattern"]["Tags"]
45 | assert regex["Regex Pattern"]["Rarity"] >= 0.6
46 |
47 |
48 | def test_identifier_sorting():
49 | r = identifier.Identifier(key=Keys.NAME, reverse=True)
50 | out = r.identify("fixtures/file", only_text=False)
51 | assert out["Regexes"]["file"]
52 |
53 |
54 | def test_identifier_sorting2():
55 | out = r.identify("fixtures/file", only_text=False, key=Keys.RARITY, reverse=True)
56 | prev = None
57 | for match in out["Regexes"]["file"]:
58 | if prev is not None:
59 | assert prev >= match["Regex Pattern"]["Rarity"]
60 | prev = match["Regex Pattern"]["Rarity"]
61 |
62 |
63 | def test_identifier_sorting3():
64 | out = r.identify("fixtures/file", only_text=False, key=Keys.NAME)
65 | prev = None
66 | for match in out["Regexes"]["file"]:
67 | if prev is not None:
68 | assert prev <= match["Regex Pattern"]["Name"]
69 | prev = match["Regex Pattern"]["Name"]
70 |
71 |
72 | def test_identifier_sorting4():
73 | r = identifier.Identifier(key=Keys.NAME, reverse=True)
74 | out = r.identify("fixtures/file", only_text=False)
75 | prev = None
76 | for match in out["Regexes"]["file"]:
77 | if prev is not None:
78 | assert prev >= match["Regex Pattern"]["Name"]
79 | prev = match["Regex Pattern"]["Name"]
80 |
81 |
82 | def test_identifier_sorting5():
83 | out = r.identify("fixtures/file", only_text=False, key=Keys.MATCHED)
84 | prev = None
85 | for match in out["Regexes"]["file"]:
86 | if prev is not None:
87 | assert prev <= match["Matched"]
88 | prev = match["Matched"]
89 |
90 |
91 | def test_identifier_sorting6():
92 | out = r.identify("fixtures/file", only_text=False, key=Keys.MATCHED, reverse=True)
93 | prev = None
94 | for match in out["Regexes"]["file"]:
95 | if prev is not None:
96 | assert prev >= match["Matched"]
97 | prev = match["Matched"]
98 |
99 |
100 | def test_only_text():
101 | out = r.identify("fixtures/file")
102 | assert out["Regexes"] is None
103 |
104 | out = r.identify("THM{7281j}}", only_text=True)
105 | assert "TryHackMe Flag Format" in out["Regexes"]["text"][0]["Regex Pattern"]["Name"]
106 |
107 |
108 | def test_recursion():
109 | out = r.identify("fixtures", only_text=False)
110 |
111 | assert re.findall(r"\'(?:\/|\\\\)file\'", str(list(out["Regexes"].keys())))
112 | assert re.findall(
113 | r"\'(?:\/|\\\\)test(?:\/|\\\\)file\'", str(list(out["Regexes"].keys()))
114 | )
115 |
116 |
117 | def test_boundaryless():
118 | r = identifier.Identifier(boundaryless=Filter())
119 | out = r.identify("127.0.0.1abrakadabra")
120 | assert (
121 | "Internet Protocol (IP) Address Version 4"
122 | in out["Regexes"]["text"][0]["Regex Pattern"]["Name"]
123 | )
124 | out = r.identify("127.0.0.1abrakadabra", boundaryless=Filter({"Tags": ["Media"]}))
125 | assert out["Regexes"] is None
126 |
127 |
128 | def test_finditer():
129 | r = identifier.Identifier(boundaryless=Filter())
130 | out = r.identify("anon@random.org dad@gmail.com")
131 | assert "anon@random.org" in out["Regexes"]["text"][2]["Matched"]
132 | assert "dad@gmail.com" in out["Regexes"]["text"][3]["Matched"]
133 |
--------------------------------------------------------------------------------
/tests/test_regex_database.py:
--------------------------------------------------------------------------------
1 | import re
2 |
3 | import pytest
4 |
5 | from pywhat.helper import load_regexes
6 |
7 | database = load_regexes()
8 |
9 |
10 | @pytest.mark.skip(
11 | reason="Not all regex have tests now, check https://github.com/bee-san/pyWhat/pull/146#issuecomment-927087231 for info."
12 | )
13 | def test_if_all_tests_exist():
14 | with open("tests/test_regex_identifier.py", "r", encoding="utf-8") as file:
15 | tests = file.read()
16 |
17 | for regex in database:
18 | assert (
19 | regex["Name"] in tests
20 | ), "No test for this regex found in 'test_regex_identifier.py'. Note that a test needs to assert the whole name."
21 |
22 |
23 | def test_name_capitalization():
24 | for entry in database:
25 | entry_name = entry["Name"]
26 | for word in entry_name.split():
27 | upper_and_num_count = sum(1 for c in word if c.isupper() or c.isnumeric())
28 | if upper_and_num_count > 0:
29 | continue
30 | cleaned_word = word.translate({ord(c): None for c in "(),."})
31 | if cleaned_word in ["a", "of", "etc"]:
32 | continue
33 |
34 | assert word.title() == word, (
35 | f'Wrong capitalization in regex name: "{entry_name}"\n'
36 | f'Expected: "{entry_name.title()}"\n'
37 | "Please capitalize the first letter of each word."
38 | )
39 |
40 |
41 | def test_regex_format():
42 | for regex in database:
43 | assert re.findall(
44 | r"^(?:\(\?i\))?\^\(.*\)\$$", regex["Regex"]
45 | ), r"Please use ^(regex)$ regex format. If there is '\n' character, you have to escape it. If there is '(?i)', it is allowed and should be before the '^'."
46 |
47 | assert (
48 | re.findall(r"\^\||\|\^|\$\|\^|\$\||\|\$", regex["Regex"]) == []
49 | ), "Remove in-between boundaries. For example, '^|$' should only be '|'."
50 |
51 |
52 | def test_check_keys():
53 | for entry in database:
54 | for key in [
55 | "Name",
56 | "Regex",
57 | "plural_name",
58 | "Description",
59 | "Rarity",
60 | "URL",
61 | "Tags",
62 | # "Examples", # TODO
63 | ]:
64 | assert key in entry, f"{key} is missing in {entry['Name']}"
65 |
66 |
67 | def test_sorted_by_rarity():
68 | rarity_num = [regex["Rarity"] for regex in database]
69 |
70 | assert rarity_num == sorted(
71 | rarity_num, reverse=True
72 | ), "Regexes should be sorted by rarity in 'regex.json'. Regexes with rarity '1' are at the top of the file and '0' is at the bottom."
73 |
74 |
75 | def test_no_duplicate_regexes():
76 | names = [regex["Name"] for regex in database]
77 | duplicate_names = {name for name in names if names.count(name) > 1}
78 | assert duplicate_names == set(), (
79 | ", ".join(duplicate_names) + " present in 'regex.json' more than once."
80 | )
81 |
--------------------------------------------------------------------------------
/tests/test_regex_identifier.py:
--------------------------------------------------------------------------------
1 | import pytest
2 |
3 | from pywhat import regex_identifier
4 | from pywhat.filter import Distribution, Filter
5 | from pywhat.helper import load_regexes
6 |
7 | database = load_regexes()
8 | r = regex_identifier.RegexIdentifier()
9 | dist = Distribution(Filter({"MinRarity": 0.0}))
10 |
11 |
12 | def test_regex_successfully_parses():
13 | regexes = r.distribution.get_regexes()
14 | assert type(regexes) == list
15 | assert len(regexes) != 0
16 | assert all([type(regex) == dict for regex in regexes])
17 |
18 |
19 | def regex_valid_match(name: str, match: str) -> bool:
20 | return any(
21 | name in matched["Regex Pattern"]["Name"]
22 | for matched in r.check([match], dist=dist)
23 | )
24 |
25 |
26 | @pytest.mark.parametrize(
27 | "name,match",
28 | [
29 | (regex["Name"], match)
30 | for regex in database
31 | for match in regex.get("Examples", {}).get("Valid", [])
32 | ],
33 | )
34 | def test_regex_valid_match(name: str, match: str):
35 | assert regex_valid_match(name, match)
36 |
37 |
38 | @pytest.mark.parametrize(
39 | "name,match",
40 | [
41 | (regex["Name"], match)
42 | for regex in database
43 | for match in regex.get("Examples", {}).get("Invalid", [])
44 | ],
45 | )
46 | def test_regex_invalid_match(name: str, match: str):
47 | assert not regex_valid_match(name, match)
48 |
49 |
50 | @pytest.mark.skip(
51 | reason="Fails because not a valid TLD. If presented in punycode, it works."
52 | )
53 | def test_international_url():
54 | assert regex_valid_match(
55 | "Uniform Resource Locator (URL)", r.check(["http://папироска.рф"])
56 | )
57 |
58 |
59 | @pytest.mark.parametrize(
60 | "match, description",
61 | [
62 | # EUI-48 Identifier (Ethernet, WiFi, Bluetooth, etc)
63 | ("00:00:00:00:00:00", "Xerox Corp"),
64 | ("00-00-00-00-00-00", "Xerox Corp"),
65 | ("0000.0000.0000", "Xerox Corp"),
66 | # MasterCard Number
67 | ("5409010000000004", "UNION NATIONAL BANK"),
68 | ("5409 0100 0000 0004", "UNION NATIONAL BANK"),
69 | # Phone Number
70 | ("+1-202-555-0156", "United States"),
71 | ("+662025550156", "Thailand"),
72 | ("+356 202 555 0156", "Malta"),
73 | ],
74 | )
75 | def test_match_description(match: str, description: str):
76 | assert description in r.check([match])[0]["Regex Pattern"]["Description"]
77 |
78 |
79 | @pytest.mark.parametrize(
80 | "match, exploit",
81 | [
82 | (
83 | "xoxp-514654431830-843187921057-792480346180-d44d2r9b71f954o8z2k5llt41ovpip6v",
84 | "https://slack.com/api/auth.test?token=xoxp-514654431830-843187921057-792480346180-d44d2r9b71f954o8z2k5llt41ovpip6v",
85 | ),
86 | (
87 | "xoxb-51465443183-hgvhXVd2ISC2x7gaoRWBOUdQ",
88 | "https://slack.com/api/auth.test?token=xoxb-51465443183-hgvhXVd2ISC2x7gaoRWBOUdQ",
89 | ),
90 | ],
91 | )
92 | def test_match_exploit(match: str, exploit: str):
93 | assert exploit in r.check([match])[0]["Regex Pattern"]["Exploit"]
94 |
--------------------------------------------------------------------------------