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.
Files changed (80) hide show
  1. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/PKG-INFO +2 -2
  2. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/cli.py +4 -3
  3. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/core/database/config_db.py +28 -35
  4. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/utils/setup.py +13 -63
  5. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/pyproject.toml +2 -2
  6. detecti_cli-2.0.1/install.py +0 -104
  7. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/.env.example +0 -0
  8. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/.github/workflows/publish.yml +0 -0
  9. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/.gitignore +0 -0
  10. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/README.md +0 -0
  11. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/__init__.py +0 -0
  12. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/__main__.py +0 -0
  13. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/__init__.py +0 -0
  14. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/banner +0 -0
  15. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/config.py +0 -0
  16. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/core/__init__.py +0 -0
  17. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/core/database/__init__.py +0 -0
  18. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/core/database/schema.py +0 -0
  19. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/core/database/storage.py +0 -0
  20. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/core/engine.py +0 -0
  21. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/core/models.py +0 -0
  22. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/data/config.sqlite +0 -0
  23. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/data/dbs/.gitkeep +0 -0
  24. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/data/dbs/example.com.sqlite +0 -0
  25. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/modules/__init__.py +0 -0
  26. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/modules/base.py +0 -0
  27. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/modules/censys.py +0 -0
  28. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/modules/crtsh.py +0 -0
  29. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/modules/exploitdb.py +0 -0
  30. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/modules/masscan.py +0 -0
  31. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/modules/nuclei.py +0 -0
  32. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/modules/nvd.py +0 -0
  33. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/modules/reverse_whois.py +0 -0
  34. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/modules/shodan.py +0 -0
  35. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/reporters/__init__.py +0 -0
  36. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/reporters/csv_reporter.py +0 -0
  37. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/reporters/html_reporter.py +0 -0
  38. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/reporters/json_reporter.py +0 -0
  39. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/reporters/markdown_reporter.py +0 -0
  40. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/utils/__init__.py +0 -0
  41. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/utils/http.py +0 -0
  42. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/utils/logger.py +0 -0
  43. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/web/__init__.py +0 -0
  44. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/web/api/__init__.py +0 -0
  45. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/web/api/auth.py +0 -0
  46. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/web/api/graph_builder.py +0 -0
  47. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/web/api/routes.py +0 -0
  48. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/web/process_manager.py +0 -0
  49. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/web/server.py +0 -0
  50. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/web/static/android-chrome-192x192.png +0 -0
  51. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/web/static/android-chrome-512x512.png +0 -0
  52. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/web/static/apple-touch-icon.png +0 -0
  53. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/web/static/css/__init__.py +0 -0
  54. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/web/static/css/dashboard.css +0 -0
  55. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/web/static/favicon-16x16.png +0 -0
  56. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/web/static/favicon-32x32.png +0 -0
  57. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/web/static/favicon.ico +0 -0
  58. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/web/static/img/DetecTI_Security_Logo.png +0 -0
  59. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/web/static/img/detecti-ico.png +0 -0
  60. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/web/static/index.html +0 -0
  61. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/web/static/js/__init__.py +0 -0
  62. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/web/static/js/api.js +0 -0
  63. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/web/static/js/cytoscape-cose-bilkent.js +0 -0
  64. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/web/static/js/cytoscape-dagre.js +0 -0
  65. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/web/static/js/cytoscape.min.js +0 -0
  66. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/web/static/js/dagre.min.js +0 -0
  67. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/web/static/js/graph.js +0 -0
  68. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/web/static/js/lucide.min.js +0 -0
  69. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/web/static/login.html +0 -0
  70. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/detecti/web/static/site.webmanifest +0 -0
  71. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/requirements.txt +0 -0
  72. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/tests/__init__.py +0 -0
  73. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/tests/conftest.py +0 -0
  74. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/tests/test_engine_cli.py +0 -0
  75. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/tests/test_http.py +0 -0
  76. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/tests/test_masscan.py +0 -0
  77. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/tests/test_models.py +0 -0
  78. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/tests/test_modules.py +0 -0
  79. {detecti_cli-2.0.1 → detecti_cli-2.0.3}/tests/test_nuclei.py +0 -0
  80. {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.1
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
- from __init__ import __version__
36
- except (ImportError, ModuleNotFoundError):
37
- __version__ = "2.0.0"
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
- return pwd_context.hash(password)
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
- return pwd_context.verify(plain_password, hashed_password)
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 create_user(self, username: str, password_hash: str, role: str = 'admin'):
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
- VALUES (?, ?, ?)
52
- ''', (username, password_hash, role))
44
+ conn.execute(
45
+ "INSERT INTO users (username, password_hash, role) VALUES (?, ?, ?)",
46
+ (username, password_hash, role)
47
+ )
53
48
  conn.commit()
54
- return True
49
+ return True
55
50
  except sqlite3.IntegrityError:
56
51
  return False
57
52
 
58
- def update_user_password(self, username: str, password_hash: 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
- ''', (password_hash, username))
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 get_user(self, username: str):
62
+ def get_user_hash(self, username: str) -> str:
66
63
  with sqlite3.connect(self.db_path) as conn:
67
- conn.row_factory = sqlite3.Row
68
- cursor = conn.execute("SELECT * FROM users WHERE username = ?", (username,))
69
- return cursor.fetchone()
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": "Optional / Not Installed",
157
- "ok": True, # Nuclei is optional but recommended
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/8: Configuring DetecTIHound Dashboard Admin...[/bold white]")
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/8: Initializing project directories...[/bold white]")
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/8: Checking environment configuration (.env)...[/bold white]")
329
+ self.console.print("\n⚙️ [bold white]Step 2/6: Checking environment configuration (.env)...[/bold white]")
330
330
  env_file = DETECTI_HOME / ".env"
331
- env_example = self.root_dir / ".env.example"
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
- self.console.print(" [yellow]⚠ No .env template found. Skipped.[/yellow]")
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/8: Verifying Python dependencies...[/bold white]")
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/8: Configuring Masscan network capabilities...[/bold white]")
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/8: Initializing ExploitDB vulnerability mapping...[/bold white]")
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/8: Checking Nuclei vulnerability engine...[/bold white]")
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.1"
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
- "passlib[bcrypt]>=1.7.4",
55
+ "bcrypt>=4.0.0",
56
56
  "python-jose[cryptography]>=3.3.0",
57
57
  "python-multipart>=0.0.6",
58
58
  ]
@@ -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