Skip to content

Commit fc26990

Browse files
authored
WIP: Add Initial Version (alpha-beta-gamma) (#1)
* Add initial WIP project version * Update src code * Update documentation * Add requirements
1 parent b0589a8 commit fc26990

File tree

22 files changed

+556
-1
lines changed

22 files changed

+556
-1
lines changed

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
# Custom
2+
.idea/
3+
14
# Byte-compiled / optimized / DLL files
25
__pycache__/
36
*.py[cod]

README.md

+61-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,62 @@
11
# osint-framework
2-
:eyes: WIP: All-in-one OSINT Tools
2+
:eyes: All-in-one OSINT/RECON Swiss Knife
3+
4+
## Installing
5+
```bash
6+
virtualenv -p python3 venv
7+
(or python3 -m venv venv)
8+
pip3 install -r requirements.txt
9+
python3 main.py
10+
```
11+
12+
## Create your own script
13+
Use the following structure:
14+
```python3
15+
#!/usr/bin/env python3
16+
17+
# Import any required runner
18+
# 1. OsintRunner - for OSINT scripts
19+
# 2. ReconRunner - for RECON scripts
20+
# 3. BaseRunner - for out-of-scope scripts ("other")
21+
from src.core.base.osint import OsintRunner, BaseRunner, ReconRunner, PossibleKeys
22+
23+
# Import 'ScriptResponse' to return good responses from the module, like
24+
# 1. ScriptResponse.success - if everything is good
25+
# 2. ScriptResponse.error - if everything is bad
26+
from src.core.utils.response import ScriptResponse
27+
28+
# Validate your named arguments. For example, this validator
29+
# will raise 'KeyError' if you will try to put 'hostname' argument
30+
# into the 'OsintRunner' runner, and so on
31+
from src.core.utils.validators import validate_kwargs
32+
33+
# You can use OsintRunner, ReconRunner or BaseRunner as the base class
34+
class Runner(OsintRunner):
35+
"""
36+
Basic script example
37+
"""
38+
39+
def __init__(self, logger: str = __name__):
40+
"""
41+
Re-init base class instance with this function.
42+
Simply put, you need to provide proper logger name
43+
to the parent class, so please, save this structure for
44+
the init function.
45+
:param logger: logger to use (name of _this_ runner by default)
46+
"""
47+
super(Runner, self).__init__(logger)
48+
49+
@validate_kwargs(PossibleKeys.KEYS)
50+
def run(self, *args, **kwargs) -> ScriptResponse.success or ScriptResponse.error:
51+
"""
52+
The main '.run()' function to run your script.
53+
Note: this function is always synchronous, without any
54+
async/await init. You can use 'asyncio.run(...)' here,
55+
but don't put any 'async' before function definition
56+
:param args: args that you provide (not used for now)
57+
:param kwargs: kwargs that you provide (required to run something!)
58+
:return: ScriptResponse message (error or success)
59+
"""
60+
argument = kwargs.get("my_argument", "Arguments were not provided!")
61+
return ScriptResponse.success(message=f"Script finished with argument {argument}")
62+
```

main.py

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
#!/usr/bin/env python3
2+
3+
"""
4+
Main runner.
5+
6+
Please, for all the searches, use the following classes:
7+
'BaseCase', 'OsintCase', 'ReconCase'
8+
"""
9+
10+
11+
from pprint import pprint
12+
13+
from src.core.case.osint import OsintCase
14+
from src.core.case.recon import ReconCase
15+
from src.core.case.base import BaseCase
16+
17+
18+
if __name__ == "__main__":
19+
# Will return 2 results from "other" category scripts
20+
other_case = BaseCase()
21+
other_case.process(
22+
username="johndoe", email="[email protected]", fullname="John Doe",
23+
)
24+
other_case_results = other_case.get_results()
25+
26+
# Will return 1 result from "recon" category scripts
27+
recon_case = ReconCase()
28+
recon_case.process(url="https://facebook.com")
29+
recon_case_results = recon_case.get_results()
30+
31+
# Will return nothing (no scripts for now, sorry!)
32+
osint_case = OsintCase()
33+
osint_case.process(username="any_value_here")
34+
osint_case_results = osint_case.get_results()
35+
36+
# Print out all the results
37+
for result in other_case_results, recon_case_results, osint_case_results:
38+
pprint(result)

requirements.txt

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
certifi==2020.6.20
2+
chardet==3.0.4
3+
idna==2.10
4+
requests==2.24.0
5+
urllib3==1.25.9

src/core/base/base.py

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#!/usr/bin/env python3
2+
3+
"""
4+
Defines base runner
5+
"""
6+
from logging import getLogger
7+
from typing import Any
8+
9+
10+
class BaseRunner:
11+
"""
12+
Defines base runner class to create childs from
13+
"""
14+
15+
def __init__(self, logger: str = __name__):
16+
"""
17+
Initialize the base class
18+
:param logger: logger name
19+
"""
20+
self.log = getLogger(name=logger)
21+
self.log.info("script started")
22+
23+
def run(self, *args, **kwargs) -> Any:
24+
"""
25+
Base run method
26+
:param args: some positional args
27+
:param kwargs: some named args
28+
:return: None in this case (base class)
29+
"""
30+
pass

src/core/base/osint.py

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#!/usr/bin/env python3
2+
3+
"""
4+
Defines base runner for the OSINT scripts
5+
"""
6+
from typing import Any
7+
8+
from src.core.utils.validators import validate_kwargs
9+
from src.core.base.base import BaseRunner
10+
11+
12+
class PossibleKeys:
13+
"""
14+
Defines default values for the function arguments (kwargs, named args)
15+
"""
16+
17+
KEYS = ["email", "username", "fullname", "vk_api_key"]
18+
19+
20+
class OsintRunner(BaseRunner):
21+
def __init__(self, logger: str = __name__):
22+
super(OsintRunner, self).__init__(logger)
23+
24+
@validate_kwargs(PossibleKeys.KEYS)
25+
def run(self, *args, **kwargs) -> Any:
26+
"""
27+
OsintRunner 'run' base implementation
28+
:param args: some positional args
29+
:param kwargs: some named args
30+
:return: None in this case(base class)
31+
"""
32+
pass

src/core/base/recon.py

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#!/usr/bin/env python3
2+
3+
"""
4+
Defines base runner for the RECON scripts
5+
"""
6+
from typing import Any
7+
8+
from src.core.utils.validators import validate_kwargs
9+
from src.core.base.base import BaseRunner
10+
11+
12+
class PossibleKeys:
13+
"""
14+
Defines default values for the function arguments (kwargs, named args)
15+
"""
16+
17+
KEYS = ["host", "hostname", "ip", "url"]
18+
19+
20+
class ReconRunner(BaseRunner):
21+
def __init__(self, logger: str = __name__):
22+
super(ReconRunner, self).__init__(logger)
23+
24+
@validate_kwargs(PossibleKeys.KEYS)
25+
def run(self, *args, **kwargs) -> Any:
26+
"""
27+
ReconRunner 'run' base implementation
28+
:param args: some positional args
29+
:param kwargs: some named args
30+
:return: None in this case(base class)
31+
"""
32+
pass

src/core/case/base.py

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#!/usr/bin/env python3
2+
3+
from src.core.runner.runner import ScriptRunner
4+
5+
6+
class BaseCase:
7+
"""
8+
Defines base search case
9+
"""
10+
11+
def __init__(self, category: str = "other", *args, **kwargs):
12+
"""
13+
Init base
14+
:param category: default category to search
15+
:param args: some args
16+
:param kwargs: some kwargs
17+
"""
18+
self.runner = ScriptRunner()
19+
self.args = args
20+
self.kwargs = kwargs
21+
self.category = category
22+
23+
def process(self, *args, **kwargs) -> dict:
24+
"""
25+
Process results
26+
:param args: some args
27+
:param kwargs: some kwargs
28+
:return: results
29+
"""
30+
_args = args or self.args
31+
_kwargs = kwargs or self.kwargs
32+
self.runner.run_category(category=self.category, *_args, **_kwargs)
33+
return self.runner.get_results()
34+
35+
def get_results(self) -> dict:
36+
"""
37+
Return results
38+
:return: dict with results
39+
"""
40+
return self.runner.get_results()

src/core/case/osint.py

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#!/usr/bin/env python3
2+
3+
from src.core.case.base import BaseCase
4+
5+
6+
class OsintCase(BaseCase):
7+
def __init__(self, *args, **kwargs):
8+
super(OsintCase, self).__init__(category="osint", *args, **kwargs)

src/core/case/recon.py

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#!/usr/bin/env python3
2+
3+
from src.core.case.base import BaseCase
4+
5+
6+
class ReconCase(BaseCase):
7+
def __init__(self, *args, **kwargs):
8+
super(ReconCase, self).__init__(category="recon", *args, **kwargs)

src/core/exceptions/.gitkeep

Whitespace-only changes.

src/core/handlers/.gitkeep

Whitespace-only changes.

src/core/runner/runner.py

+109
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
#!/usr/bin/env python3
2+
3+
"""
4+
Defines basic scripts runner
5+
"""
6+
7+
from concurrent.futures import ThreadPoolExecutor
8+
from functools import partial
9+
from importlib.machinery import SourceFileLoader
10+
from logging import basicConfig, INFO
11+
from pathlib import Path
12+
from types import ModuleType
13+
14+
from src.core.utils.response import ScriptResponse
15+
16+
basicConfig(level=INFO)
17+
18+
19+
class Defaults:
20+
SCRIPTS_BASE = Path("src/scripts/")
21+
22+
23+
class ScriptRunnerPaths:
24+
OSINT = Defaults.SCRIPTS_BASE.joinpath("osint")
25+
RECON = Defaults.SCRIPTS_BASE.joinpath("recon")
26+
CONVERT = Defaults.SCRIPTS_BASE.joinpath("convert")
27+
OTHER = Defaults.SCRIPTS_BASE.joinpath("other")
28+
29+
30+
class ScriptRunner:
31+
def __init__(self):
32+
self.scripts = {}
33+
self.results = {}
34+
35+
def exec_script(
36+
self,
37+
path: str or Path,
38+
script_class: str = "Runner",
39+
function: str = "run",
40+
args: list or None = None,
41+
kwargs: dict or None = None,
42+
) -> ScriptResponse:
43+
"""
44+
Load and exec python script
45+
:param path: name of the script to load
46+
:param script_class: class to initialize when script is started
47+
:param function: name of the function to run from script
48+
:param args: args to pass into the module
49+
:param kwargs: kwargs to pass into the module
50+
:return: result of the function
51+
"""
52+
if args is None:
53+
args = []
54+
if kwargs is None:
55+
kwargs = {}
56+
loader = SourceFileLoader(fullname=script_class, path=str(path))
57+
module = ModuleType(name=loader.name)
58+
loader.exec_module(module)
59+
class_instance = getattr(module, script_class)(logger=path.parent.stem)
60+
try:
61+
result = getattr(class_instance, function)(*args, **kwargs)
62+
except Exception as unexp_err:
63+
result = ScriptResponse.error(message=str(unexp_err))
64+
result.update({"script": Path(path).parent.stem})
65+
return result
66+
67+
def get_scripts(self) -> dict:
68+
"""
69+
Load the dictionary with all of the scripts
70+
:return: dict {'dir':['script1', 'script2', ...]}
71+
"""
72+
for directory in [
73+
ScriptRunnerPaths.OSINT,
74+
ScriptRunnerPaths.RECON,
75+
ScriptRunnerPaths.OTHER,
76+
ScriptRunnerPaths.CONVERT,
77+
]:
78+
self.scripts.update({directory.stem: list()})
79+
for file in directory.glob("*/__main__.py"):
80+
self.scripts[directory.stem].append(file)
81+
return self.scripts
82+
83+
def run_category(self, category: str, *args, **kwargs) -> None:
84+
"""
85+
Run a category with scripts
86+
:return: nothing
87+
"""
88+
if not self.scripts:
89+
self.get_scripts()
90+
futures = []
91+
with ThreadPoolExecutor(max_workers=10) as executor:
92+
for script in self.scripts.get(category, []):
93+
futures.append(
94+
executor.submit(
95+
fn=partial(
96+
self.exec_script, path=script, args=args, kwargs=kwargs
97+
)
98+
)
99+
)
100+
for future in futures:
101+
result = future.result()
102+
self.results.update({result.get("script"): result})
103+
104+
def get_results(self) -> dict:
105+
"""
106+
Return retrieved results
107+
:return:
108+
"""
109+
return self.results

0 commit comments

Comments
 (0)