eva-exploit 3.4.2__tar.gz → 3.4.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 (26) hide show
  1. {eva_exploit-3.4.2 → eva_exploit-3.4.3}/PKG-INFO +1 -1
  2. {eva_exploit-3.4.2 → eva_exploit-3.4.3}/config.py +1 -1
  3. {eva_exploit-3.4.2 → eva_exploit-3.4.3}/eva_exploit.egg-info/PKG-INFO +1 -1
  4. {eva_exploit-3.4.2 → eva_exploit-3.4.3}/modules/llm.py +68 -17
  5. {eva_exploit-3.4.2 → eva_exploit-3.4.3}/pyproject.toml +1 -1
  6. {eva_exploit-3.4.2 → eva_exploit-3.4.3}/sessions/eva_session.py +3 -2
  7. {eva_exploit-3.4.2 → eva_exploit-3.4.3}/utils/system.py +116 -36
  8. {eva_exploit-3.4.2 → eva_exploit-3.4.3}/README.md +0 -0
  9. {eva_exploit-3.4.2 → eva_exploit-3.4.3}/eva.py +0 -0
  10. {eva_exploit-3.4.2 → eva_exploit-3.4.3}/eva_exploit.egg-info/SOURCES.txt +0 -0
  11. {eva_exploit-3.4.2 → eva_exploit-3.4.3}/eva_exploit.egg-info/dependency_links.txt +0 -0
  12. {eva_exploit-3.4.2 → eva_exploit-3.4.3}/eva_exploit.egg-info/entry_points.txt +0 -0
  13. {eva_exploit-3.4.2 → eva_exploit-3.4.3}/eva_exploit.egg-info/requires.txt +0 -0
  14. {eva_exploit-3.4.2 → eva_exploit-3.4.3}/eva_exploit.egg-info/top_level.txt +0 -0
  15. {eva_exploit-3.4.2 → eva_exploit-3.4.3}/modules/__init__.py +0 -0
  16. {eva_exploit-3.4.2 → eva_exploit-3.4.3}/modules/attack_map.py +0 -0
  17. {eva_exploit-3.4.2 → eva_exploit-3.4.3}/modules/exploit_search.py +0 -0
  18. {eva_exploit-3.4.2 → eva_exploit-3.4.3}/modules/prompt_builder.py +0 -0
  19. {eva_exploit-3.4.2 → eva_exploit-3.4.3}/modules/reporting.py +0 -0
  20. {eva_exploit-3.4.2 → eva_exploit-3.4.3}/modules/tooling.py +0 -0
  21. {eva_exploit-3.4.2 → eva_exploit-3.4.3}/modules/vuln_intel.py +0 -0
  22. {eva_exploit-3.4.2 → eva_exploit-3.4.3}/modules/workflow.py +0 -0
  23. {eva_exploit-3.4.2 → eva_exploit-3.4.3}/sessions/__init__.py +0 -0
  24. {eva_exploit-3.4.2 → eva_exploit-3.4.3}/setup.cfg +0 -0
  25. {eva_exploit-3.4.2 → eva_exploit-3.4.3}/utils/__init__.py +0 -0
  26. {eva_exploit-3.4.2 → eva_exploit-3.4.3}/utils/ui.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: eva-exploit
3
- Version: 3.4.2
3
+ Version: 3.4.3
4
4
  Summary: Exploit Vector Agent
5
5
  Author: ARCANGEL0
6
6
  License: MIT
@@ -10,7 +10,7 @@ from pathlib import Path
10
10
 
11
11
  # ================= CONFIG =================
12
12
  APP_NAME = "EVA"
13
- APP_VERSION = "3.4.2"
13
+ APP_VERSION = "3.4.3"
14
14
  GITHUB_REPO = "arcangel0/EVA"
15
15
  PYPI_PACKAGE = "eva-exploit"
16
16
  API_ENDPOINT = "NOT_SET"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: eva-exploit
3
- Version: 3.4.2
3
+ Version: 3.4.3
4
4
  Summary: Exploit Vector Agent
5
5
  Author: ARCANGEL0
6
6
  License: MIT
@@ -703,10 +703,59 @@ def _query_g4f(history):
703
703
  return ""
704
704
 
705
705
 
706
- def _query_custom_api(history, prompt_text=""):
706
+ def normalize_util(session_name):
707
+ suffix = re.sub(r"[^A-Za-z0-9_]", "_", str(session_name or "").strip())
708
+ suffix = re.sub(r"_+", "_", suffix).strip("_")
709
+ return suffix
710
+
711
+
712
+ def custom_enpdoint_func(session_name=""):
707
713
  endpoint = str(getattr(config_module, "API_ENDPOINT", API_ENDPOINT) or "").strip()
708
714
  if endpoint == "NOT_SET":
709
715
  endpoint = ""
716
+
717
+ session_name = str(session_name or "").strip()
718
+ if session_name:
719
+ session_key = f"EVA_API_CUSTOMAPI_{session_name}"
720
+ session_endpoint = os.getenv(session_key, "").strip()
721
+ if session_endpoint:
722
+ return session_endpoint
723
+
724
+ normalized_suffix = normalize_util(session_name)
725
+ if normalized_suffix and normalized_suffix != session_name:
726
+ normalized_key = f"EVA_API_CUSTOMAPI_{normalized_suffix}"
727
+ normalized_endpoint = os.getenv(normalized_key, "").strip()
728
+ if normalized_endpoint:
729
+ return normalized_endpoint
730
+
731
+ return endpoint
732
+
733
+
734
+ def _call_custom_api_handler(query_fn, history, endpoint, prompt_text, session_name):
735
+ attempts = [
736
+ lambda: query_fn(history=history, endpoint=endpoint, prompt=prompt_text, session=session_name),
737
+ lambda: query_fn(history=history, endpoint=endpoint, session=session_name, prompt=prompt_text),
738
+ lambda: query_fn(history=history, endpoint=endpoint, prompt=prompt_text),
739
+ lambda: query_fn(history=history, endpoint=endpoint),
740
+ lambda: query_fn(history, endpoint, prompt_text, session_name),
741
+ lambda: query_fn(history, endpoint, prompt_text),
742
+ lambda: query_fn(history, endpoint),
743
+ lambda: query_fn(history),
744
+ ]
745
+ last_type_error = None
746
+ for call in attempts:
747
+ try:
748
+ return call()
749
+ except TypeError as e:
750
+ last_type_error = e
751
+
752
+ if last_type_error is not None:
753
+ raise last_type_error
754
+ return ""
755
+
756
+
757
+ def _query_custom_api(history, prompt_text="", session_name=""):
758
+ endpoint = custom_enpdoint_func(session_name=session_name)
710
759
  handler_path = str(getattr(config_module, "CUSTOM_API_HANDLER", CUSTOM_API_HANDLER) or "").strip()
711
760
 
712
761
  if handler_path and handler_path != "NOT_SET":
@@ -720,19 +769,13 @@ def _query_custom_api(history, prompt_text=""):
720
769
  spec.loader.exec_module(module)
721
770
  query_fn = getattr(module, "query_custom_api", None)
722
771
  if callable(query_fn):
723
- try:
724
- result = query_fn(history=history, endpoint=endpoint, prompt=prompt_text)
725
- except TypeError:
726
- try:
727
- result = query_fn(history=history, endpoint=endpoint)
728
- except TypeError:
729
- try:
730
- result = query_fn(history, endpoint, prompt_text)
731
- except TypeError:
732
- try:
733
- result = query_fn(history, endpoint)
734
- except TypeError:
735
- result = query_fn(history)
772
+ result = _call_custom_api_handler(
773
+ query_fn,
774
+ history=history,
775
+ endpoint=endpoint,
776
+ prompt_text=prompt_text,
777
+ session_name=session_name,
778
+ )
736
779
  if isinstance(result, (dict, list)):
737
780
  return json.dumps(result)
738
781
  if result is None:
@@ -745,7 +788,7 @@ def _query_custom_api(history, prompt_text=""):
745
788
  print(Fore.RED + "⚠️ Custom API endpoint is not configured.")
746
789
  return ""
747
790
 
748
- payload = {"conversation": history, "prompt": prompt_text}
791
+ payload = {"conversation": history, "prompt": prompt_text, "session": session_name}
749
792
  r = requests.post(endpoint, json=payload, timeout=None)
750
793
  return r.text
751
794
 
@@ -855,10 +898,14 @@ def _query_gemini(history):
855
898
 
856
899
 
857
900
  class LLM:
858
- def __init__(self, backend):
901
+ def __init__(self, backend, session_name=""):
859
902
  self.backend = backend
903
+ self.session_name = str(session_name or "").strip()
860
904
  self.history = []
861
905
 
906
+ def set_session_name(self, session_name):
907
+ self.session_name = str(session_name or "").strip()
908
+
862
909
  def query(self, user_msg, last_output="", on_stream_start=None, workflow_context=""):
863
910
  followup = _is_followup_analysis_request(user_msg)
864
911
  if followup and (
@@ -917,7 +964,11 @@ class LLM:
917
964
  elif self.backend == "g4f":
918
965
  raw = _query_g4f(request_messages)
919
966
  elif self.backend == "api":
920
- raw = _query_custom_api(request_messages, prompt_text=prompt)
967
+ raw = _query_custom_api(
968
+ request_messages,
969
+ prompt_text=prompt,
970
+ session_name=self.session_name,
971
+ )
921
972
  elif self.backend == "gpt":
922
973
  raw = _query_openai(request_messages)
923
974
  elif self.backend == "anthropic":
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "eva-exploit"
7
- version = "3.4.2"
7
+ version = "3.4.3"
8
8
  description = "Exploit Vector Agent"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -95,7 +95,7 @@ class Eva:
95
95
  self.memory = json.loads(session_path.read_text())
96
96
  self.backend = self.memory.get("backend", backend)
97
97
 
98
- self.model = LLM(self.backend)
98
+ self.model = LLM(self.backend, self.sessionName)
99
99
  self._hydrate_model_context()
100
100
 
101
101
  def _hydrate_model_context(self):
@@ -164,7 +164,7 @@ class Eva:
164
164
  checkAPI()
165
165
  self.memory["backend"] = self.backend
166
166
  self.save()
167
- self.model = LLM(self.backend)
167
+ self.model = LLM(self.backend, self.sessionName)
168
168
  self._hydrate_model_context()
169
169
 
170
170
  def rename_session(self):
@@ -189,6 +189,7 @@ class Eva:
189
189
  self.session_path.rename(new_path)
190
190
  self.session_path = new_path
191
191
  self.sessionName = new_name
192
+ self.model.set_session_name(self.sessionName)
192
193
  self.save()
193
194
  cyber(f"Session renamed to {new_name}", color=Fore.GREEN)
194
195
 
@@ -70,7 +70,7 @@ def _custom_api_template(endpoint):
70
70
  "#!/usr/bin/env python3\n"
71
71
  "import requests\n\n"
72
72
  f"API_ENDPOINT = {json.dumps(target)}\n\n"
73
- "def query_custom_api(history, endpoint=None, prompt=None):\n"
73
+ "def query_custom_api(history, endpoint=None, session=None, prompt=None):\n"
74
74
  " target = endpoint or API_ENDPOINT\n"
75
75
  " compiled_prompt = str(prompt or \"\").strip()\n"
76
76
  " if not compiled_prompt:\n"
@@ -81,7 +81,7 @@ def _custom_api_template(endpoint):
81
81
  " payload = {\n"
82
82
  " \"prompt\": compiled_prompt,\n"
83
83
  " \"conversation\": history,\n"
84
- " \"session\": \"eva-session\",\n"
84
+ " \"session\": session,\n"
85
85
  " }\n"
86
86
  " r = requests.post(target, json=payload, timeout=None)\n"
87
87
  " try:\n"
@@ -249,11 +249,74 @@ def _is_newer(latest, current):
249
249
  _UPDATE_STATUS_CACHE = None
250
250
 
251
251
 
252
+ def _module_git_root():
253
+ here = Path(__file__).resolve()
254
+ for base in (here.parent, *here.parents):
255
+ if (base / ".git").exists():
256
+ return base
257
+ return None
258
+
259
+
260
+ def _installed_package_version():
261
+ try:
262
+ return metadata.version(PYPI_PACKAGE)
263
+ except metadata.PackageNotFoundError:
264
+ return None
265
+
266
+
267
+ def _is_path_in_repo(raw_path, repo_root):
268
+ if not raw_path:
269
+ return False
270
+ try:
271
+ candidate = Path(raw_path).expanduser()
272
+ if not candidate.exists():
273
+ return False
274
+ candidate = candidate.resolve()
275
+ return candidate.is_relative_to(repo_root.resolve())
276
+ except OSError:
277
+ return False
278
+
279
+
280
+ def _running_from_repo_checkout(repo_root):
281
+ main_module = sys.modules.get("__main__")
282
+ main_file = getattr(main_module, "__file__", "")
283
+ if _is_path_in_repo(main_file, repo_root):
284
+ return True
285
+ argv0 = sys.argv[0] if sys.argv else ""
286
+ if argv0 and Path(argv0).expanduser().exists() and _is_path_in_repo(argv0, repo_root):
287
+ return True
288
+ return False
289
+
290
+
291
+ def _read_local_version(base_path):
292
+ pyproject = base_path / "pyproject.toml"
293
+ if pyproject.exists():
294
+ try:
295
+ data = tomllib.loads(pyproject.read_text(encoding="utf-8"))
296
+ version = data.get("project", {}).get("version")
297
+ if version:
298
+ return str(version).strip()
299
+ except (tomllib.TOMLDecodeError, OSError):
300
+ pass
301
+
302
+ cfg_path = base_path / "config.py"
303
+ if cfg_path.exists():
304
+ try:
305
+ raw = cfg_path.read_text(encoding="utf-8")
306
+ except OSError:
307
+ return None
308
+ match = re.search(r'^APP_VERSION\s*=\s*["\']([^"\']+)["\']', raw, flags=re.MULTILINE)
309
+ if match:
310
+ return match.group(1).strip()
311
+ return None
312
+
313
+
252
314
  def _git_branch():
253
- if not Path(".git").exists():
315
+ repo_root = _module_git_root()
316
+ if repo_root is None:
254
317
  return "main"
255
318
  branch_detect = subprocess.run(
256
- ["git", "rev-parse", "--abbrev-ref", "HEAD"],
319
+ ["git", "-C", str(repo_root), "rev-parse", "--abbrev-ref", "HEAD"],
257
320
  capture_output=True,
258
321
  text=True
259
322
  )
@@ -263,13 +326,15 @@ def _git_branch():
263
326
 
264
327
 
265
328
  def _update_source():
266
- if Path(".git").exists():
329
+ repo_root = _module_git_root()
330
+ installed_version = _installed_package_version()
331
+ if repo_root is not None and command_exists("git") and _running_from_repo_checkout(repo_root):
267
332
  return "github"
268
- try:
269
- metadata.version(PYPI_PACKAGE)
333
+ if installed_version:
270
334
  return "pypi"
271
- except metadata.PackageNotFoundError:
335
+ if repo_root is not None and command_exists("git"):
272
336
  return "github"
337
+ return "pypi"
273
338
 
274
339
 
275
340
  def _can_reach_tls_host(host):
@@ -282,18 +347,25 @@ def _can_reach_tls_host(host):
282
347
 
283
348
 
284
349
  def get_current_version():
285
- try:
286
- return metadata.version(PYPI_PACKAGE)
287
- except metadata.PackageNotFoundError:
288
- pyproject = Path("pyproject.toml")
289
- if pyproject.exists():
290
- try:
291
- data = tomllib.loads(pyproject.read_text(encoding="utf-8"))
292
- version = data.get("project", {}).get("version")
293
- if version:
294
- return version
295
- except (tomllib.TOMLDecodeError, OSError):
296
- pass
350
+ repo_root = _module_git_root()
351
+ installed_version = _installed_package_version()
352
+
353
+ if repo_root is not None and _running_from_repo_checkout(repo_root):
354
+ local_version = _read_local_version(repo_root)
355
+ if local_version:
356
+ return local_version
357
+
358
+ if installed_version:
359
+ return installed_version
360
+
361
+ if repo_root is not None:
362
+ local_version = _read_local_version(repo_root)
363
+ if local_version:
364
+ return local_version
365
+
366
+ local_version = _read_local_version(Path.cwd())
367
+ if local_version:
368
+ return local_version
297
369
  return APP_VERSION
298
370
 
299
371
 
@@ -339,7 +411,11 @@ def get_update_status(force=False):
339
411
  latest = None
340
412
  available = bool(latest) and _is_newer(latest, current)
341
413
 
342
- command = f"git pull --tags origin {branch}" if source == "github" else "eva -u"
414
+ repo_root = _module_git_root()
415
+ if source == "github" and repo_root is not None:
416
+ command = f"git -C {shlex.quote(str(repo_root))} pull --tags origin {branch}"
417
+ else:
418
+ command = "eva -u"
343
419
  prefix = "|> Update github checkout running " if source == "github" else "|> Update eva to latest version running "
344
420
 
345
421
  _UPDATE_STATUS_CACHE = {
@@ -377,21 +453,22 @@ def run_self_update():
377
453
  source = status.get("source")
378
454
  print(Style.BRIGHT + Fore.MAGENTA + f"Update {latest} found! Installing . . . . " + Style.RESET_ALL)
379
455
 
456
+ repo_root = _module_git_root()
380
457
  updated = False
381
- with open(os.devnull, "w") as devnull:
382
- if source == "github" and Path(".git").exists() and command_exists("git"):
383
- branch = _git_branch()
384
- pull_result = subprocess.run(
385
- ["git", "pull", "--tags", "origin", branch],
386
- text=True
387
- )
388
- updated = pull_result.returncode == 0
389
- else:
390
- pip_result = subprocess.run(
391
- [sys.executable, "-m", "pip", "install", "--upgrade", PYPI_PACKAGE,"--break-system-packages"],
392
- text=True
393
- )
394
- updated = pip_result.returncode == 0
458
+ if source == "github" and repo_root is not None and command_exists("git"):
459
+ branch = _git_branch()
460
+ pull_result = subprocess.run(
461
+ ["git", "-C", str(repo_root), "pull", "--tags", "origin", branch],
462
+ text=True
463
+ )
464
+ updated = pull_result.returncode == 0
465
+ else:
466
+ pip_cmd = [sys.executable, "-m", "pip", "install", "--upgrade", PYPI_PACKAGE, "--break-system-packages"]
467
+ pip_result = subprocess.run(pip_cmd, text=True, capture_output=True)
468
+ if pip_result.returncode != 0 and "no such option: --break-system-packages" in (pip_result.stderr or "").lower():
469
+ pip_cmd = [sys.executable, "-m", "pip", "install", "--upgrade", PYPI_PACKAGE]
470
+ pip_result = subprocess.run(pip_cmd, text=True)
471
+ updated = pip_result.returncode == 0
395
472
 
396
473
  print(Fore.CYAN + "Almost done . . . . ")
397
474
  if updated:
@@ -402,7 +479,10 @@ def run_self_update():
402
479
 
403
480
  print(Fore.RED + "\n[!] Could not auto-update EVA in this environment.")
404
481
  if source == "github":
405
- print(Fore.YELLOW + f"Try manually: git pull --tags origin {_git_branch()}")
482
+ if repo_root is not None:
483
+ print(Fore.YELLOW + f"Try manually: git -C {shlex.quote(str(repo_root))} pull --tags origin {_git_branch()}")
484
+ else:
485
+ print(Fore.YELLOW + f"Try manually: git pull --tags origin {_git_branch()}")
406
486
  else:
407
487
  print(Fore.YELLOW + f"Try manually: {sys.executable} -m pip install --upgrade {PYPI_PACKAGE}")
408
488
  return 1
File without changes
File without changes
File without changes
File without changes