forensic-cli 1.5.3__tar.gz → 1.6.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {forensic_cli-1.5.3/src/forensic_cli.egg-info → forensic_cli-1.6.0}/PKG-INFO +1 -1
- {forensic_cli-1.5.3 → forensic_cli-1.6.0}/pyproject.toml +2 -2
- forensic_cli-1.6.0/src/browser/api.py +23 -0
- forensic_cli-1.6.0/src/browser/schemas.py +13 -0
- {forensic_cli-1.5.3 → forensic_cli-1.6.0/src/forensic_cli.egg-info}/PKG-INFO +1 -1
- {forensic_cli-1.5.3 → forensic_cli-1.6.0}/src/forensic_cli.egg-info/SOURCES.txt +3 -0
- forensic_cli-1.6.0/src/mail/api.py +19 -0
- forensic_cli-1.6.0/src/mail/schemas.py +12 -0
- {forensic_cli-1.5.3 → forensic_cli-1.6.0}/src/network/api.py +8 -14
- forensic_cli-1.6.0/src/network/schemas.py +16 -0
- forensic_cli-1.5.3/src/browser/api.py +0 -39
- forensic_cli-1.5.3/src/mail/api.py +0 -37
- {forensic_cli-1.5.3 → forensic_cli-1.6.0}/LICENSE +0 -0
- {forensic_cli-1.5.3 → forensic_cli-1.6.0}/LICENSE-GPL +0 -0
- {forensic_cli-1.5.3 → forensic_cli-1.6.0}/README.md +0 -0
- {forensic_cli-1.5.3 → forensic_cli-1.6.0}/setup.cfg +0 -0
- {forensic_cli-1.5.3 → forensic_cli-1.6.0}/src/api/main.py +0 -0
- {forensic_cli-1.5.3 → forensic_cli-1.6.0}/src/api/routers/__init__.py +0 -0
- {forensic_cli-1.5.3 → forensic_cli-1.6.0}/src/api/routers/executions.py +0 -0
- {forensic_cli-1.5.3 → forensic_cli-1.6.0}/src/api/routers/functionalities.py +0 -0
- {forensic_cli-1.5.3 → forensic_cli-1.6.0}/src/api/routers/modules.py +0 -0
- {forensic_cli-1.5.3 → forensic_cli-1.6.0}/src/api/routers/network.py +0 -0
- {forensic_cli-1.5.3 → forensic_cli-1.6.0}/src/api/routers/reports.py +0 -0
- {forensic_cli-1.5.3 → forensic_cli-1.6.0}/src/api/routers/results.py +0 -0
- {forensic_cli-1.5.3 → forensic_cli-1.6.0}/src/api/utils/db.py +0 -0
- {forensic_cli-1.5.3 → forensic_cli-1.6.0}/src/app/__init__.py +0 -0
- {forensic_cli-1.5.3 → forensic_cli-1.6.0}/src/app/main.py +0 -0
- {forensic_cli-1.5.3 → forensic_cli-1.6.0}/src/app/utils/__init__.py +0 -0
- {forensic_cli-1.5.3 → forensic_cli-1.6.0}/src/app/utils/converter.py +0 -0
- {forensic_cli-1.5.3 → forensic_cli-1.6.0}/src/browser/__init__.py +0 -0
- {forensic_cli-1.5.3 → forensic_cli-1.6.0}/src/browser/browser_history.py +0 -0
- {forensic_cli-1.5.3 → forensic_cli-1.6.0}/src/browser/cli.py +0 -0
- {forensic_cli-1.5.3 → forensic_cli-1.6.0}/src/browser/common_words.py +0 -0
- {forensic_cli-1.5.3 → forensic_cli-1.6.0}/src/browser/downloads_history.py +0 -0
- {forensic_cli-1.5.3 → forensic_cli-1.6.0}/src/browser/fav_screen.py +0 -0
- {forensic_cli-1.5.3 → forensic_cli-1.6.0}/src/browser/logins.py +0 -0
- {forensic_cli-1.5.3 → forensic_cli-1.6.0}/src/browser/unusual_patterns.py +0 -0
- {forensic_cli-1.5.3 → forensic_cli-1.6.0}/src/forensic_cli.egg-info/dependency_links.txt +0 -0
- {forensic_cli-1.5.3 → forensic_cli-1.6.0}/src/forensic_cli.egg-info/entry_points.txt +0 -0
- {forensic_cli-1.5.3 → forensic_cli-1.6.0}/src/forensic_cli.egg-info/requires.txt +0 -0
- {forensic_cli-1.5.3 → forensic_cli-1.6.0}/src/forensic_cli.egg-info/top_level.txt +0 -0
- {forensic_cli-1.5.3 → forensic_cli-1.6.0}/src/mail/__init__.py +0 -0
- {forensic_cli-1.5.3 → forensic_cli-1.6.0}/src/mail/cli.py +0 -0
- {forensic_cli-1.5.3 → forensic_cli-1.6.0}/src/mail/email_parser.py +0 -0
- {forensic_cli-1.5.3 → forensic_cli-1.6.0}/src/mail/header_analysis.py +0 -0
- {forensic_cli-1.5.3 → forensic_cli-1.6.0}/src/network/__init__.py +0 -0
- {forensic_cli-1.5.3 → forensic_cli-1.6.0}/src/network/arp_scan.py +0 -0
- {forensic_cli-1.5.3 → forensic_cli-1.6.0}/src/network/cli.py +0 -0
- {forensic_cli-1.5.3 → forensic_cli-1.6.0}/src/network/dns_recon.py +0 -0
- {forensic_cli-1.5.3 → forensic_cli-1.6.0}/src/network/fingerprinting.py +0 -0
- {forensic_cli-1.5.3 → forensic_cli-1.6.0}/src/network/ip_info.py +0 -0
- {forensic_cli-1.5.3 → forensic_cli-1.6.0}/src/network/network_map.py +0 -0
- {forensic_cli-1.5.3 → forensic_cli-1.6.0}/src/network/ping_sweep.py +0 -0
- {forensic_cli-1.5.3 → forensic_cli-1.6.0}/src/network/port_scanner.py +0 -0
- {forensic_cli-1.5.3 → forensic_cli-1.6.0}/src/network/smb_scan.py +0 -0
- {forensic_cli-1.5.3 → forensic_cli-1.6.0}/src/network/snmp_scan.py +0 -0
- {forensic_cli-1.5.3 → forensic_cli-1.6.0}/src/network/traceroute.py +0 -0
- {forensic_cli-1.5.3 → forensic_cli-1.6.0}/src/network/utils.py +0 -0
- {forensic_cli-1.5.3 → forensic_cli-1.6.0}/src/shared/__init__.py +0 -0
- {forensic_cli-1.5.3 → forensic_cli-1.6.0}/src/shared/config.py +0 -0
- {forensic_cli-1.5.3 → forensic_cli-1.6.0}/src/shared/db.py +0 -0
- {forensic_cli-1.5.3 → forensic_cli-1.6.0}/src/shared/describe.py +0 -0
- {forensic_cli-1.5.3 → forensic_cli-1.6.0}/src/shared/exporter.py +0 -0
- {forensic_cli-1.5.3 → forensic_cli-1.6.0}/src/shared/gerar_amostras.py +0 -0
- {forensic_cli-1.5.3 → forensic_cli-1.6.0}/src/shared/logger.py +0 -0
- {forensic_cli-1.5.3 → forensic_cli-1.6.0}/src/shared/orm.py +0 -0
- {forensic_cli-1.5.3 → forensic_cli-1.6.0}/src/shared/registry.py +0 -0
- {forensic_cli-1.5.3 → forensic_cli-1.6.0}/src/shared/schemas.py +0 -0
- {forensic_cli-1.5.3 → forensic_cli-1.6.0}/src/shared/utils_cmd.py +0 -0
- {forensic_cli-1.5.3 → forensic_cli-1.6.0}/tests/test_file_inspector.py +0 -0
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "forensic-cli"
|
|
7
|
-
version = "1.
|
|
7
|
+
version = "1.6.0"
|
|
8
8
|
description = "DevKit Forense - CLI para análise de navegadores e rede"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = {text = "MIT"}
|
|
@@ -123,7 +123,7 @@ pythonpath = ["src"]
|
|
|
123
123
|
|
|
124
124
|
[tool.commitizen]
|
|
125
125
|
name = "cz_conventional_commits"
|
|
126
|
-
version = "1.
|
|
126
|
+
version = "1.6.0"
|
|
127
127
|
version_files = [
|
|
128
128
|
"pyproject.toml:version",
|
|
129
129
|
"src/shared/__init__.py:__version__"
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from fastapi import APIRouter
|
|
2
|
+
|
|
3
|
+
from browser.schemas import BrowserHistoryRequest, BrowserHistoryResponse
|
|
4
|
+
from shared.logger import get_logger
|
|
5
|
+
|
|
6
|
+
logger = get_logger(__name__)
|
|
7
|
+
|
|
8
|
+
router = APIRouter(prefix="/api/browser", tags=["Browser"])
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@router.post("/history", response_model=BrowserHistoryResponse)
|
|
12
|
+
def get_history(request: BrowserHistoryRequest):
|
|
13
|
+
logger.info(
|
|
14
|
+
"API /history chamada para navegador: %s com limite: %s", request.browser, request.limit
|
|
15
|
+
)
|
|
16
|
+
# Mock seguro simulando processamento
|
|
17
|
+
result_data = [
|
|
18
|
+
{"url": "https://example.com", "title": "Example", "visit_count": 10},
|
|
19
|
+
{"url": "https://google.com", "title": "Google", "visit_count": 5},
|
|
20
|
+
]
|
|
21
|
+
if request.limit:
|
|
22
|
+
result_data = result_data[: request.limit]
|
|
23
|
+
return BrowserHistoryResponse(status="success", data=result_data)
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from typing import Any, Dict, List, Optional
|
|
2
|
+
|
|
3
|
+
from pydantic import BaseModel, Field
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class BrowserHistoryRequest(BaseModel):
|
|
7
|
+
browser: str = Field(..., description="Nome do navegador (ex: chrome, firefox)")
|
|
8
|
+
limit: Optional[int] = Field(None, description="Limite de registros a retornar")
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class BrowserHistoryResponse(BaseModel):
|
|
12
|
+
status: str
|
|
13
|
+
data: List[Dict[str, Any]]
|
|
@@ -23,6 +23,7 @@ src/browser/common_words.py
|
|
|
23
23
|
src/browser/downloads_history.py
|
|
24
24
|
src/browser/fav_screen.py
|
|
25
25
|
src/browser/logins.py
|
|
26
|
+
src/browser/schemas.py
|
|
26
27
|
src/browser/unusual_patterns.py
|
|
27
28
|
src/forensic_cli.egg-info/PKG-INFO
|
|
28
29
|
src/forensic_cli.egg-info/SOURCES.txt
|
|
@@ -35,6 +36,7 @@ src/mail/api.py
|
|
|
35
36
|
src/mail/cli.py
|
|
36
37
|
src/mail/email_parser.py
|
|
37
38
|
src/mail/header_analysis.py
|
|
39
|
+
src/mail/schemas.py
|
|
38
40
|
src/network/__init__.py
|
|
39
41
|
src/network/api.py
|
|
40
42
|
src/network/arp_scan.py
|
|
@@ -45,6 +47,7 @@ src/network/ip_info.py
|
|
|
45
47
|
src/network/network_map.py
|
|
46
48
|
src/network/ping_sweep.py
|
|
47
49
|
src/network/port_scanner.py
|
|
50
|
+
src/network/schemas.py
|
|
48
51
|
src/network/smb_scan.py
|
|
49
52
|
src/network/snmp_scan.py
|
|
50
53
|
src/network/traceroute.py
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from fastapi import APIRouter
|
|
2
|
+
|
|
3
|
+
from mail.schemas import MailAnalysisRequest, MailAnalysisResponse
|
|
4
|
+
from shared.logger import get_logger
|
|
5
|
+
|
|
6
|
+
logger = get_logger(__name__)
|
|
7
|
+
|
|
8
|
+
router = APIRouter(prefix="/api/mail", tags=["Mail"])
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@router.post("/analyze", response_model=MailAnalysisResponse)
|
|
12
|
+
def analyze_mail(request: MailAnalysisRequest):
|
|
13
|
+
logger.info("API /analyze chamada para: %s", request.file_path)
|
|
14
|
+
# Mock seguro simulando processamento
|
|
15
|
+
result_data = {
|
|
16
|
+
"headers": {"subject": "Mock Subject", "from": "test@example.com"},
|
|
17
|
+
"body": "Mock body content",
|
|
18
|
+
}
|
|
19
|
+
return MailAnalysisResponse(status="success", data=result_data)
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from typing import Any, Dict
|
|
2
|
+
|
|
3
|
+
from pydantic import BaseModel, Field
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class MailAnalysisRequest(BaseModel):
|
|
7
|
+
file_path: str = Field(..., description="Caminho para o arquivo .eml ou cabeçalho")
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class MailAnalysisResponse(BaseModel):
|
|
11
|
+
status: str
|
|
12
|
+
data: Dict[str, Any]
|
|
@@ -15,13 +15,14 @@ from network.dns_recon import dns_recon
|
|
|
15
15
|
from network.ip_info import ip_info_lookup
|
|
16
16
|
from network.ping_sweep import parse_network, ping_host
|
|
17
17
|
from network.port_scanner import scan_host
|
|
18
|
+
from network.schemas import NetworkScanRequest, NetworkScanResponse
|
|
18
19
|
from network.traceroute import traceroute_host
|
|
19
20
|
from shared.config import get as cfg_get
|
|
20
21
|
from shared.logger import get_logger
|
|
21
22
|
|
|
22
23
|
logger = get_logger(__name__)
|
|
23
24
|
|
|
24
|
-
router = APIRouter()
|
|
25
|
+
router = APIRouter(prefix="/api/network", tags=["Network"])
|
|
25
26
|
|
|
26
27
|
_DEFAULT_PORTS = cfg_get("network", "default_ports", default="21,22,53,80,443,445,3306,8080")
|
|
27
28
|
|
|
@@ -31,15 +32,6 @@ _DEFAULT_PORTS = cfg_get("network", "default_ports", default="21,22,53,80,443,44
|
|
|
31
32
|
# ---------------------------------------------------------------------------
|
|
32
33
|
|
|
33
34
|
|
|
34
|
-
class ScanRequest(BaseModel):
|
|
35
|
-
target: str = Field(..., examples=["192.168.1.1"], description="IP ou hostname do alvo")
|
|
36
|
-
ports: str = Field(
|
|
37
|
-
default=_DEFAULT_PORTS,
|
|
38
|
-
examples=["22,80,443"],
|
|
39
|
-
description="Portas a escanear. Ex: '22,80,100-200'",
|
|
40
|
-
)
|
|
41
|
-
|
|
42
|
-
|
|
43
35
|
class SweepRequest(BaseModel):
|
|
44
36
|
network: str = Field(
|
|
45
37
|
..., examples=["192.168.1.1-254"], description="Range de IPs. Ex: 192.168.1.1-254"
|
|
@@ -66,13 +58,15 @@ class TracerouteRequest(BaseModel):
|
|
|
66
58
|
"/scan",
|
|
67
59
|
summary="Port Scan",
|
|
68
60
|
description="Realiza um scan de portas TCP em um host e retorna as portas abertas com serviços e banners.",
|
|
61
|
+
response_model=NetworkScanResponse,
|
|
69
62
|
)
|
|
70
|
-
def run_port_scan(request:
|
|
71
|
-
logger.info("API /scan — alvo: %s | portas: %s", request.target, request.ports)
|
|
63
|
+
def run_port_scan(request: NetworkScanRequest):
|
|
64
|
+
logger.info("API /scan — alvo: %s | portas (list): %s", request.target, request.ports)
|
|
72
65
|
try:
|
|
73
|
-
|
|
66
|
+
ports_str = ",".join(map(str, request.ports)) if request.ports else _DEFAULT_PORTS
|
|
67
|
+
results = scan_host(target=request.target, ports=ports_str)
|
|
74
68
|
logger.info("API /scan concluído — %d resultado(s).", len(results))
|
|
75
|
-
return
|
|
69
|
+
return NetworkScanResponse(target=request.target, status="success", data=results)
|
|
76
70
|
except Exception as exc:
|
|
77
71
|
logger.exception("Erro em /scan para '%s'.", request.target)
|
|
78
72
|
raise HTTPException(status_code=500, detail=str(exc))
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from typing import Any, List, Optional
|
|
2
|
+
|
|
3
|
+
from pydantic import BaseModel, Field
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class NetworkScanRequest(BaseModel):
|
|
7
|
+
target: str = Field(..., examples=["192.168.1.1"], description="IP ou hostname do alvo")
|
|
8
|
+
ports: Optional[list[int]] = Field(
|
|
9
|
+
None, examples=[[22, 80, 443]], description="Lista de portas a escanear"
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class NetworkScanResponse(BaseModel):
|
|
14
|
+
target: str
|
|
15
|
+
status: str
|
|
16
|
+
data: List[Any]
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
API Router da feature Browser.
|
|
3
|
-
|
|
4
|
-
Expõe endpoints REST para extração de artefatos de navegadores.
|
|
5
|
-
Os endpoints de extração são operações de longa duração — em produção
|
|
6
|
-
considere movê-los para tarefas assíncronas (ex: Celery/BackgroundTasks).
|
|
7
|
-
"""
|
|
8
|
-
|
|
9
|
-
from fastapi import APIRouter
|
|
10
|
-
|
|
11
|
-
from shared.logger import get_logger
|
|
12
|
-
|
|
13
|
-
logger = get_logger(__name__)
|
|
14
|
-
|
|
15
|
-
router = APIRouter()
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
# ---------------------------------------------------------------------------
|
|
19
|
-
# Health-check da feature
|
|
20
|
-
# ---------------------------------------------------------------------------
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
@router.get(
|
|
24
|
-
"/health",
|
|
25
|
-
summary="Browser Feature Health-check",
|
|
26
|
-
description="Confirma que o módulo de análise de navegadores está disponível.",
|
|
27
|
-
)
|
|
28
|
-
def browser_health():
|
|
29
|
-
return {
|
|
30
|
-
"feature": "browser",
|
|
31
|
-
"status": "online",
|
|
32
|
-
"endpoints_available": [
|
|
33
|
-
"GET /browser/health",
|
|
34
|
-
],
|
|
35
|
-
"note": (
|
|
36
|
-
"Os endpoints de extração (history, downloads, logins) operam sobre "
|
|
37
|
-
"o sistema de arquivos local e serão expostos em versões futuras da API."
|
|
38
|
-
),
|
|
39
|
-
}
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
API Router da feature Email.
|
|
3
|
-
|
|
4
|
-
Expõe endpoints REST para análise forense de e-mails.
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
|
-
from fastapi import APIRouter
|
|
8
|
-
|
|
9
|
-
from shared.logger import get_logger
|
|
10
|
-
|
|
11
|
-
logger = get_logger(__name__)
|
|
12
|
-
|
|
13
|
-
router = APIRouter()
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
# ---------------------------------------------------------------------------
|
|
17
|
-
# Health-check da feature
|
|
18
|
-
# ---------------------------------------------------------------------------
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
@router.get(
|
|
22
|
-
"/health",
|
|
23
|
-
summary="Email Feature Health-check",
|
|
24
|
-
description="Confirma que o módulo de análise de e-mails está disponível.",
|
|
25
|
-
)
|
|
26
|
-
def email_health():
|
|
27
|
-
return {
|
|
28
|
-
"feature": "email",
|
|
29
|
-
"status": "online",
|
|
30
|
-
"endpoints_available": [
|
|
31
|
-
"GET /email/health",
|
|
32
|
-
],
|
|
33
|
-
"note": (
|
|
34
|
-
"Os endpoints de parsing (.eml) e análise de cabeçalhos serão "
|
|
35
|
-
"expostos em versões futuras da API REST."
|
|
36
|
-
),
|
|
37
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|