souleyez 2.43.29__py3-none-any.whl → 2.43.34__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 +9526 -2879
  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 +563 -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 +408 -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 +371 -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 +854 -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 +173 -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 +223 -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 +22827 -10678
  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-2.43.34.dist-info}/METADATA +1 -1
  353. souleyez-2.43.34.dist-info/RECORD +443 -0
  354. {souleyez-2.43.29.dist-info → souleyez-2.43.34.dist-info}/WHEEL +1 -1
  355. souleyez-2.43.29.dist-info/RECORD +0 -379
  356. {souleyez-2.43.29.dist-info → souleyez-2.43.34.dist-info}/entry_points.txt +0 -0
  357. {souleyez-2.43.29.dist-info → souleyez-2.43.34.dist-info}/licenses/LICENSE +0 -0
  358. {souleyez-2.43.29.dist-info → souleyez-2.43.34.dist-info}/top_level.txt +0 -0
@@ -14,7 +14,7 @@ logger = logging.getLogger(__name__)
14
14
  class FeedbackHandler:
15
15
  """
16
16
  Automatically update database based on command execution results.
17
-
17
+
18
18
  Implements the feedback loop:
19
19
  - Update credential status (valid/invalid)
20
20
  - Update host status (compromised/active)
@@ -32,63 +32,74 @@ class FeedbackHandler:
32
32
  engagement_id: int,
33
33
  parsed_result: Dict[str, Any],
34
34
  recommendation: Dict[str, Any],
35
- command: str
35
+ command: str,
36
36
  ) -> Dict[str, Any]:
37
37
  """
38
38
  Apply feedback updates to database.
39
-
39
+
40
40
  Args:
41
41
  engagement_id: Current engagement ID
42
42
  parsed_result: Parsed command result
43
43
  recommendation: Original AI recommendation
44
44
  command: Command that was executed
45
-
45
+
46
46
  Returns:
47
47
  Dict describing what was updated
48
48
  """
49
49
  feedback = {
50
- 'hosts_updated': 0,
51
- 'credentials_updated': 0,
52
- 'services_added': 0,
53
- 'notes_added': []
50
+ "hosts_updated": 0,
51
+ "credentials_updated": 0,
52
+ "services_added": 0,
53
+ "notes_added": [],
54
54
  }
55
-
55
+
56
56
  # Extract target IP
57
- target = recommendation.get('target', '')
58
- action = recommendation.get('action', '').lower()
59
-
57
+ target = recommendation.get("target", "")
58
+ action = recommendation.get("action", "").lower()
59
+
60
60
  import re
61
- ip_match = re.search(r'\b(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\b', target)
61
+
62
+ ip_match = re.search(r"\b(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\b", target)
62
63
  if not ip_match:
63
64
  logger.warning(f"Could not extract IP from target: {target}")
64
65
  return feedback
65
-
66
+
66
67
  ip = ip_match.group(1)
67
-
68
+
68
69
  # Get host from database
69
70
  host = self.host_mgr.get_host_by_ip(engagement_id, ip)
70
71
  if not host:
71
72
  logger.warning(f"Host {ip} not found in engagement {engagement_id}")
72
73
  return feedback
73
-
74
+
74
75
  # Handle SSH results
75
- if 'ssh' in command.lower() and parsed_result.get('credential_valid') is not None:
76
- feedback.update(self._handle_ssh_feedback(
77
- engagement_id, host, parsed_result, recommendation
78
- ))
79
-
76
+ if (
77
+ "ssh" in command.lower()
78
+ and parsed_result.get("credential_valid") is not None
79
+ ):
80
+ feedback.update(
81
+ self._handle_ssh_feedback(
82
+ engagement_id, host, parsed_result, recommendation
83
+ )
84
+ )
85
+
80
86
  # Handle MySQL results
81
- elif 'mysql' in command.lower() and parsed_result.get('credential_valid') is not None:
82
- feedback.update(self._handle_mysql_feedback(
83
- engagement_id, host, parsed_result, recommendation
84
- ))
85
-
87
+ elif (
88
+ "mysql" in command.lower()
89
+ and parsed_result.get("credential_valid") is not None
90
+ ):
91
+ feedback.update(
92
+ self._handle_mysql_feedback(
93
+ engagement_id, host, parsed_result, recommendation
94
+ )
95
+ )
96
+
86
97
  # Handle nmap results
87
- elif 'nmap' in command.lower() and parsed_result.get('open_ports'):
88
- feedback.update(self._handle_nmap_feedback(
89
- engagement_id, host, parsed_result
90
- ))
91
-
98
+ elif "nmap" in command.lower() and parsed_result.get("open_ports"):
99
+ feedback.update(
100
+ self._handle_nmap_feedback(engagement_id, host, parsed_result)
101
+ )
102
+
92
103
  return feedback
93
104
 
94
105
  def _handle_ssh_feedback(
@@ -96,61 +107,63 @@ class FeedbackHandler:
96
107
  engagement_id: int,
97
108
  host: Dict[str, Any],
98
109
  result: Dict[str, Any],
99
- recommendation: Dict[str, Any]
110
+ recommendation: Dict[str, Any],
100
111
  ) -> Dict[str, Any]:
101
112
  """Handle feedback for SSH credential testing."""
102
- feedback = {'hosts_updated': 0, 'credentials_updated': 0, 'notes_added': []}
103
-
113
+ feedback = {"hosts_updated": 0, "credentials_updated": 0, "notes_added": []}
114
+
104
115
  # Extract credentials from recommendation
105
116
  import re
106
- text = f"{recommendation.get('action', '')} {recommendation.get('rationale', '')}"
107
- cred_match = re.search(r'(\w+):(\w+)', text)
108
-
117
+
118
+ text = (
119
+ f"{recommendation.get('action', '')} {recommendation.get('rationale', '')}"
120
+ )
121
+ cred_match = re.search(r"(\w+):(\w+)", text)
122
+
109
123
  if not cred_match:
110
124
  logger.warning("Could not extract credentials from recommendation")
111
125
  return feedback
112
-
126
+
113
127
  username = cred_match.group(1)
114
128
  password = cred_match.group(2)
115
-
129
+
116
130
  # Find credential in database
117
131
  creds = self.creds_mgr.list_credentials(engagement_id)
118
132
  cred_id = None
119
133
  for cred in creds:
120
- if cred.get('username') == username and cred.get('password') == password:
121
- cred_id = cred.get('id')
134
+ if cred.get("username") == username and cred.get("password") == password:
135
+ cred_id = cred.get("id")
122
136
  break
123
-
137
+
124
138
  # Update credential status
125
139
  if cred_id:
126
- status = 'valid' if result.get('credential_valid') else 'invalid'
127
- notes = result.get('details', '')
128
-
129
- self.creds_mgr.update_credential_status(
130
- cred_id,
131
- status=status,
132
- notes=notes
140
+ status = "valid" if result.get("credential_valid") else "invalid"
141
+ notes = result.get("details", "")
142
+
143
+ self.creds_mgr.update_credential_status(cred_id, status=status, notes=notes)
144
+ feedback["credentials_updated"] = 1
145
+ feedback["notes_added"].append(
146
+ f"Updated credential {username} status: {status}"
133
147
  )
134
- feedback['credentials_updated'] = 1
135
- feedback['notes_added'].append(f"Updated credential {username} status: {status}")
136
148
  logger.info(f"Updated credential {cred_id} status to {status}")
137
-
149
+
138
150
  # Update host status if credentials were valid
139
- if result.get('credential_valid'):
140
- access_level = result.get('access_level', 'user')
141
- status = 'compromised'
151
+ if result.get("credential_valid"):
152
+ access_level = result.get("access_level", "user")
153
+ status = "compromised"
142
154
  notes = f"Gained {access_level} access via SSH with {username}:{password}"
143
-
155
+
144
156
  self.host_mgr.update_host_status(
145
- host['id'],
146
- status=status,
147
- access_level=access_level,
148
- notes=notes
157
+ host["id"], status=status, access_level=access_level, notes=notes
158
+ )
159
+ feedback["hosts_updated"] = 1
160
+ feedback["notes_added"].append(
161
+ f"Updated host {host['ip_address']}: {status}, access={access_level}"
149
162
  )
150
- feedback['hosts_updated'] = 1
151
- feedback['notes_added'].append(f"Updated host {host['ip_address']}: {status}, access={access_level}")
152
- logger.info(f"Updated host {host['id']} to {status} with {access_level} access")
153
-
163
+ logger.info(
164
+ f"Updated host {host['id']} to {status} with {access_level} access"
165
+ )
166
+
154
167
  return feedback
155
168
 
156
169
  def _handle_mysql_feedback(
@@ -158,106 +171,108 @@ class FeedbackHandler:
158
171
  engagement_id: int,
159
172
  host: Dict[str, Any],
160
173
  result: Dict[str, Any],
161
- recommendation: Dict[str, Any]
174
+ recommendation: Dict[str, Any],
162
175
  ) -> Dict[str, Any]:
163
176
  """Handle feedback for MySQL credential testing."""
164
- feedback = {'hosts_updated': 0, 'credentials_updated': 0, 'notes_added': []}
165
-
177
+ feedback = {"hosts_updated": 0, "credentials_updated": 0, "notes_added": []}
178
+
166
179
  # Extract credentials
167
180
  import re
168
- text = f"{recommendation.get('action', '')} {recommendation.get('rationale', '')}"
169
- cred_match = re.search(r'(\w+):(\w+)', text)
170
-
181
+
182
+ text = (
183
+ f"{recommendation.get('action', '')} {recommendation.get('rationale', '')}"
184
+ )
185
+ cred_match = re.search(r"(\w+):(\w+)", text)
186
+
171
187
  if not cred_match:
172
188
  return feedback
173
-
189
+
174
190
  username = cred_match.group(1)
175
191
  password = cred_match.group(2)
176
-
192
+
177
193
  # Find/update credential
178
194
  creds = self.creds_mgr.list_credentials(engagement_id)
179
195
  cred_id = None
180
196
  for cred in creds:
181
- if (cred.get('username') == username and
182
- cred.get('password') == password and
183
- cred.get('service') == 'mysql'):
184
- cred_id = cred.get('id')
197
+ if (
198
+ cred.get("username") == username
199
+ and cred.get("password") == password
200
+ and cred.get("service") == "mysql"
201
+ ):
202
+ cred_id = cred.get("id")
185
203
  break
186
-
204
+
187
205
  if cred_id:
188
- status = 'valid' if result.get('credential_valid') else 'invalid'
189
- notes = result.get('details', '')
190
-
191
- self.creds_mgr.update_credential_status(
192
- cred_id,
193
- status=status,
194
- notes=notes
206
+ status = "valid" if result.get("credential_valid") else "invalid"
207
+ notes = result.get("details", "")
208
+
209
+ self.creds_mgr.update_credential_status(cred_id, status=status, notes=notes)
210
+ feedback["credentials_updated"] = 1
211
+ feedback["notes_added"].append(
212
+ f"Updated MySQL credential {username} status: {status}"
195
213
  )
196
- feedback['credentials_updated'] = 1
197
- feedback['notes_added'].append(f"Updated MySQL credential {username} status: {status}")
198
-
214
+
199
215
  # Update host notes if connection was successful
200
- if result.get('credential_valid'):
216
+ if result.get("credential_valid"):
201
217
  notes = f"MySQL access confirmed with {username}:{password}"
202
- if result.get('databases'):
218
+ if result.get("databases"):
203
219
  notes += f" - Databases: {', '.join(result['databases'][:5])}"
204
-
220
+
205
221
  # Only update if not already compromised with higher access
206
- current_access = host.get('access_level', 'none')
207
- if current_access == 'none':
208
- self.host_mgr.update_host_status(
209
- host['id'],
210
- notes=notes
222
+ current_access = host.get("access_level", "none")
223
+ if current_access == "none":
224
+ self.host_mgr.update_host_status(host["id"], notes=notes)
225
+ feedback["hosts_updated"] = 1
226
+ feedback["notes_added"].append(
227
+ f"Added MySQL access notes to host {host['ip_address']}"
211
228
  )
212
- feedback['hosts_updated'] = 1
213
- feedback['notes_added'].append(f"Added MySQL access notes to host {host['ip_address']}")
214
-
229
+
215
230
  return feedback
216
231
 
217
232
  def _handle_nmap_feedback(
218
- self,
219
- engagement_id: int,
220
- host: Dict[str, Any],
221
- result: Dict[str, Any]
233
+ self, engagement_id: int, host: Dict[str, Any], result: Dict[str, Any]
222
234
  ) -> Dict[str, Any]:
223
235
  """Handle feedback for nmap scans."""
224
- feedback = {'hosts_updated': 0, 'services_added': 0, 'notes_added': []}
225
-
236
+ feedback = {"hosts_updated": 0, "services_added": 0, "notes_added": []}
237
+
226
238
  # Add discovered services
227
- open_ports = result.get('open_ports', [])
228
- services_info = result.get('services', {})
229
-
239
+ open_ports = result.get("open_ports", [])
240
+ services_info = result.get("services", {})
241
+
230
242
  for port in open_ports:
231
- service_info = services_info.get(str(port), 'unknown')
232
-
243
+ service_info = services_info.get(str(port), "unknown")
244
+
233
245
  # Try to parse service name and version
234
246
  import re
235
- service_match = re.match(r'(\S+)(?:\s+(.+))?', service_info)
247
+
248
+ service_match = re.match(r"(\S+)(?:\s+(.+))?", service_info)
236
249
  if service_match:
237
250
  service_name = service_match.group(1)
238
- service_version = service_match.group(2) if service_match.group(2) else None
251
+ service_version = (
252
+ service_match.group(2) if service_match.group(2) else None
253
+ )
239
254
  else:
240
- service_name = 'unknown'
255
+ service_name = "unknown"
241
256
  service_version = None
242
-
257
+
243
258
  # Add service to database
244
259
  try:
245
260
  self.host_mgr.add_service(
246
- host['id'],
261
+ host["id"],
247
262
  port=port,
248
- protocol='tcp',
263
+ protocol="tcp",
249
264
  service_name=service_name,
250
265
  service_version=service_version,
251
- state='open'
266
+ state="open",
252
267
  )
253
- feedback['services_added'] += 1
268
+ feedback["services_added"] += 1
254
269
  logger.info(f"Added service {service_name} on port {port}")
255
270
  except Exception as e:
256
271
  logger.warning(f"Failed to add service {port}: {e}")
257
-
258
- if feedback['services_added'] > 0:
259
- feedback['notes_added'].append(
272
+
273
+ if feedback["services_added"] > 0:
274
+ feedback["notes_added"].append(
260
275
  f"Added {feedback['services_added']} services to host {host['ip_address']}"
261
276
  )
262
-
277
+
263
278
  return feedback
@@ -4,6 +4,7 @@ souleyez.ai.llm_factory - Factory for creating LLM providers
4
4
  This module provides a factory pattern for creating LLM providers
5
5
  based on user configuration.
6
6
  """
7
+
7
8
  import logging
8
9
  from typing import Optional
9
10
 
@@ -35,20 +36,24 @@ class LLMFactory:
35
36
 
36
37
  if provider_type is None:
37
38
  # Read from config
38
- provider_str = get('ai.provider', 'ollama')
39
+ provider_str = get("ai.provider", "ollama")
39
40
  try:
40
41
  provider_type = LLMProviderType(provider_str)
41
42
  except ValueError:
42
- logger.warning(f"Unknown provider '{provider_str}', defaulting to ollama")
43
+ logger.warning(
44
+ f"Unknown provider '{provider_str}', defaulting to ollama"
45
+ )
43
46
  provider_type = LLMProviderType.OLLAMA
44
47
 
45
48
  if provider_type == LLMProviderType.CLAUDE:
46
49
  from .claude_provider import ClaudeProvider
47
- model = get('ai.claude_model')
50
+
51
+ model = get("ai.claude_model")
48
52
  return ClaudeProvider(model=model)
49
53
  else:
50
54
  from .ollama_provider import OllamaProvider
51
- model = get('ai.ollama_model') or get('settings.ollama_model')
55
+
56
+ model = get("ai.ollama_model") or get("settings.ollama_model")
52
57
  return OllamaProvider(model=model)
53
58
 
54
59
  @staticmethod
@@ -103,33 +108,35 @@ class LLMFactory:
103
108
  # Check Ollama
104
109
  try:
105
110
  from .ollama_provider import OllamaProvider
111
+
106
112
  ollama = OllamaProvider()
107
- results['ollama'] = {
108
- 'available': ollama.is_available(),
109
- 'status': ollama.get_status(),
110
- 'configured': get('ai.provider', 'ollama') == 'ollama'
113
+ results["ollama"] = {
114
+ "available": ollama.is_available(),
115
+ "status": ollama.get_status(),
116
+ "configured": get("ai.provider", "ollama") == "ollama",
111
117
  }
112
118
  except Exception as e:
113
- results['ollama'] = {
114
- 'available': False,
115
- 'error': str(e),
116
- 'configured': get('ai.provider', 'ollama') == 'ollama'
119
+ results["ollama"] = {
120
+ "available": False,
121
+ "error": str(e),
122
+ "configured": get("ai.provider", "ollama") == "ollama",
117
123
  }
118
124
 
119
125
  # Check Claude
120
126
  try:
121
127
  from .claude_provider import ClaudeProvider
128
+
122
129
  claude = ClaudeProvider()
123
- results['claude'] = {
124
- 'available': claude.is_available(),
125
- 'status': claude.get_status(),
126
- 'configured': get('ai.provider', 'ollama') == 'claude'
130
+ results["claude"] = {
131
+ "available": claude.is_available(),
132
+ "status": claude.get_status(),
133
+ "configured": get("ai.provider", "ollama") == "claude",
127
134
  }
128
135
  except Exception as e:
129
- results['claude'] = {
130
- 'available': False,
131
- 'error': str(e),
132
- 'configured': get('ai.provider', 'ollama') == 'claude'
136
+ results["claude"] = {
137
+ "available": False,
138
+ "error": str(e),
139
+ "configured": get("ai.provider", "ollama") == "claude",
133
140
  }
134
141
 
135
142
  return results
@@ -4,6 +4,7 @@ souleyez.ai.llm_provider - Abstract LLM provider interface
4
4
  This module defines the abstract base class for LLM providers,
5
5
  enabling support for multiple backends (Ollama, Claude, etc.)
6
6
  """
7
+
7
8
  from abc import ABC, abstractmethod
8
9
  from enum import Enum
9
10
  from typing import Optional, Dict, Any
@@ -14,6 +15,7 @@ logger = logging.getLogger(__name__)
14
15
 
15
16
  class LLMProviderType(Enum):
16
17
  """Supported LLM provider types."""
18
+
17
19
  OLLAMA = "ollama"
18
20
  CLAUDE = "claude"
19
21
 
@@ -54,7 +56,7 @@ class LLMProvider(ABC):
54
56
  prompt: str,
55
57
  system_prompt: Optional[str] = None,
56
58
  max_tokens: int = 4096,
57
- temperature: float = 0.3
59
+ temperature: float = 0.3,
58
60
  ) -> Optional[str]:
59
61
  """
60
62
  Generate text from a prompt.
@@ -86,7 +88,7 @@ class LLMProvider(ABC):
86
88
  system_prompt: Optional[str] = None,
87
89
  max_tokens: int = 4096,
88
90
  temperature: float = 0.3,
89
- fallback: Optional[str] = None
91
+ fallback: Optional[str] = None,
90
92
  ) -> str:
91
93
  """
92
94
  Generate text with a fallback value if generation fails.
@@ -3,6 +3,7 @@ souleyez.ai.ollama_provider - Ollama LLM provider implementation
3
3
 
4
4
  Wraps the existing OllamaService to implement the LLMProvider interface.
5
5
  """
6
+
6
7
  import logging
7
8
  from typing import Optional, Dict, Any
8
9
 
@@ -20,11 +21,7 @@ class OllamaProvider(LLMProvider):
20
21
  No API key required, but Ollama must be installed and running.
21
22
  """
22
23
 
23
- def __init__(
24
- self,
25
- model: Optional[str] = None,
26
- endpoint: Optional[str] = None
27
- ):
24
+ def __init__(self, model: Optional[str] = None, endpoint: Optional[str] = None):
28
25
  """
29
26
  Initialize Ollama provider.
30
27
 
@@ -71,7 +68,7 @@ class OllamaProvider(LLMProvider):
71
68
  prompt: str,
72
69
  system_prompt: Optional[str] = None,
73
70
  max_tokens: int = 4096,
74
- temperature: float = 0.3
71
+ temperature: float = 0.3,
75
72
  ) -> Optional[str]:
76
73
  """
77
74
  Generate text using Ollama.
@@ -108,7 +105,7 @@ class OllamaProvider(LLMProvider):
108
105
  dict: Status including connection, models, availability
109
106
  """
110
107
  status = self._service.get_status()
111
- status['provider_type'] = self.provider_type.value
112
- status['provider'] = 'Ollama'
113
- status['provider_name'] = 'Ollama (Local)'
108
+ status["provider_type"] = self.provider_type.value
109
+ status["provider"] = "Ollama"
110
+ status["provider_name"] = "Ollama (Local)"
114
111
  return status