detecti-cli 2.0.1__tar.gz → 2.0.3__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.
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/PKG-INFO +2 -2
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/cli.py +4 -3
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/core/database/config_db.py +28 -35
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/utils/setup.py +13 -63
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/pyproject.toml +2 -2
- detecti_cli-2.0.1/install.py +0 -104
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/.env.example +0 -0
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/.github/workflows/publish.yml +0 -0
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/.gitignore +0 -0
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/README.md +0 -0
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/__init__.py +0 -0
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/__main__.py +0 -0
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/__init__.py +0 -0
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/banner +0 -0
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/config.py +0 -0
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/core/__init__.py +0 -0
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/core/database/__init__.py +0 -0
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/core/database/schema.py +0 -0
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/core/database/storage.py +0 -0
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/core/engine.py +0 -0
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/core/models.py +0 -0
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/data/config.sqlite +0 -0
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/data/dbs/.gitkeep +0 -0
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/data/dbs/example.com.sqlite +0 -0
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/modules/__init__.py +0 -0
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/modules/base.py +0 -0
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/modules/censys.py +0 -0
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/modules/crtsh.py +0 -0
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/modules/exploitdb.py +0 -0
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/modules/masscan.py +0 -0
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/modules/nuclei.py +0 -0
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/modules/nvd.py +0 -0
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/modules/reverse_whois.py +0 -0
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/modules/shodan.py +0 -0
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/reporters/__init__.py +0 -0
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/reporters/csv_reporter.py +0 -0
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/reporters/html_reporter.py +0 -0
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/reporters/json_reporter.py +0 -0
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/reporters/markdown_reporter.py +0 -0
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/utils/__init__.py +0 -0
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/utils/http.py +0 -0
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/utils/logger.py +0 -0
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/web/__init__.py +0 -0
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/web/api/__init__.py +0 -0
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/web/api/auth.py +0 -0
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/web/api/graph_builder.py +0 -0
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/web/api/routes.py +0 -0
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/web/process_manager.py +0 -0
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/web/server.py +0 -0
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/web/static/android-chrome-192x192.png +0 -0
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/web/static/android-chrome-512x512.png +0 -0
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/web/static/apple-touch-icon.png +0 -0
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/web/static/css/__init__.py +0 -0
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/web/static/css/dashboard.css +0 -0
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/web/static/favicon-16x16.png +0 -0
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/web/static/favicon-32x32.png +0 -0
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/web/static/favicon.ico +0 -0
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/web/static/img/DetecTI_Security_Logo.png +0 -0
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/web/static/img/detecti-ico.png +0 -0
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/web/static/index.html +0 -0
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/web/static/js/__init__.py +0 -0
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/web/static/js/api.js +0 -0
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/web/static/js/cytoscape-cose-bilkent.js +0 -0
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/web/static/js/cytoscape-dagre.js +0 -0
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/web/static/js/cytoscape.min.js +0 -0
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/web/static/js/dagre.min.js +0 -0
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/web/static/js/graph.js +0 -0
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/web/static/js/lucide.min.js +0 -0
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/web/static/login.html +0 -0
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/web/static/site.webmanifest +0 -0
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/requirements.txt +0 -0
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/tests/__init__.py +0 -0
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/tests/conftest.py +0 -0
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/tests/test_engine_cli.py +0 -0
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/tests/test_http.py +0 -0
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/tests/test_masscan.py +0 -0
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/tests/test_models.py +0 -0
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/tests/test_modules.py +0 -0
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/tests/test_nuclei.py +0 -0
- {detecti_cli-2.0.1 → detecti_cli-2.0.3}/tests/test_reporters.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: detecti-cli
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.3
|
|
4
4
|
Summary: Modern Attack Surface Management & Threat Intelligence Engine
|
|
5
5
|
Author-email: "Lucas S. (Ls4ss)" <lucas@lucassouza.io>
|
|
6
6
|
License: MIT
|
|
@@ -17,10 +17,10 @@ Classifier: Programming Language :: Python :: 3.12
|
|
|
17
17
|
Classifier: Programming Language :: Python :: 3.13
|
|
18
18
|
Classifier: Topic :: Security
|
|
19
19
|
Requires-Python: >=3.11
|
|
20
|
+
Requires-Dist: bcrypt>=4.0.0
|
|
20
21
|
Requires-Dist: cve-searchsploit>=0.3.0
|
|
21
22
|
Requires-Dist: fastapi>=0.104.0
|
|
22
23
|
Requires-Dist: httpx>=0.27.0
|
|
23
|
-
Requires-Dist: passlib[bcrypt]>=1.7.4
|
|
24
24
|
Requires-Dist: psutil>=5.9.0
|
|
25
25
|
Requires-Dist: pydantic-settings>=2.2.0
|
|
26
26
|
Requires-Dist: pydantic>=2.7.0
|
|
@@ -31,10 +31,11 @@ def _compat_make_metavar(self, ctx=None):
|
|
|
31
31
|
|
|
32
32
|
click.Option.make_metavar = _compat_make_metavar
|
|
33
33
|
|
|
34
|
+
import importlib.metadata
|
|
34
35
|
try:
|
|
35
|
-
|
|
36
|
-
except
|
|
37
|
-
__version__ = "
|
|
36
|
+
__version__ = importlib.metadata.version("detecti-cli")
|
|
37
|
+
except importlib.metadata.PackageNotFoundError:
|
|
38
|
+
__version__ = "dev"
|
|
38
39
|
|
|
39
40
|
from detecti.config import settings, DETECTI_HOME
|
|
40
41
|
from detecti.core.engine import ThreatTrackEngine, DetectIEngine
|
|
@@ -1,28 +1,18 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
import sqlite3
|
|
3
3
|
import hashlib
|
|
4
|
+
import bcrypt
|
|
4
5
|
from pathlib import Path
|
|
5
6
|
|
|
6
|
-
# Suppress passlib bcrypt warning
|
|
7
|
-
try:
|
|
8
|
-
import bcrypt
|
|
9
|
-
if not hasattr(bcrypt, "__about__"):
|
|
10
|
-
class AboutMock:
|
|
11
|
-
__version__ = bcrypt.__version__
|
|
12
|
-
bcrypt.__about__ = AboutMock()
|
|
13
|
-
except ImportError:
|
|
14
|
-
pass
|
|
15
|
-
|
|
16
|
-
from passlib.context import CryptContext
|
|
17
|
-
from pydantic_settings import BaseSettings
|
|
18
|
-
|
|
19
|
-
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
|
|
20
|
-
|
|
21
7
|
def get_password_hash(password: str) -> str:
|
|
22
|
-
|
|
8
|
+
salt = bcrypt.gensalt()
|
|
9
|
+
return bcrypt.hashpw(password.encode('utf-8'), salt).decode('utf-8')
|
|
23
10
|
|
|
24
11
|
def verify_password(plain_password: str, hashed_password: str) -> bool:
|
|
25
|
-
|
|
12
|
+
try:
|
|
13
|
+
return bcrypt.checkpw(plain_password.encode('utf-8'), hashed_password.encode('utf-8'))
|
|
14
|
+
except Exception:
|
|
15
|
+
return False
|
|
26
16
|
|
|
27
17
|
class ConfigDBManager:
|
|
28
18
|
def __init__(self, db_path: Path):
|
|
@@ -43,31 +33,34 @@ class ConfigDBManager:
|
|
|
43
33
|
''')
|
|
44
34
|
conn.commit()
|
|
45
35
|
|
|
46
|
-
def
|
|
36
|
+
def user_exists(self, username: str) -> bool:
|
|
37
|
+
with sqlite3.connect(self.db_path) as conn:
|
|
38
|
+
cursor = conn.execute("SELECT 1 FROM users WHERE username = ?", (username,))
|
|
39
|
+
return cursor.fetchone() is not None
|
|
40
|
+
|
|
41
|
+
def create_user(self, username: str, password_hash: str, role: str = "admin") -> bool:
|
|
47
42
|
try:
|
|
48
43
|
with sqlite3.connect(self.db_path) as conn:
|
|
49
|
-
conn.execute(
|
|
50
|
-
INSERT INTO users (username, password_hash, role)
|
|
51
|
-
|
|
52
|
-
|
|
44
|
+
conn.execute(
|
|
45
|
+
"INSERT INTO users (username, password_hash, role) VALUES (?, ?, ?)",
|
|
46
|
+
(username, password_hash, role)
|
|
47
|
+
)
|
|
53
48
|
conn.commit()
|
|
54
|
-
|
|
49
|
+
return True
|
|
55
50
|
except sqlite3.IntegrityError:
|
|
56
51
|
return False
|
|
57
52
|
|
|
58
|
-
def update_user_password(self, username: str,
|
|
53
|
+
def update_user_password(self, username: str, new_password_hash: str) -> bool:
|
|
59
54
|
with sqlite3.connect(self.db_path) as conn:
|
|
60
|
-
conn.execute(
|
|
61
|
-
UPDATE users SET password_hash = ? WHERE username = ?
|
|
62
|
-
|
|
55
|
+
cursor = conn.execute(
|
|
56
|
+
"UPDATE users SET password_hash = ? WHERE username = ?",
|
|
57
|
+
(new_password_hash, username)
|
|
58
|
+
)
|
|
63
59
|
conn.commit()
|
|
60
|
+
return cursor.rowcount > 0
|
|
64
61
|
|
|
65
|
-
def
|
|
62
|
+
def get_user_hash(self, username: str) -> str:
|
|
66
63
|
with sqlite3.connect(self.db_path) as conn:
|
|
67
|
-
conn.
|
|
68
|
-
|
|
69
|
-
return
|
|
70
|
-
|
|
71
|
-
def user_exists(self, username: str) -> bool:
|
|
72
|
-
return self.get_user(username) is not None
|
|
73
|
-
|
|
64
|
+
cursor = conn.execute("SELECT password_hash FROM users WHERE username = ?", (username,))
|
|
65
|
+
row = cursor.fetchone()
|
|
66
|
+
return row[0] if row else None
|
|
@@ -153,8 +153,8 @@ class SetupManager:
|
|
|
153
153
|
if not nuclei_path:
|
|
154
154
|
return {
|
|
155
155
|
"name": "Nuclei Vulnerability Scanner",
|
|
156
|
-
"status": "
|
|
157
|
-
"ok":
|
|
156
|
+
"status": "Not Installed",
|
|
157
|
+
"ok": False,
|
|
158
158
|
"installed": False,
|
|
159
159
|
"path": None,
|
|
160
160
|
"message": "Nuclei binary not found in PATH. Install to enable active vulnerability verification.",
|
|
@@ -245,7 +245,7 @@ class SetupManager:
|
|
|
245
245
|
all_success = True
|
|
246
246
|
|
|
247
247
|
# Step 0: Dashboard Admin Password Setup
|
|
248
|
-
self.console.print("🔐 [bold white]Step 0/
|
|
248
|
+
self.console.print("🔐 [bold white]Step 0/6: Configuring DetecTIHound Dashboard Admin...[/bold white]")
|
|
249
249
|
try:
|
|
250
250
|
import getpass
|
|
251
251
|
import sys
|
|
@@ -313,7 +313,7 @@ class SetupManager:
|
|
|
313
313
|
traceback.print_exc()
|
|
314
314
|
|
|
315
315
|
# Step 1: Create Directories & Copy Demo DB
|
|
316
|
-
self.console.print("📁 [bold white]Step 1/
|
|
316
|
+
self.console.print("📁 [bold white]Step 1/6: Initializing project directories...[/bold white]")
|
|
317
317
|
for d in [DETECTI_HOME / "data" / "dbs", Path.cwd() / "reports"]:
|
|
318
318
|
d.mkdir(parents=True, exist_ok=True)
|
|
319
319
|
|
|
@@ -326,19 +326,17 @@ class SetupManager:
|
|
|
326
326
|
self.console.print(" [green]✔ Operational directories verified (data/dbs, reports).[/green]")
|
|
327
327
|
|
|
328
328
|
# Step 2: Configure .env
|
|
329
|
-
self.console.print("\n⚙️ [bold white]Step 2/
|
|
329
|
+
self.console.print("\n⚙️ [bold white]Step 2/6: Checking environment configuration (.env)...[/bold white]")
|
|
330
330
|
env_file = DETECTI_HOME / ".env"
|
|
331
|
-
|
|
332
|
-
if not env_file.exists() and env_example.exists():
|
|
333
|
-
shutil.copy(env_example, env_file)
|
|
334
|
-
self.console.print(f" [green]✔ Created .env file at {env_file} from template.[/green]")
|
|
335
|
-
elif env_file.exists():
|
|
331
|
+
if env_file.exists():
|
|
336
332
|
self.console.print(f" [green]✔ Existing .env file detected at {env_file} and preserved.[/green]")
|
|
337
333
|
else:
|
|
338
|
-
|
|
334
|
+
env_content = "# DetecTI-CLI Configuration\n# Add your API Keys here for enhanced intelligence\nSHODAN_API_KEY=\nCENSYS_API_ID=\nCENSYS_API_SECRET=\nGITHUB_TOKEN=\n"
|
|
335
|
+
env_file.write_text(env_content)
|
|
336
|
+
self.console.print(f" [green]✔ Created default .env file at {env_file}.[/green]")
|
|
339
337
|
|
|
340
338
|
# Step 3: Python dependencies check / install
|
|
341
|
-
self.console.print("\n🐍 [bold white]Step 3/
|
|
339
|
+
self.console.print("\n🐍 [bold white]Step 3/6: Verifying Python dependencies...[/bold white]")
|
|
342
340
|
req_file = self.root_dir / "requirements.txt"
|
|
343
341
|
dep_check = self.check_python_modules()
|
|
344
342
|
if not dep_check["ok"] and req_file.exists():
|
|
@@ -353,7 +351,7 @@ class SetupManager:
|
|
|
353
351
|
self.console.print(" [green]✔ All Python core dependencies are satisfied.[/green]")
|
|
354
352
|
|
|
355
353
|
# Step 4: Masscan capabilities configuration
|
|
356
|
-
self.console.print("\n⚡ [bold white]Step 4/
|
|
354
|
+
self.console.print("\n⚡ [bold white]Step 4/6: Configuring Masscan network capabilities...[/bold white]")
|
|
357
355
|
masscan_bin = shutil.which("masscan")
|
|
358
356
|
if masscan_bin:
|
|
359
357
|
is_root = hasattr(os, "geteuid") and os.geteuid() == 0
|
|
@@ -379,7 +377,7 @@ class SetupManager:
|
|
|
379
377
|
self.console.print(" [dim]Install on Linux with: sudo apt install -y masscan (or pacman/dnf)[/dim]")
|
|
380
378
|
|
|
381
379
|
# Step 5: ExploitDB Cache Update
|
|
382
|
-
self.console.print("\n💣 [bold white]Step 5/
|
|
380
|
+
self.console.print("\n💣 [bold white]Step 5/6: Initializing ExploitDB vulnerability mapping...[/bold white]")
|
|
383
381
|
try:
|
|
384
382
|
from modules.exploitdb import ExploitDBModule
|
|
385
383
|
ExploitDBModule.update_database()
|
|
@@ -388,7 +386,7 @@ class SetupManager:
|
|
|
388
386
|
self.console.print(f" [yellow]⚠ ExploitDB update notice: {exc}[/yellow]")
|
|
389
387
|
|
|
390
388
|
# Step 6: Nuclei Templates Check
|
|
391
|
-
self.console.print("\n🛡️ [bold white]Step 6/
|
|
389
|
+
self.console.print("\n🛡️ [bold white]Step 6/6: Checking Nuclei vulnerability engine...[/bold white]")
|
|
392
390
|
nuclei_bin = shutil.which("nuclei")
|
|
393
391
|
if nuclei_bin:
|
|
394
392
|
try:
|
|
@@ -400,54 +398,6 @@ class SetupManager:
|
|
|
400
398
|
else:
|
|
401
399
|
self.console.print(" [dim]Nuclei is optional and not currently installed.[/dim]")
|
|
402
400
|
|
|
403
|
-
# Step 7: Configure Global Executable & Install Source
|
|
404
|
-
self.console.print("\n🌍 [bold white]Step 7/8: Installing Source & Configuring Global Executable...[/bold white]")
|
|
405
|
-
try:
|
|
406
|
-
is_root = hasattr(os, "geteuid") and os.geteuid() == 0
|
|
407
|
-
if is_root:
|
|
408
|
-
bin_dir = Path("/usr/local/bin")
|
|
409
|
-
install_dir = Path("/opt/detecti-cli")
|
|
410
|
-
else:
|
|
411
|
-
bin_dir = Path.home() / ".local" / "bin"
|
|
412
|
-
install_dir = DETECTI_HOME / "app"
|
|
413
|
-
|
|
414
|
-
if self.root_dir.resolve() == install_dir.resolve():
|
|
415
|
-
self.console.print(f" [cyan]Running from installed location ({install_dir}). Skipping source copy.[/cyan]")
|
|
416
|
-
else:
|
|
417
|
-
self.console.print(f" [cyan]Copying source code to {install_dir}...[/cyan]")
|
|
418
|
-
|
|
419
|
-
# Remove old install dir if exists to ensure clean install
|
|
420
|
-
if install_dir.exists():
|
|
421
|
-
shutil.rmtree(install_dir)
|
|
422
|
-
|
|
423
|
-
# Copy source code, ignoring unnecessary/heavy folders
|
|
424
|
-
shutil.copytree(
|
|
425
|
-
self.root_dir,
|
|
426
|
-
install_dir,
|
|
427
|
-
ignore=shutil.ignore_patterns('.git', '__pycache__', 'node_modules', 'reports', '.pytest_cache')
|
|
428
|
-
)
|
|
429
|
-
|
|
430
|
-
bin_dir.mkdir(parents=True, exist_ok=True)
|
|
431
|
-
wrapper_path = bin_dir / "detecti-cli"
|
|
432
|
-
|
|
433
|
-
# The actual python script is now in the install_dir
|
|
434
|
-
target_script = install_dir / "cli.py"
|
|
435
|
-
|
|
436
|
-
wrapper_content = f"""#!/usr/bin/env bash
|
|
437
|
-
# DetecTI-CLI Global Wrapper
|
|
438
|
-
python3 "{target_script}" "$@"
|
|
439
|
-
"""
|
|
440
|
-
wrapper_path.write_text(wrapper_content)
|
|
441
|
-
# Make it executable (chmod +x)
|
|
442
|
-
wrapper_path.chmod(wrapper_path.stat().st_mode | 0o111)
|
|
443
|
-
|
|
444
|
-
self.console.print(f" [green]✔ Source installed securely in {install_dir}[/green]")
|
|
445
|
-
self.console.print(f" [green]✔ Global executable created at {wrapper_path}[/green]")
|
|
446
|
-
if not is_root:
|
|
447
|
-
self.console.print(f" [cyan]ℹ Make sure {bin_dir} is in your PATH.[/cyan]")
|
|
448
|
-
except Exception as exc:
|
|
449
|
-
self.console.print(f" [red]✘ Failed to install source or create global executable: {exc}[/red]")
|
|
450
|
-
all_success = False
|
|
451
401
|
|
|
452
402
|
self.console.print("\n[bold green]✅ DetecTI-CLI setup routine completed![/bold green]\n")
|
|
453
403
|
return all_success
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "detecti-cli"
|
|
7
|
-
version = "2.0.
|
|
7
|
+
version = "2.0.3"
|
|
8
8
|
description = "Modern Attack Surface Management & Threat Intelligence Engine"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.11"
|
|
@@ -52,7 +52,7 @@ dependencies = [
|
|
|
52
52
|
"fastapi>=0.104.0",
|
|
53
53
|
"uvicorn[standard]>=0.24.0",
|
|
54
54
|
"psutil>=5.9.0",
|
|
55
|
-
"
|
|
55
|
+
"bcrypt>=4.0.0",
|
|
56
56
|
"python-jose[cryptography]>=3.3.0",
|
|
57
57
|
"python-multipart>=0.0.6",
|
|
58
58
|
]
|
detecti_cli-2.0.1/install.py
DELETED
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""
|
|
3
|
-
DetecTI-CLI - Automated Installer & Bootstrapper
|
|
4
|
-
This script installs the necessary dependencies and delegates the
|
|
5
|
-
system configuration to the SetupManager.
|
|
6
|
-
"""
|
|
7
|
-
import os
|
|
8
|
-
import sys
|
|
9
|
-
import subprocess
|
|
10
|
-
from pathlib import Path
|
|
11
|
-
|
|
12
|
-
def print_step(msg: str) -> None:
|
|
13
|
-
print(f"\n\033[1;34m[+]\033[0m \033[1;37m{msg}\033[0m")
|
|
14
|
-
|
|
15
|
-
def print_success(msg: str) -> None:
|
|
16
|
-
print(f"\033[1;32m[✔]\033[0m {msg}")
|
|
17
|
-
|
|
18
|
-
def print_error(msg: str) -> None:
|
|
19
|
-
print(f"\033[1;31m[✘]\033[0m \033[1;31m{msg}\033[0m")
|
|
20
|
-
|
|
21
|
-
def print_banner() -> None:
|
|
22
|
-
banner = """
|
|
23
|
-
██████╗ ███████╗████████╗███████╗ ██████╗████████╗██╗ ██████╗██╗ ██╗
|
|
24
|
-
██╔══██╗██╔════╝╚══██╔══╝██╔════╝██╔════╝╚══██╔══╝██║ ██╔════╝██║ ██║
|
|
25
|
-
██║ ██║█████╗ ██║ █████╗ ██║ ██║ ██║█████╗██║ ██║ ██║
|
|
26
|
-
██║ ██║██╔══╝ ██║ ██╔══╝ ██║ ██║ ██║╚════╝██║ ██║ ██║
|
|
27
|
-
██████╔╝███████╗ ██║ ███████╗╚██████╗ ██║ ██║ ╚██████╗███████╗██║
|
|
28
|
-
╚═════╝ ╚══════╝ ╚═╝ ╚══════╝ ╚═════╝ ╚═╝ ╚═╝ ╚═════╝╚══════╝╚═╝
|
|
29
|
-
|
|
30
|
-
DetecTI - Cyber Lead Intelligence Installer
|
|
31
|
-
Powered by DetecTI Security - https://detecti.com.br
|
|
32
|
-
"""
|
|
33
|
-
print(f"\033[1;36m{banner}\033[0m")
|
|
34
|
-
|
|
35
|
-
def install_dependencies() -> None:
|
|
36
|
-
root_dir = Path(__file__).resolve().parent
|
|
37
|
-
req_file = root_dir / "requirements.txt"
|
|
38
|
-
if req_file.exists():
|
|
39
|
-
print_step("Bootstrapping Python dependencies...")
|
|
40
|
-
try:
|
|
41
|
-
# First attempt standard installation
|
|
42
|
-
result = subprocess.run(
|
|
43
|
-
[sys.executable, "-m", "pip", "install", "-r", str(req_file)],
|
|
44
|
-
stdout=subprocess.DEVNULL,
|
|
45
|
-
stderr=subprocess.PIPE,
|
|
46
|
-
text=True
|
|
47
|
-
)
|
|
48
|
-
|
|
49
|
-
if result.returncode != 0:
|
|
50
|
-
if "externally-managed-environment" in result.stderr:
|
|
51
|
-
# PEP 668 bypass for Debian/Kali/Ubuntu modern versions
|
|
52
|
-
subprocess.check_call(
|
|
53
|
-
[sys.executable, "-m", "pip", "install", "--break-system-packages", "-r", str(req_file)],
|
|
54
|
-
stdout=subprocess.DEVNULL,
|
|
55
|
-
stderr=subprocess.STDOUT
|
|
56
|
-
)
|
|
57
|
-
else:
|
|
58
|
-
print_error("Failed to install dependencies.")
|
|
59
|
-
print(result.stderr)
|
|
60
|
-
sys.exit(1)
|
|
61
|
-
|
|
62
|
-
print_success("Core dependencies installed successfully.")
|
|
63
|
-
except subprocess.CalledProcessError as e:
|
|
64
|
-
print_error("Failed to install dependencies.")
|
|
65
|
-
print_error("Try running: pip3 install -r requirements.txt manually.")
|
|
66
|
-
sys.exit(1)
|
|
67
|
-
else:
|
|
68
|
-
print_error(f"requirements.txt not found at {req_file}")
|
|
69
|
-
sys.exit(1)
|
|
70
|
-
|
|
71
|
-
def run_setup() -> None:
|
|
72
|
-
print_step("Initializing DetecTI-CLI Setup Routine...")
|
|
73
|
-
# Now that dependencies are guaranteed, we can safely import them
|
|
74
|
-
try:
|
|
75
|
-
from rich.console import Console
|
|
76
|
-
from utils.setup import SetupManager
|
|
77
|
-
|
|
78
|
-
console = Console()
|
|
79
|
-
setup_mgr = SetupManager(console=console)
|
|
80
|
-
|
|
81
|
-
success = setup_mgr.run_automated_setup()
|
|
82
|
-
|
|
83
|
-
print("\n")
|
|
84
|
-
console.rule("[bold cyan]Verification Diagnostics[/bold cyan]")
|
|
85
|
-
checks = setup_mgr.check_all()
|
|
86
|
-
setup_mgr.render_diagnostics_table(checks)
|
|
87
|
-
|
|
88
|
-
if not success:
|
|
89
|
-
console.print("\n[yellow]⚠ Setup completed, but some components reported errors. Please review the logs above.[/yellow]")
|
|
90
|
-
|
|
91
|
-
except ImportError as e:
|
|
92
|
-
print_error(f"Failed to load setup module. Error: {e}")
|
|
93
|
-
sys.exit(1)
|
|
94
|
-
|
|
95
|
-
if __name__ == "__main__":
|
|
96
|
-
print_banner()
|
|
97
|
-
|
|
98
|
-
# Enforce running from the repository root
|
|
99
|
-
if not (Path(__file__).resolve().parent / "utils" / "setup.py").exists():
|
|
100
|
-
print_error("Installer must be run from the root of the DetecTI-CLI repository.")
|
|
101
|
-
sys.exit(1)
|
|
102
|
-
|
|
103
|
-
install_dependencies()
|
|
104
|
-
run_setup()
|
|
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
|
|
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
|