souleyez 2.43.29__py3-none-any.whl → 3.0.0__py3-none-any.whl

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 (358) hide show
  1. souleyez/__init__.py +1 -2
  2. souleyez/ai/__init__.py +21 -15
  3. souleyez/ai/action_mapper.py +249 -150
  4. souleyez/ai/chain_advisor.py +116 -100
  5. souleyez/ai/claude_provider.py +29 -28
  6. souleyez/ai/context_builder.py +80 -62
  7. souleyez/ai/executor.py +158 -117
  8. souleyez/ai/feedback_handler.py +136 -121
  9. souleyez/ai/llm_factory.py +27 -20
  10. souleyez/ai/llm_provider.py +4 -2
  11. souleyez/ai/ollama_provider.py +6 -9
  12. souleyez/ai/ollama_service.py +44 -37
  13. souleyez/ai/path_scorer.py +91 -76
  14. souleyez/ai/recommender.py +176 -144
  15. souleyez/ai/report_context.py +74 -73
  16. souleyez/ai/report_service.py +84 -66
  17. souleyez/ai/result_parser.py +222 -229
  18. souleyez/ai/safety.py +67 -44
  19. souleyez/auth/__init__.py +23 -22
  20. souleyez/auth/audit.py +36 -26
  21. souleyez/auth/engagement_access.py +65 -48
  22. souleyez/auth/permissions.py +14 -3
  23. souleyez/auth/session_manager.py +54 -37
  24. souleyez/auth/user_manager.py +109 -64
  25. souleyez/commands/audit.py +40 -43
  26. souleyez/commands/auth.py +35 -15
  27. souleyez/commands/deliverables.py +55 -50
  28. souleyez/commands/engagement.py +47 -28
  29. souleyez/commands/license.py +32 -23
  30. souleyez/commands/screenshots.py +36 -32
  31. souleyez/commands/user.py +82 -36
  32. souleyez/config.py +52 -44
  33. souleyez/core/credential_tester.py +87 -81
  34. souleyez/core/cve_mappings.py +179 -192
  35. souleyez/core/cve_matcher.py +162 -148
  36. souleyez/core/msf_auto_mapper.py +100 -83
  37. souleyez/core/msf_chain_engine.py +294 -256
  38. souleyez/core/msf_database.py +153 -70
  39. souleyez/core/msf_integration.py +679 -673
  40. souleyez/core/msf_rpc_client.py +40 -42
  41. souleyez/core/msf_rpc_manager.py +77 -79
  42. souleyez/core/msf_sync_manager.py +241 -181
  43. souleyez/core/network_utils.py +22 -15
  44. souleyez/core/parser_handler.py +34 -25
  45. souleyez/core/pending_chains.py +114 -63
  46. souleyez/core/templates.py +158 -107
  47. souleyez/core/tool_chaining.py +9564 -2881
  48. souleyez/core/version_utils.py +79 -94
  49. souleyez/core/vuln_correlation.py +136 -89
  50. souleyez/core/web_utils.py +33 -32
  51. souleyez/data/wordlists/ad_users.txt +378 -0
  52. souleyez/data/wordlists/api_endpoints_large.txt +769 -0
  53. souleyez/data/wordlists/home_dir_sensitive.txt +39 -0
  54. souleyez/data/wordlists/lfi_payloads.txt +82 -0
  55. souleyez/data/wordlists/passwords_brute.txt +1548 -0
  56. souleyez/data/wordlists/passwords_crack.txt +2479 -0
  57. souleyez/data/wordlists/passwords_spray.txt +386 -0
  58. souleyez/data/wordlists/subdomains_large.txt +5057 -0
  59. souleyez/data/wordlists/usernames_common.txt +694 -0
  60. souleyez/data/wordlists/web_dirs_large.txt +4769 -0
  61. souleyez/detection/__init__.py +1 -1
  62. souleyez/detection/attack_signatures.py +12 -17
  63. souleyez/detection/mitre_mappings.py +61 -55
  64. souleyez/detection/validator.py +97 -86
  65. souleyez/devtools.py +23 -10
  66. souleyez/docs/README.md +4 -4
  67. souleyez/docs/api-reference/cli-commands.md +2 -2
  68. souleyez/docs/developer-guide/adding-new-tools.md +562 -0
  69. souleyez/docs/user-guide/auto-chaining.md +30 -8
  70. souleyez/docs/user-guide/getting-started.md +1 -1
  71. souleyez/docs/user-guide/installation.md +26 -3
  72. souleyez/docs/user-guide/metasploit-integration.md +2 -2
  73. souleyez/docs/user-guide/rbac.md +1 -1
  74. souleyez/docs/user-guide/scope-management.md +1 -1
  75. souleyez/docs/user-guide/siem-integration.md +1 -1
  76. souleyez/docs/user-guide/tools-reference.md +1 -8
  77. souleyez/docs/user-guide/worker-management.md +1 -1
  78. souleyez/engine/background.py +1239 -535
  79. souleyez/engine/base.py +4 -1
  80. souleyez/engine/job_status.py +17 -49
  81. souleyez/engine/log_sanitizer.py +103 -77
  82. souleyez/engine/manager.py +38 -7
  83. souleyez/engine/result_handler.py +2200 -1550
  84. souleyez/engine/worker_manager.py +50 -41
  85. souleyez/export/evidence_bundle.py +72 -62
  86. souleyez/feature_flags/features.py +16 -20
  87. souleyez/feature_flags.py +5 -9
  88. souleyez/handlers/__init__.py +11 -0
  89. souleyez/handlers/base.py +188 -0
  90. souleyez/handlers/bash_handler.py +277 -0
  91. souleyez/handlers/bloodhound_handler.py +243 -0
  92. souleyez/handlers/certipy_handler.py +311 -0
  93. souleyez/handlers/crackmapexec_handler.py +486 -0
  94. souleyez/handlers/dnsrecon_handler.py +344 -0
  95. souleyez/handlers/enum4linux_handler.py +400 -0
  96. souleyez/handlers/evil_winrm_handler.py +493 -0
  97. souleyez/handlers/ffuf_handler.py +815 -0
  98. souleyez/handlers/gobuster_handler.py +1114 -0
  99. souleyez/handlers/gpp_extract_handler.py +334 -0
  100. souleyez/handlers/hashcat_handler.py +444 -0
  101. souleyez/handlers/hydra_handler.py +564 -0
  102. souleyez/handlers/impacket_getuserspns_handler.py +343 -0
  103. souleyez/handlers/impacket_psexec_handler.py +222 -0
  104. souleyez/handlers/impacket_secretsdump_handler.py +426 -0
  105. souleyez/handlers/john_handler.py +286 -0
  106. souleyez/handlers/katana_handler.py +425 -0
  107. souleyez/handlers/kerbrute_handler.py +298 -0
  108. souleyez/handlers/ldapsearch_handler.py +636 -0
  109. souleyez/handlers/lfi_extract_handler.py +464 -0
  110. souleyez/handlers/msf_auxiliary_handler.py +409 -0
  111. souleyez/handlers/msf_exploit_handler.py +380 -0
  112. souleyez/handlers/nikto_handler.py +413 -0
  113. souleyez/handlers/nmap_handler.py +821 -0
  114. souleyez/handlers/nuclei_handler.py +359 -0
  115. souleyez/handlers/nxc_handler.py +417 -0
  116. souleyez/handlers/rdp_sec_check_handler.py +353 -0
  117. souleyez/handlers/registry.py +292 -0
  118. souleyez/handlers/responder_handler.py +232 -0
  119. souleyez/handlers/service_explorer_handler.py +434 -0
  120. souleyez/handlers/smbclient_handler.py +344 -0
  121. souleyez/handlers/smbmap_handler.py +510 -0
  122. souleyez/handlers/smbpasswd_handler.py +296 -0
  123. souleyez/handlers/sqlmap_handler.py +1116 -0
  124. souleyez/handlers/theharvester_handler.py +601 -0
  125. souleyez/handlers/web_login_test_handler.py +327 -0
  126. souleyez/handlers/whois_handler.py +277 -0
  127. souleyez/handlers/wpscan_handler.py +554 -0
  128. souleyez/history.py +32 -16
  129. souleyez/importers/msf_importer.py +106 -75
  130. souleyez/importers/smart_importer.py +208 -147
  131. souleyez/integrations/siem/__init__.py +10 -10
  132. souleyez/integrations/siem/base.py +17 -18
  133. souleyez/integrations/siem/elastic.py +108 -122
  134. souleyez/integrations/siem/factory.py +207 -80
  135. souleyez/integrations/siem/googlesecops.py +146 -154
  136. souleyez/integrations/siem/rule_mappings/__init__.py +1 -1
  137. souleyez/integrations/siem/rule_mappings/wazuh_rules.py +8 -5
  138. souleyez/integrations/siem/sentinel.py +107 -109
  139. souleyez/integrations/siem/splunk.py +246 -212
  140. souleyez/integrations/siem/wazuh.py +65 -71
  141. souleyez/integrations/wazuh/__init__.py +5 -5
  142. souleyez/integrations/wazuh/client.py +70 -93
  143. souleyez/integrations/wazuh/config.py +85 -57
  144. souleyez/integrations/wazuh/host_mapper.py +28 -36
  145. souleyez/integrations/wazuh/sync.py +78 -68
  146. souleyez/intelligence/__init__.py +4 -5
  147. souleyez/intelligence/correlation_analyzer.py +309 -295
  148. souleyez/intelligence/exploit_knowledge.py +661 -623
  149. souleyez/intelligence/exploit_suggestions.py +159 -139
  150. souleyez/intelligence/gap_analyzer.py +132 -97
  151. souleyez/intelligence/gap_detector.py +251 -214
  152. souleyez/intelligence/sensitive_tables.py +266 -129
  153. souleyez/intelligence/service_parser.py +137 -123
  154. souleyez/intelligence/surface_analyzer.py +407 -268
  155. souleyez/intelligence/target_parser.py +159 -162
  156. souleyez/licensing/__init__.py +6 -6
  157. souleyez/licensing/validator.py +17 -19
  158. souleyez/log_config.py +79 -54
  159. souleyez/main.py +1505 -687
  160. souleyez/migrations/fix_job_counter.py +16 -14
  161. souleyez/parsers/bloodhound_parser.py +41 -39
  162. souleyez/parsers/crackmapexec_parser.py +178 -111
  163. souleyez/parsers/dalfox_parser.py +72 -77
  164. souleyez/parsers/dnsrecon_parser.py +103 -91
  165. souleyez/parsers/enum4linux_parser.py +183 -153
  166. souleyez/parsers/ffuf_parser.py +29 -25
  167. souleyez/parsers/gobuster_parser.py +301 -41
  168. souleyez/parsers/hashcat_parser.py +324 -79
  169. souleyez/parsers/http_fingerprint_parser.py +350 -103
  170. souleyez/parsers/hydra_parser.py +131 -111
  171. souleyez/parsers/impacket_parser.py +231 -178
  172. souleyez/parsers/john_parser.py +98 -86
  173. souleyez/parsers/katana_parser.py +316 -0
  174. souleyez/parsers/msf_parser.py +943 -498
  175. souleyez/parsers/nikto_parser.py +346 -65
  176. souleyez/parsers/nmap_parser.py +262 -174
  177. souleyez/parsers/nuclei_parser.py +40 -44
  178. souleyez/parsers/responder_parser.py +26 -26
  179. souleyez/parsers/searchsploit_parser.py +74 -74
  180. souleyez/parsers/service_explorer_parser.py +279 -0
  181. souleyez/parsers/smbmap_parser.py +180 -124
  182. souleyez/parsers/sqlmap_parser.py +434 -308
  183. souleyez/parsers/theharvester_parser.py +75 -57
  184. souleyez/parsers/whois_parser.py +135 -94
  185. souleyez/parsers/wpscan_parser.py +278 -190
  186. souleyez/plugins/afp.py +44 -36
  187. souleyez/plugins/afp_brute.py +114 -46
  188. souleyez/plugins/ard.py +48 -37
  189. souleyez/plugins/bloodhound.py +95 -61
  190. souleyez/plugins/certipy.py +303 -0
  191. souleyez/plugins/crackmapexec.py +186 -85
  192. souleyez/plugins/dalfox.py +120 -59
  193. souleyez/plugins/dns_hijack.py +146 -41
  194. souleyez/plugins/dnsrecon.py +97 -61
  195. souleyez/plugins/enum4linux.py +91 -66
  196. souleyez/plugins/evil_winrm.py +291 -0
  197. souleyez/plugins/ffuf.py +166 -90
  198. souleyez/plugins/firmware_extract.py +133 -29
  199. souleyez/plugins/gobuster.py +387 -190
  200. souleyez/plugins/gpp_extract.py +393 -0
  201. souleyez/plugins/hashcat.py +100 -73
  202. souleyez/plugins/http_fingerprint.py +913 -267
  203. souleyez/plugins/hydra.py +566 -200
  204. souleyez/plugins/impacket_getnpusers.py +117 -69
  205. souleyez/plugins/impacket_psexec.py +84 -64
  206. souleyez/plugins/impacket_secretsdump.py +103 -69
  207. souleyez/plugins/impacket_smbclient.py +89 -75
  208. souleyez/plugins/john.py +86 -69
  209. souleyez/plugins/katana.py +313 -0
  210. souleyez/plugins/kerbrute.py +237 -0
  211. souleyez/plugins/lfi_extract.py +541 -0
  212. souleyez/plugins/macos_ssh.py +117 -48
  213. souleyez/plugins/mdns.py +35 -30
  214. souleyez/plugins/msf_auxiliary.py +253 -130
  215. souleyez/plugins/msf_exploit.py +239 -161
  216. souleyez/plugins/nikto.py +134 -78
  217. souleyez/plugins/nmap.py +275 -91
  218. souleyez/plugins/nuclei.py +180 -89
  219. souleyez/plugins/nxc.py +285 -0
  220. souleyez/plugins/plugin_base.py +35 -36
  221. souleyez/plugins/plugin_template.py +13 -5
  222. souleyez/plugins/rdp_sec_check.py +130 -0
  223. souleyez/plugins/responder.py +112 -71
  224. souleyez/plugins/router_http_brute.py +76 -65
  225. souleyez/plugins/router_ssh_brute.py +118 -41
  226. souleyez/plugins/router_telnet_brute.py +124 -42
  227. souleyez/plugins/routersploit.py +91 -59
  228. souleyez/plugins/routersploit_exploit.py +77 -55
  229. souleyez/plugins/searchsploit.py +91 -77
  230. souleyez/plugins/service_explorer.py +1160 -0
  231. souleyez/plugins/smbmap.py +122 -72
  232. souleyez/plugins/smbpasswd.py +215 -0
  233. souleyez/plugins/sqlmap.py +301 -113
  234. souleyez/plugins/theharvester.py +127 -75
  235. souleyez/plugins/tr069.py +79 -57
  236. souleyez/plugins/upnp.py +65 -47
  237. souleyez/plugins/upnp_abuse.py +73 -55
  238. souleyez/plugins/vnc_access.py +129 -42
  239. souleyez/plugins/vnc_brute.py +109 -38
  240. souleyez/plugins/web_login_test.py +417 -0
  241. souleyez/plugins/whois.py +77 -58
  242. souleyez/plugins/wpscan.py +219 -69
  243. souleyez/reporting/__init__.py +2 -1
  244. souleyez/reporting/attack_chain.py +411 -346
  245. souleyez/reporting/charts.py +436 -501
  246. souleyez/reporting/compliance_mappings.py +334 -201
  247. souleyez/reporting/detection_report.py +126 -125
  248. souleyez/reporting/formatters.py +828 -591
  249. souleyez/reporting/generator.py +386 -302
  250. souleyez/reporting/metrics.py +72 -75
  251. souleyez/scanner.py +35 -29
  252. souleyez/security/__init__.py +37 -11
  253. souleyez/security/scope_validator.py +175 -106
  254. souleyez/security/validation.py +237 -149
  255. souleyez/security.py +22 -6
  256. souleyez/storage/credentials.py +247 -186
  257. souleyez/storage/crypto.py +296 -129
  258. souleyez/storage/database.py +73 -50
  259. souleyez/storage/db.py +58 -36
  260. souleyez/storage/deliverable_evidence.py +177 -128
  261. souleyez/storage/deliverable_exporter.py +282 -246
  262. souleyez/storage/deliverable_templates.py +134 -116
  263. souleyez/storage/deliverables.py +135 -130
  264. souleyez/storage/engagements.py +109 -56
  265. souleyez/storage/evidence.py +181 -152
  266. souleyez/storage/execution_log.py +31 -17
  267. souleyez/storage/exploit_attempts.py +93 -57
  268. souleyez/storage/exploits.py +67 -36
  269. souleyez/storage/findings.py +48 -61
  270. souleyez/storage/hosts.py +176 -144
  271. souleyez/storage/migrate_to_engagements.py +43 -19
  272. souleyez/storage/migrations/_001_add_credential_enhancements.py +22 -12
  273. souleyez/storage/migrations/_002_add_status_tracking.py +10 -7
  274. souleyez/storage/migrations/_003_add_execution_log.py +14 -8
  275. souleyez/storage/migrations/_005_screenshots.py +13 -5
  276. souleyez/storage/migrations/_006_deliverables.py +13 -5
  277. souleyez/storage/migrations/_007_deliverable_templates.py +12 -7
  278. souleyez/storage/migrations/_008_add_nuclei_table.py +10 -4
  279. souleyez/storage/migrations/_010_evidence_linking.py +17 -10
  280. souleyez/storage/migrations/_011_timeline_tracking.py +20 -13
  281. souleyez/storage/migrations/_012_team_collaboration.py +34 -21
  282. souleyez/storage/migrations/_013_add_host_tags.py +12 -6
  283. souleyez/storage/migrations/_014_exploit_attempts.py +22 -10
  284. souleyez/storage/migrations/_015_add_mac_os_fields.py +15 -7
  285. souleyez/storage/migrations/_016_add_domain_field.py +10 -4
  286. souleyez/storage/migrations/_017_msf_sessions.py +16 -8
  287. souleyez/storage/migrations/_018_add_osint_target.py +10 -6
  288. souleyez/storage/migrations/_019_add_engagement_type.py +10 -6
  289. souleyez/storage/migrations/_020_add_rbac.py +36 -15
  290. souleyez/storage/migrations/_021_wazuh_integration.py +20 -8
  291. souleyez/storage/migrations/_022_wazuh_indexer_columns.py +6 -4
  292. souleyez/storage/migrations/_023_fix_detection_results_fk.py +16 -6
  293. souleyez/storage/migrations/_024_wazuh_vulnerabilities.py +26 -10
  294. souleyez/storage/migrations/_025_multi_siem_support.py +3 -5
  295. souleyez/storage/migrations/_026_add_engagement_scope.py +31 -12
  296. souleyez/storage/migrations/_027_multi_siem_persistence.py +32 -15
  297. souleyez/storage/migrations/__init__.py +26 -26
  298. souleyez/storage/migrations/migration_manager.py +19 -19
  299. souleyez/storage/msf_sessions.py +100 -65
  300. souleyez/storage/osint.py +17 -24
  301. souleyez/storage/recommendation_engine.py +269 -235
  302. souleyez/storage/screenshots.py +33 -32
  303. souleyez/storage/smb_shares.py +136 -92
  304. souleyez/storage/sqlmap_data.py +183 -128
  305. souleyez/storage/team_collaboration.py +135 -141
  306. souleyez/storage/timeline_tracker.py +122 -94
  307. souleyez/storage/wazuh_vulns.py +64 -66
  308. souleyez/storage/web_paths.py +33 -37
  309. souleyez/testing/credential_tester.py +221 -205
  310. souleyez/ui/__init__.py +1 -1
  311. souleyez/ui/ai_quotes.py +12 -12
  312. souleyez/ui/attack_surface.py +2439 -1516
  313. souleyez/ui/chain_rules_view.py +914 -382
  314. souleyez/ui/correlation_view.py +312 -230
  315. souleyez/ui/dashboard.py +2382 -1130
  316. souleyez/ui/deliverables_view.py +148 -62
  317. souleyez/ui/design_system.py +13 -13
  318. souleyez/ui/errors.py +49 -49
  319. souleyez/ui/evidence_linking_view.py +284 -179
  320. souleyez/ui/evidence_vault.py +393 -285
  321. souleyez/ui/exploit_suggestions_view.py +555 -349
  322. souleyez/ui/export_view.py +100 -66
  323. souleyez/ui/gap_analysis_view.py +315 -171
  324. souleyez/ui/help_system.py +105 -97
  325. souleyez/ui/intelligence_view.py +436 -293
  326. souleyez/ui/interactive.py +23034 -10679
  327. souleyez/ui/interactive_selector.py +75 -68
  328. souleyez/ui/log_formatter.py +47 -39
  329. souleyez/ui/menu_components.py +22 -13
  330. souleyez/ui/msf_auxiliary_menu.py +184 -133
  331. souleyez/ui/pending_chains_view.py +336 -172
  332. souleyez/ui/progress_indicators.py +5 -3
  333. souleyez/ui/recommendations_view.py +195 -137
  334. souleyez/ui/rule_builder.py +343 -225
  335. souleyez/ui/setup_wizard.py +678 -284
  336. souleyez/ui/shortcuts.py +217 -165
  337. souleyez/ui/splunk_gap_analysis_view.py +452 -270
  338. souleyez/ui/splunk_vulns_view.py +139 -86
  339. souleyez/ui/team_dashboard.py +498 -335
  340. souleyez/ui/template_selector.py +196 -105
  341. souleyez/ui/terminal.py +6 -6
  342. souleyez/ui/timeline_view.py +198 -127
  343. souleyez/ui/tool_setup.py +264 -164
  344. souleyez/ui/tutorial.py +202 -72
  345. souleyez/ui/tutorial_state.py +40 -40
  346. souleyez/ui/wazuh_vulns_view.py +235 -141
  347. souleyez/ui/wordlist_browser.py +260 -107
  348. souleyez/ui.py +464 -312
  349. souleyez/utils/tool_checker.py +427 -367
  350. souleyez/utils.py +33 -29
  351. souleyez/wordlists.py +134 -167
  352. {souleyez-2.43.29.dist-info → souleyez-3.0.0.dist-info}/METADATA +2 -2
  353. souleyez-3.0.0.dist-info/RECORD +443 -0
  354. {souleyez-2.43.29.dist-info → souleyez-3.0.0.dist-info}/WHEEL +1 -1
  355. souleyez-2.43.29.dist-info/RECORD +0 -379
  356. {souleyez-2.43.29.dist-info → souleyez-3.0.0.dist-info}/entry_points.txt +0 -0
  357. {souleyez-2.43.29.dist-info → souleyez-3.0.0.dist-info}/licenses/LICENSE +0 -0
  358. {souleyez-2.43.29.dist-info → souleyez-3.0.0.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,7 @@
1
1
  """
2
2
  Screenshot management for visual evidence collection.
3
3
  """
4
+
4
5
  import os
5
6
  import shutil
6
7
  import time
@@ -31,7 +32,7 @@ class ScreenshotManager:
31
32
  description: str = None,
32
33
  host_id: int = None,
33
34
  finding_id: int = None,
34
- job_id: int = None
35
+ job_id: int = None,
35
36
  ) -> int:
36
37
  """
37
38
  Add a screenshot to the engagement.
@@ -63,18 +64,21 @@ class ScreenshotManager:
63
64
  shutil.copy2(source, dest_path)
64
65
  os.chmod(dest_path, 0o600)
65
66
 
66
- screenshot_id = self.db.insert('screenshots', {
67
- 'engagement_id': engagement_id,
68
- 'host_id': host_id,
69
- 'finding_id': finding_id,
70
- 'job_id': job_id,
71
- 'filename': filename,
72
- 'filepath': str(dest_path),
73
- 'title': title or source.name,
74
- 'description': description,
75
- 'file_size': file_size,
76
- 'mime_type': mime_type
77
- })
67
+ screenshot_id = self.db.insert(
68
+ "screenshots",
69
+ {
70
+ "engagement_id": engagement_id,
71
+ "host_id": host_id,
72
+ "finding_id": finding_id,
73
+ "job_id": job_id,
74
+ "filename": filename,
75
+ "filepath": str(dest_path),
76
+ "title": title or source.name,
77
+ "description": description,
78
+ "file_size": file_size,
79
+ "mime_type": mime_type,
80
+ },
81
+ )
78
82
 
79
83
  return screenshot_id
80
84
 
@@ -83,7 +87,7 @@ class ScreenshotManager:
83
87
  engagement_id: int,
84
88
  host_id: int = None,
85
89
  finding_id: int = None,
86
- job_id: int = None
90
+ job_id: int = None,
87
91
  ) -> List[Dict]:
88
92
  """
89
93
  List screenshots for engagement.
@@ -119,8 +123,7 @@ class ScreenshotManager:
119
123
  def get_screenshot(self, screenshot_id: int) -> Optional[Dict]:
120
124
  """Get screenshot by ID."""
121
125
  return self.db.execute_one(
122
- "SELECT * FROM screenshots WHERE id = ?",
123
- (screenshot_id,)
126
+ "SELECT * FROM screenshots WHERE id = ?", (screenshot_id,)
124
127
  )
125
128
 
126
129
  def delete_screenshot(self, screenshot_id: int) -> bool:
@@ -129,7 +132,7 @@ class ScreenshotManager:
129
132
  if not screenshot:
130
133
  return False
131
134
 
132
- filepath = Path(screenshot['filepath'])
135
+ filepath = Path(screenshot["filepath"])
133
136
  if filepath.exists():
134
137
  filepath.unlink()
135
138
 
@@ -140,23 +143,21 @@ class ScreenshotManager:
140
143
  """Link screenshot to a finding."""
141
144
  self.db.execute(
142
145
  "UPDATE screenshots SET finding_id = ? WHERE id = ?",
143
- (finding_id, screenshot_id)
146
+ (finding_id, screenshot_id),
144
147
  )
145
148
  return True
146
149
 
147
150
  def link_to_job(self, screenshot_id: int, job_id: int) -> bool:
148
151
  """Link screenshot to a job."""
149
152
  self.db.execute(
150
- "UPDATE screenshots SET job_id = ? WHERE id = ?",
151
- (job_id, screenshot_id)
153
+ "UPDATE screenshots SET job_id = ? WHERE id = ?", (job_id, screenshot_id)
152
154
  )
153
155
  return True
154
156
 
155
157
  def link_to_host(self, screenshot_id: int, host_id: int) -> bool:
156
158
  """Link screenshot to a host."""
157
159
  self.db.execute(
158
- "UPDATE screenshots SET host_id = ? WHERE id = ?",
159
- (host_id, screenshot_id)
160
+ "UPDATE screenshots SET host_id = ? WHERE id = ?", (host_id, screenshot_id)
160
161
  )
161
162
  return True
162
163
 
@@ -164,20 +165,20 @@ class ScreenshotManager:
164
165
  """Detect MIME type from file extension."""
165
166
  ext = filepath.suffix.lower()
166
167
  mime_types = {
167
- '.png': 'image/png',
168
- '.jpg': 'image/jpeg',
169
- '.jpeg': 'image/jpeg',
170
- '.gif': 'image/gif',
171
- '.bmp': 'image/bmp',
172
- '.webp': 'image/webp',
173
- '.svg': 'image/svg+xml'
168
+ ".png": "image/png",
169
+ ".jpg": "image/jpeg",
170
+ ".jpeg": "image/jpeg",
171
+ ".gif": "image/gif",
172
+ ".bmp": "image/bmp",
173
+ ".webp": "image/webp",
174
+ ".svg": "image/svg+xml",
174
175
  }
175
- return mime_types.get(ext, 'application/octet-stream')
176
+ return mime_types.get(ext, "application/octet-stream")
176
177
 
177
178
  def get_screenshot_count(self, engagement_id: int) -> int:
178
179
  """Get total screenshot count for engagement."""
179
180
  result = self.db.execute_one(
180
181
  "SELECT COUNT(*) as count FROM screenshots WHERE engagement_id = ?",
181
- (engagement_id,)
182
+ (engagement_id,),
182
183
  )
183
- return result['count'] if result else 0
184
+ return result["count"] if result else 0
@@ -27,42 +27,48 @@ class SMBSharesManager:
27
27
  # Check if share already exists
28
28
  cursor.execute(
29
29
  "SELECT id FROM smb_shares WHERE host_id = ? AND share_name = ?",
30
- (host_id, share_data['name'])
30
+ (host_id, share_data["name"]),
31
31
  )
32
32
  existing = cursor.fetchone()
33
33
 
34
34
  if existing:
35
35
  # Update existing
36
- cursor.execute("""
36
+ cursor.execute(
37
+ """
37
38
  UPDATE smb_shares
38
39
  SET share_type = ?, permissions = ?, comment = ?,
39
40
  readable = ?, writable = ?
40
41
  WHERE id = ?
41
- """, (
42
- share_data.get('type', ''),
43
- share_data.get('permissions', ''),
44
- share_data.get('comment', ''),
45
- 1 if share_data.get('readable') else 0,
46
- 1 if share_data.get('writable') else 0,
47
- existing[0]
48
- ))
42
+ """,
43
+ (
44
+ share_data.get("type", ""),
45
+ share_data.get("permissions", ""),
46
+ share_data.get("comment", ""),
47
+ 1 if share_data.get("readable") else 0,
48
+ 1 if share_data.get("writable") else 0,
49
+ existing[0],
50
+ ),
51
+ )
49
52
  conn.commit()
50
53
  conn.close()
51
54
  return existing[0]
52
55
  else:
53
56
  # Insert new
54
- cursor.execute("""
57
+ cursor.execute(
58
+ """
55
59
  INSERT INTO smb_shares (host_id, share_name, share_type, permissions, comment, readable, writable)
56
60
  VALUES (?, ?, ?, ?, ?, ?, ?)
57
- """, (
58
- host_id,
59
- share_data['name'],
60
- share_data.get('type', ''),
61
- share_data.get('permissions', ''),
62
- share_data.get('comment', ''),
63
- 1 if share_data.get('readable') else 0,
64
- 1 if share_data.get('writable') else 0
65
- ))
61
+ """,
62
+ (
63
+ host_id,
64
+ share_data["name"],
65
+ share_data.get("type", ""),
66
+ share_data.get("permissions", ""),
67
+ share_data.get("comment", ""),
68
+ 1 if share_data.get("readable") else 0,
69
+ 1 if share_data.get("writable") else 0,
70
+ ),
71
+ )
66
72
  row_id = cursor.lastrowid
67
73
  conn.commit()
68
74
  conn.close()
@@ -86,43 +92,51 @@ class SMBSharesManager:
86
92
  # Check if file already exists
87
93
  cursor.execute(
88
94
  "SELECT id FROM smb_files WHERE share_id = ? AND path = ?",
89
- (share_id, file_data['path'])
95
+ (share_id, file_data["path"]),
90
96
  )
91
97
  existing = cursor.fetchone()
92
98
 
93
99
  if existing:
94
100
  # Update existing
95
- cursor.execute("""
101
+ cursor.execute(
102
+ """
96
103
  UPDATE smb_files
97
104
  SET size = ?, timestamp = ?, is_directory = ?
98
105
  WHERE id = ?
99
- """, (
100
- file_data.get('size', 0),
101
- file_data.get('timestamp', ''),
102
- 1 if file_data.get('is_directory') else 0,
103
- existing[0]
104
- ))
106
+ """,
107
+ (
108
+ file_data.get("size", 0),
109
+ file_data.get("timestamp", ""),
110
+ 1 if file_data.get("is_directory") else 0,
111
+ existing[0],
112
+ ),
113
+ )
105
114
  conn.commit()
106
115
  conn.close()
107
116
  return existing[0]
108
117
  else:
109
118
  # Insert new
110
- cursor.execute("""
119
+ cursor.execute(
120
+ """
111
121
  INSERT INTO smb_files (share_id, path, size, timestamp, is_directory)
112
122
  VALUES (?, ?, ?, ?, ?)
113
- """, (
114
- share_id,
115
- file_data['path'],
116
- file_data.get('size', 0),
117
- file_data.get('timestamp', ''),
118
- 1 if file_data.get('is_directory') else 0
119
- ))
123
+ """,
124
+ (
125
+ share_id,
126
+ file_data["path"],
127
+ file_data.get("size", 0),
128
+ file_data.get("timestamp", ""),
129
+ 1 if file_data.get("is_directory") else 0,
130
+ ),
131
+ )
120
132
  row_id = cursor.lastrowid
121
133
  conn.commit()
122
134
  conn.close()
123
135
  return row_id
124
136
 
125
- def list_shares(self, engagement_id: int, host_id: Optional[int] = None) -> List[Dict[str, Any]]:
137
+ def list_shares(
138
+ self, engagement_id: int, host_id: Optional[int] = None
139
+ ) -> List[Dict[str, Any]]:
126
140
  """
127
141
  List all SMB shares for an engagement or specific host.
128
142
 
@@ -138,37 +152,45 @@ class SMBSharesManager:
138
152
  cursor = conn.cursor()
139
153
 
140
154
  if host_id:
141
- cursor.execute("""
155
+ cursor.execute(
156
+ """
142
157
  SELECT s.*, h.ip_address, h.hostname
143
158
  FROM smb_shares s
144
159
  JOIN hosts h ON s.host_id = h.id
145
160
  WHERE h.engagement_id = ? AND s.host_id = ?
146
161
  ORDER BY h.ip_address, s.share_name
147
- """, (engagement_id, host_id))
162
+ """,
163
+ (engagement_id, host_id),
164
+ )
148
165
  else:
149
- cursor.execute("""
166
+ cursor.execute(
167
+ """
150
168
  SELECT s.*, h.ip_address, h.hostname
151
169
  FROM smb_shares s
152
170
  JOIN hosts h ON s.host_id = h.id
153
171
  WHERE h.engagement_id = ?
154
172
  ORDER BY h.ip_address, s.share_name
155
- """, (engagement_id,))
173
+ """,
174
+ (engagement_id,),
175
+ )
156
176
 
157
177
  shares = []
158
178
  for row in cursor.fetchall():
159
- shares.append({
160
- 'id': row[0],
161
- 'host_id': row[1],
162
- 'share_name': row[2],
163
- 'share_type': row[3],
164
- 'permissions': row[4],
165
- 'comment': row[5],
166
- 'readable': bool(row[6]),
167
- 'writable': bool(row[7]),
168
- 'created_at': row[8],
169
- 'ip_address': row[9],
170
- 'hostname': row[10]
171
- })
179
+ shares.append(
180
+ {
181
+ "id": row[0],
182
+ "host_id": row[1],
183
+ "share_name": row[2],
184
+ "share_type": row[3],
185
+ "permissions": row[4],
186
+ "comment": row[5],
187
+ "readable": bool(row[6]),
188
+ "writable": bool(row[7]),
189
+ "created_at": row[8],
190
+ "ip_address": row[9],
191
+ "hostname": row[10],
192
+ }
193
+ )
172
194
 
173
195
  conn.close()
174
196
  return shares
@@ -187,24 +209,29 @@ class SMBSharesManager:
187
209
  conn = db.get_connection()
188
210
  cursor = conn.cursor()
189
211
 
190
- cursor.execute("""
212
+ cursor.execute(
213
+ """
191
214
  SELECT id, share_id, path, size, timestamp, is_directory, created_at
192
215
  FROM smb_files
193
216
  WHERE share_id = ?
194
217
  ORDER BY is_directory DESC, path
195
- """, (share_id,))
218
+ """,
219
+ (share_id,),
220
+ )
196
221
 
197
222
  files = []
198
223
  for row in cursor.fetchall():
199
- files.append({
200
- 'id': row[0],
201
- 'share_id': row[1],
202
- 'path': row[2],
203
- 'size': row[3],
204
- 'timestamp': row[4],
205
- 'is_directory': bool(row[5]),
206
- 'created_at': row[6]
207
- })
224
+ files.append(
225
+ {
226
+ "id": row[0],
227
+ "share_id": row[1],
228
+ "path": row[2],
229
+ "size": row[3],
230
+ "timestamp": row[4],
231
+ "is_directory": bool(row[5]),
232
+ "created_at": row[6],
233
+ }
234
+ )
208
235
 
209
236
  conn.close()
210
237
  return files
@@ -215,29 +242,34 @@ class SMBSharesManager:
215
242
  conn = db.get_connection()
216
243
  cursor = conn.cursor()
217
244
 
218
- cursor.execute("""
245
+ cursor.execute(
246
+ """
219
247
  SELECT s.*, h.ip_address, h.hostname
220
248
  FROM smb_shares s
221
249
  JOIN hosts h ON s.host_id = h.id
222
250
  WHERE h.engagement_id = ? AND s.writable = 1
223
251
  ORDER BY h.ip_address, s.share_name
224
- """, (engagement_id,))
252
+ """,
253
+ (engagement_id,),
254
+ )
225
255
 
226
256
  shares = []
227
257
  for row in cursor.fetchall():
228
- shares.append({
229
- 'id': row[0],
230
- 'host_id': row[1],
231
- 'share_name': row[2],
232
- 'share_type': row[3],
233
- 'permissions': row[4],
234
- 'comment': row[5],
235
- 'readable': bool(row[6]),
236
- 'writable': bool(row[7]),
237
- 'created_at': row[8],
238
- 'ip_address': row[9],
239
- 'hostname': row[10]
240
- })
258
+ shares.append(
259
+ {
260
+ "id": row[0],
261
+ "host_id": row[1],
262
+ "share_name": row[2],
263
+ "share_type": row[3],
264
+ "permissions": row[4],
265
+ "comment": row[5],
266
+ "readable": bool(row[6]),
267
+ "writable": bool(row[7]),
268
+ "created_at": row[8],
269
+ "ip_address": row[9],
270
+ "hostname": row[10],
271
+ }
272
+ )
241
273
 
242
274
  conn.close()
243
275
  return shares
@@ -249,45 +281,57 @@ class SMBSharesManager:
249
281
  cursor = conn.cursor()
250
282
 
251
283
  # Count total shares
252
- cursor.execute("""
284
+ cursor.execute(
285
+ """
253
286
  SELECT COUNT(*)
254
287
  FROM smb_shares s
255
288
  JOIN hosts h ON s.host_id = h.id
256
289
  WHERE h.engagement_id = ?
257
- """, (engagement_id,))
290
+ """,
291
+ (engagement_id,),
292
+ )
258
293
  total = cursor.fetchone()[0]
259
294
 
260
295
  # Count writable shares
261
- cursor.execute("""
296
+ cursor.execute(
297
+ """
262
298
  SELECT COUNT(*)
263
299
  FROM smb_shares s
264
300
  JOIN hosts h ON s.host_id = h.id
265
301
  WHERE h.engagement_id = ? AND s.writable = 1
266
- """, (engagement_id,))
302
+ """,
303
+ (engagement_id,),
304
+ )
267
305
  writable = cursor.fetchone()[0]
268
306
 
269
307
  # Count readable shares
270
- cursor.execute("""
308
+ cursor.execute(
309
+ """
271
310
  SELECT COUNT(*)
272
311
  FROM smb_shares s
273
312
  JOIN hosts h ON s.host_id = h.id
274
313
  WHERE h.engagement_id = ? AND s.readable = 1
275
- """, (engagement_id,))
314
+ """,
315
+ (engagement_id,),
316
+ )
276
317
  readable = cursor.fetchone()[0]
277
318
 
278
319
  # Count hosts with SMB
279
- cursor.execute("""
320
+ cursor.execute(
321
+ """
280
322
  SELECT COUNT(DISTINCT s.host_id)
281
323
  FROM smb_shares s
282
324
  JOIN hosts h ON s.host_id = h.id
283
325
  WHERE h.engagement_id = ?
284
- """, (engagement_id,))
326
+ """,
327
+ (engagement_id,),
328
+ )
285
329
  hosts_with_smb = cursor.fetchone()[0]
286
330
 
287
331
  conn.close()
288
332
  return {
289
- 'total_shares': total,
290
- 'writable': writable,
291
- 'readable': readable,
292
- 'hosts_with_smb': hosts_with_smb
333
+ "total_shares": total,
334
+ "writable": writable,
335
+ "readable": readable,
336
+ "hosts_with_smb": hosts_with_smb,
293
337
  }