sharkit 0.2.0.dev2__tar.gz → 0.2.1__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 (35) hide show
  1. {sharkit-0.2.0.dev2 → sharkit-0.2.1}/PKG-INFO +1 -1
  2. {sharkit-0.2.0.dev2 → sharkit-0.2.1}/pyproject.toml +1 -1
  3. {sharkit-0.2.0.dev2 → sharkit-0.2.1}/src/sharkit/app.py +2 -2
  4. {sharkit-0.2.0.dev2 → sharkit-0.2.1}/src/sharkit/commands/builtins.py +95 -22
  5. {sharkit-0.2.0.dev2 → sharkit-0.2.1}/src/sharkit/output/renderer.py +4 -1
  6. {sharkit-0.2.0.dev2 → sharkit-0.2.1}/src/sharkit/tools/manager.py +15 -1
  7. {sharkit-0.2.0.dev2 → sharkit-0.2.1}/src/sharkit/tools/osint/recon/hybrid/blackbird.py +3 -1
  8. {sharkit-0.2.0.dev2 → sharkit-0.2.1}/src/sharkit/tools/osint/recon/username/maigret.py +1 -0
  9. {sharkit-0.2.0.dev2 → sharkit-0.2.1}/src/sharkit/tools/osint/recon/username/sherlock.py +1 -0
  10. {sharkit-0.2.0.dev2 → sharkit-0.2.1}/.gitignore +0 -0
  11. {sharkit-0.2.0.dev2 → sharkit-0.2.1}/LICENSE +0 -0
  12. {sharkit-0.2.0.dev2 → sharkit-0.2.1}/README.md +0 -0
  13. {sharkit-0.2.0.dev2 → sharkit-0.2.1}/src/sharkit/__init__.py +0 -0
  14. {sharkit-0.2.0.dev2 → sharkit-0.2.1}/src/sharkit/__main__.py +0 -0
  15. {sharkit-0.2.0.dev2 → sharkit-0.2.1}/src/sharkit/commands/__init__.py +0 -0
  16. {sharkit-0.2.0.dev2 → sharkit-0.2.1}/src/sharkit/commands/base.py +0 -0
  17. {sharkit-0.2.0.dev2 → sharkit-0.2.1}/src/sharkit/commands/registry.py +0 -0
  18. {sharkit-0.2.0.dev2 → sharkit-0.2.1}/src/sharkit/config/__init__.py +0 -0
  19. {sharkit-0.2.0.dev2 → sharkit-0.2.1}/src/sharkit/config/manager.py +0 -0
  20. {sharkit-0.2.0.dev2 → sharkit-0.2.1}/src/sharkit/config/paths.py +0 -0
  21. {sharkit-0.2.0.dev2 → sharkit-0.2.1}/src/sharkit/console/__init__.py +0 -0
  22. {sharkit-0.2.0.dev2 → sharkit-0.2.1}/src/sharkit/console/completion.py +0 -0
  23. {sharkit-0.2.0.dev2 → sharkit-0.2.1}/src/sharkit/console/prompt.py +0 -0
  24. {sharkit-0.2.0.dev2 → sharkit-0.2.1}/src/sharkit/console/repl.py +0 -0
  25. {sharkit-0.2.0.dev2 → sharkit-0.2.1}/src/sharkit/exceptions.py +0 -0
  26. {sharkit-0.2.0.dev2 → sharkit-0.2.1}/src/sharkit/history/__init__.py +0 -0
  27. {sharkit-0.2.0.dev2 → sharkit-0.2.1}/src/sharkit/history/manager.py +0 -0
  28. {sharkit-0.2.0.dev2 → sharkit-0.2.1}/src/sharkit/network/__init__.py +0 -0
  29. {sharkit-0.2.0.dev2 → sharkit-0.2.1}/src/sharkit/network/client.py +0 -0
  30. {sharkit-0.2.0.dev2 → sharkit-0.2.1}/src/sharkit/output/__init__.py +0 -0
  31. {sharkit-0.2.0.dev2 → sharkit-0.2.1}/src/sharkit/output/theme.py +0 -0
  32. {sharkit-0.2.0.dev2 → sharkit-0.2.1}/src/sharkit/tools/__init__.py +0 -0
  33. {sharkit-0.2.0.dev2 → sharkit-0.2.1}/src/sharkit/tools/base.py +0 -0
  34. {sharkit-0.2.0.dev2 → sharkit-0.2.1}/src/sharkit/tools/loader.py +0 -0
  35. {sharkit-0.2.0.dev2 → sharkit-0.2.1}/src/sharkit/tools/registry.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: sharkit
3
- Version: 0.2.0.dev2
3
+ Version: 0.2.1
4
4
  Summary: OSINT / HUMINT / GEOINT research framework
5
5
  Project-URL: Homepage, https://github.com/sshsrv/sharkit
6
6
  Project-URL: Repository, https://github.com/sshsrv/sharkit
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "sharkit"
3
- version = "0.2.0.dev2"
3
+ version = "0.2.1"
4
4
  description = "OSINT / HUMINT / GEOINT research framework"
5
5
  readme = "README.md"
6
6
  license = "MIT"
@@ -20,7 +20,7 @@ NON_LINUX_MESSAGE = (
20
20
  "it was built for open water,\n"
21
21
  "where it can actually swim.\n"
22
22
  "\n"
23
- "windows/mac is more of a glass aquarium.\n"
23
+ "windows is more of a glass aquarium.\n"
24
24
  "tidy, bright, and a little too enclosed.\n"
25
25
  "\n"
26
26
  "the shark doesn't dislike the aquarium.\n"
@@ -37,7 +37,7 @@ def main() -> int:
37
37
  sys.stdout.flush()
38
38
  renderer = Renderer()
39
39
 
40
- if sys.platform != "linux":
40
+ if sys.platform == "win32":
41
41
  renderer.banner(tool_count=0, message=NON_LINUX_MESSAGE)
42
42
  return 1
43
43
 
@@ -193,10 +193,16 @@ class UseCommand(Command):
193
193
  self._log(context, f'Tool "{name}" is not installed. Run: install {name}')
194
194
  return None
195
195
  renderer = context.session.get("renderer")
196
+ first_progress = [True]
196
197
 
197
198
  def on_progress(msg: str) -> None:
198
199
  if renderer is not None:
199
- renderer.log_line(f"install {display}", msg, color=GREEN)
200
+ tag = f"install {display}"
201
+ if first_progress[0]:
202
+ renderer.gutter(tag, msg, GREEN, is_first=True)
203
+ first_progress[0] = False
204
+ else:
205
+ renderer.gutter(tag, msg, GREEN, is_first=False)
200
206
 
201
207
  ok, message = tool_manager.install(name, spec, on_progress=on_progress)
202
208
  if not ok:
@@ -382,7 +388,13 @@ class SetCommand(Command):
382
388
  tool_instance.set_option(key, value)
383
389
  renderer = context.session.get("renderer")
384
390
  if renderer is not None:
385
- renderer.log_line(f"set ({context.current_tool})", f"{key} = {value}")
391
+ tool_registry = context.session.get("tool_registry")
392
+ display = context.current_tool
393
+ if tool_registry is not None and context.current_tool is not None:
394
+ display = tool_registry.format_display(
395
+ tool_registry.get_tool_path(context.current_tool),
396
+ )
397
+ renderer.log_line(f"set {display}", f"{key} = {value}")
386
398
  return None
387
399
  return f"Set {key} = {value}"
388
400
  except Exception as e:
@@ -627,24 +639,44 @@ class InstallCommand(Command):
627
639
  tool_cls = tool_registry.get_tool(name)
628
640
  if tool_cls is None or tool_cls.metadata.install is None:
629
641
  return f'Tool "{name}" is not an external tool or was not found.'
630
- display = tool_registry.format_display(tool_registry.get_tool_path(name))
631
- if tool_manager.is_installed(name):
642
+ tool_name = tool_cls.metadata.name
643
+ display = tool_registry.format_display(tool_registry.get_tool_path(tool_name))
644
+ if tool_manager.is_installed(tool_name):
632
645
  renderer = context.session.get("renderer")
633
646
  if renderer is not None:
634
647
  renderer.log_line(f"install {display}", "already installed", color=GREEN)
635
648
  return None
636
649
  renderer = context.session.get("renderer")
650
+ first_progress = [True]
637
651
 
638
652
  def on_progress(msg: str) -> None:
639
653
  if renderer is not None:
640
- renderer.log_line(f"install {display}", msg, color=GREEN)
654
+ tag = f"install {display}"
655
+ if first_progress[0]:
656
+ renderer.gutter(tag, msg, GREEN, is_first=True)
657
+ first_progress[0] = False
658
+ else:
659
+ renderer.gutter(tag, msg, GREEN, is_first=False)
641
660
 
642
- ok, message = tool_manager.install(name, tool_cls.metadata.install, on_progress=on_progress)
661
+ install_spec = tool_cls.metadata.install
662
+ ok, message = tool_manager.install(
663
+ tool_name, install_spec, on_progress=on_progress
664
+ )
643
665
  if renderer is not None:
666
+ tag = f"install {display}"
644
667
  if ok:
645
- renderer.log_line(f"install {display}", "installed", color=GREEN)
668
+ msg = "installed"
669
+ elif message == "Aborted":
670
+ msg = "aborted"
671
+ print("\r\033[K", end="")
646
672
  else:
647
- renderer.log_line(f"install {display}", f"failed: {message}", color=GREEN)
673
+ msg = f"failed: {message}"
674
+ if first_progress[0]:
675
+ renderer.log_line(tag, msg, color=GREEN)
676
+ else:
677
+ lines = msg.splitlines() or [""]
678
+ for line in lines:
679
+ renderer.gutter(tag, line, GREEN, is_first=False)
648
680
  return None
649
681
  return str(message)
650
682
 
@@ -671,24 +703,44 @@ class UpgradeCommand(Command):
671
703
  tool_cls = tool_registry.get_tool(name)
672
704
  if tool_cls is None or tool_cls.metadata.install is None:
673
705
  return f'Tool "{name}" is not an external tool or was not found.'
674
- display = tool_registry.format_display(tool_registry.get_tool_path(name))
675
- if not tool_manager.is_installed(name):
706
+ tool_name = tool_cls.metadata.name
707
+ display = tool_registry.format_display(tool_registry.get_tool_path(tool_name))
708
+ if not tool_manager.is_installed(tool_name):
676
709
  renderer = context.session.get("renderer")
677
710
  if renderer is not None:
678
711
  renderer.log_line(f"upgrade {display}", "not installed (skipped)", color=BLUE)
679
712
  return None
680
713
  renderer = context.session.get("renderer")
714
+ first_progress = [True]
681
715
 
682
716
  def on_progress(msg: str) -> None:
683
717
  if renderer is not None:
684
- renderer.log_line(f"upgrade {display}", msg, color=BLUE)
718
+ tag = f"upgrade {display}"
719
+ if first_progress[0]:
720
+ renderer.gutter(tag, msg, BLUE, is_first=True)
721
+ first_progress[0] = False
722
+ else:
723
+ renderer.gutter(tag, msg, BLUE, is_first=False)
685
724
 
686
- ok, message = tool_manager.update(name, tool_cls.metadata.install, on_progress=on_progress)
725
+ upgrade_spec = tool_cls.metadata.install
726
+ ok, message = tool_manager.update(
727
+ tool_name, upgrade_spec, on_progress=on_progress
728
+ )
687
729
  if renderer is not None:
730
+ tag = f"upgrade {display}"
688
731
  if ok:
689
- renderer.log_line(f"upgrade {display}", "upgraded", color=BLUE)
732
+ msg = "upgraded"
733
+ elif message == "Aborted":
734
+ msg = "aborted"
735
+ print("\r\033[K", end="")
690
736
  else:
691
- renderer.log_line(f"upgrade {display}", f"failed: {message}", color=BLUE)
737
+ msg = f"failed: {message}"
738
+ if first_progress[0]:
739
+ renderer.log_line(tag, msg, color=BLUE)
740
+ else:
741
+ lines = msg.splitlines() or [""]
742
+ for line in lines:
743
+ renderer.gutter(tag, line, BLUE, is_first=False)
692
744
  return None
693
745
  return str(message)
694
746
 
@@ -721,17 +773,37 @@ class UpgradeCommand(Command):
721
773
  renderer.log_line(f"upgrade {display}", "not installed (skipped)", color=BLUE)
722
774
  continue
723
775
  renderer = context.session.get("renderer")
724
-
725
- def on_progress(msg: str, display: str = display, renderer: Any = renderer) -> None:
726
- if renderer is not None:
727
- renderer.log_line(f"upgrade {display}", msg, color=BLUE)
776
+ first_progress = [True]
777
+
778
+ def on_progress(
779
+ msg: str,
780
+ _first: list[bool] = first_progress,
781
+ _tag: str = f"upgrade {display}",
782
+ _renderer: Any = renderer,
783
+ ) -> None:
784
+ if _renderer is not None:
785
+ if _first[0]:
786
+ _renderer.gutter(_tag, msg, BLUE, is_first=True)
787
+ _first[0] = False
788
+ else:
789
+ _renderer.gutter(_tag, msg, BLUE, is_first=False)
728
790
 
729
791
  ok, message = tool_manager.update(name, spec, on_progress=on_progress)
730
792
  if renderer is not None:
793
+ tag = f"upgrade {display}"
731
794
  if ok:
732
- renderer.log_line(f"upgrade {display}", "upgraded", color=BLUE)
795
+ msg = "upgraded"
796
+ elif message == "Aborted":
797
+ msg = "aborted"
798
+ print("\r\033[K", end="")
799
+ else:
800
+ msg = f"failed: {message}"
801
+ if first_progress[0]:
802
+ renderer.log_line(tag, msg, color=BLUE)
733
803
  else:
734
- renderer.log_line(f"upgrade {display}", f"failed: {message}", color=BLUE)
804
+ lines = msg.splitlines() or [""]
805
+ for line in lines:
806
+ renderer.gutter(tag, line, BLUE, is_first=False)
735
807
  return None
736
808
 
737
809
 
@@ -753,9 +825,10 @@ class RemoveCommand(Command):
753
825
  tool_cls = tool_registry.get_tool(name)
754
826
  if tool_cls is None or tool_cls.metadata.install is None:
755
827
  return f'Tool "{name}" is not an external tool or was not found.'
756
- display = tool_registry.format_display(tool_registry.get_tool_path(name))
828
+ tool_name = tool_cls.metadata.name
829
+ display = tool_registry.format_display(tool_registry.get_tool_path(tool_name))
757
830
  renderer = context.session.get("renderer")
758
- ok, message = tool_manager.uninstall(name)
831
+ ok, message = tool_manager.uninstall(tool_name)
759
832
  if renderer is not None:
760
833
  if ok:
761
834
  renderer.log_line(f"remove {display}", "removed", color=RED)
@@ -253,7 +253,10 @@ class Renderer:
253
253
  print(text, end="")
254
254
 
255
255
  def log_line(self, tag: str, message: str, color: str = PINK) -> None:
256
- print(f"{color}{BOLD}{tag} - {RESET}{message}")
256
+ lines = message.splitlines() or [""]
257
+ self.gutter(tag, lines[0], color, is_first=True)
258
+ for line in lines[1:]:
259
+ print(f"{color}{BOLD}│{RESET} {line}")
257
260
 
258
261
  def gutter(self, name: str, line: str, color: str, is_first: bool) -> None:
259
262
  if is_first:
@@ -54,7 +54,11 @@ class ToolManager:
54
54
  self._run([pip, "install", *spec.pip_args])
55
55
  dest.joinpath(".installed").write_text(name)
56
56
  return True, f'Tool "{name}" installed.'
57
+ except KeyboardInterrupt:
58
+ shutil.rmtree(dest, ignore_errors=True)
59
+ return False, "Aborted"
57
60
  except Exception as e:
61
+ shutil.rmtree(dest, ignore_errors=True)
58
62
  return False, f'Failed to install "{name}": {e}'
59
63
 
60
64
  def update(
@@ -82,6 +86,8 @@ class ToolManager:
82
86
  on_progress("upgrading packages...")
83
87
  self._run([pip, "install", "--upgrade", *spec.pip_args])
84
88
  return True, f'Tool "{name}" updated.'
89
+ except KeyboardInterrupt:
90
+ return False, "Aborted"
85
91
  except Exception as e:
86
92
  return False, f'Failed to update "{name}": {e}'
87
93
 
@@ -96,4 +102,12 @@ class ToolManager:
96
102
  return False, f'Failed to uninstall "{name}": {e}'
97
103
 
98
104
  def _run(self, cmd: list[str]) -> None:
99
- subprocess.run(cmd, check=True, capture_output=True)
105
+ result = subprocess.run(cmd, capture_output=True, text=True)
106
+ if result.returncode != 0:
107
+ stderr = result.stderr.strip() if result.stderr else ""
108
+ stdout = result.stdout.strip() if result.stdout else ""
109
+ raw = stderr or stdout or "No output"
110
+ # Truncate long build output — keep last 20 lines where the actual error lives
111
+ lines = raw.splitlines()
112
+ detail = "\n".join(lines[-20:]) if len(lines) > 20 else raw
113
+ raise RuntimeError(detail)
@@ -107,7 +107,7 @@ class BlackbirdTool(Tool):
107
107
  success=False,
108
108
  error="Both 'type' and 'query' options are required.",
109
109
  )
110
- args = [f"--{stype}", query, "--no-update"]
110
+ args = [f"--{stype}", query]
111
111
  if parse_bool(context.options.get("pdf")):
112
112
  args.append("--pdf")
113
113
  renderer = context.renderer
@@ -191,6 +191,8 @@ class BlackbirdTool(Tool):
191
191
  proc.kill()
192
192
  current = ""
193
193
  if renderer is not None:
194
+ # \r\033[K clears the ^C echo from the terminal before printing.
195
+ print("\r\033[K", end="")
194
196
  renderer.gutter(name, "Run aborted (Ctrl+C).", tool_color, first)
195
197
  else:
196
198
  print("Run aborted (Ctrl+C).")
@@ -233,6 +233,7 @@ class MaigretTool(Tool):
233
233
  proc.kill()
234
234
  current = ""
235
235
  if renderer is not None:
236
+ print("\r\033[K", end="")
236
237
  renderer.gutter(name, "Run aborted (Ctrl+C).", tool_color, first)
237
238
  else:
238
239
  print("Run aborted (Ctrl+C).")
@@ -233,6 +233,7 @@ class SherlockTool(Tool):
233
233
  proc.kill()
234
234
  current = ""
235
235
  if renderer is not None:
236
+ print("\r\033[K", end="")
236
237
  renderer.gutter(name, "Run aborted (Ctrl+C).", tool_color, first)
237
238
  else:
238
239
  print("Run aborted (Ctrl+C).")
File without changes
File without changes
File without changes