souleyez 2.43.26__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 +23434 -10286
  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.26.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.26.dist-info → souleyez-2.43.34.dist-info}/WHEEL +1 -1
  355. souleyez-2.43.26.dist-info/RECORD +0 -379
  356. {souleyez-2.43.26.dist-info → souleyez-2.43.34.dist-info}/entry_points.txt +0 -0
  357. {souleyez-2.43.26.dist-info → souleyez-2.43.34.dist-info}/licenses/LICENSE +0 -0
  358. {souleyez-2.43.26.dist-info → souleyez-2.43.34.dist-info}/top_level.txt +0 -0
@@ -7,17 +7,17 @@ from typing import Optional, Dict, List, Any
7
7
  from souleyez.ui.design_system import DesignSystem
8
8
 
9
9
 
10
- def show_rule_builder(mode: str = 'simple') -> Optional[Dict[str, Any]]:
10
+ def show_rule_builder(mode: str = "simple") -> Optional[Dict[str, Any]]:
11
11
  """
12
12
  Show chain rule builder interface.
13
-
13
+
14
14
  Args:
15
15
  mode: 'simple' or 'advanced'
16
-
16
+
17
17
  Returns:
18
18
  Dict with rule definition or None if cancelled
19
19
  """
20
- if mode == 'simple':
20
+ if mode == "simple":
21
21
  return _simple_mode_builder()
22
22
  else:
23
23
  return _advanced_mode_builder()
@@ -27,59 +27,65 @@ def _simple_mode_builder() -> Optional[Dict[str, Any]]:
27
27
  """Guided step-by-step rule builder (simple mode)."""
28
28
  DesignSystem.clear_screen()
29
29
  width = 60
30
-
30
+
31
31
  click.echo("\n┌" + "─" * (width - 2) + "┐")
32
- click.echo("│" + click.style(" CREATE CHAIN RULE ".center(width - 2), bold=True, fg='cyan') + "│")
32
+ click.echo(
33
+ "│"
34
+ + click.style(" CREATE CHAIN RULE ".center(width - 2), bold=True, fg="cyan")
35
+ + "│"
36
+ )
33
37
  click.echo("└" + "─" * (width - 2) + "┘")
34
38
  click.echo()
35
- click.echo(" " + click.style("Simple Mode", fg='yellow') + " - Guided step-by-step")
39
+ click.echo(
40
+ " " + click.style("Simple Mode", fg="yellow") + " - Guided step-by-step"
41
+ )
36
42
  click.echo(" Press 'q' at any step to cancel")
37
43
  click.echo()
38
-
44
+
39
45
  try:
40
46
  # Step 1: Select trigger tool
41
47
  trigger_tool = _select_trigger_tool()
42
48
  if not trigger_tool:
43
49
  return None
44
-
50
+
45
51
  # Step 2: Select condition
46
52
  condition = _select_condition_simple(trigger_tool)
47
53
  if not condition:
48
54
  return None
49
-
55
+
50
56
  # Step 3: Select target tool
51
57
  target_tool = _select_target_tool()
52
58
  if not target_tool:
53
59
  return None
54
-
60
+
55
61
  # Step 4: Select args template
56
62
  args_template = _select_args_template(target_tool)
57
-
63
+
58
64
  # Step 5: Rule settings
59
65
  rule_settings = _configure_rule_settings()
60
66
  if not rule_settings:
61
67
  return None
62
-
68
+
63
69
  # Build rule
64
70
  rule = {
65
- 'trigger_tool': trigger_tool,
66
- 'condition': condition,
67
- 'target_tool': target_tool,
68
- 'args': args_template,
69
- 'priority': rule_settings['priority'],
70
- 'category': rule_settings['category'],
71
- 'enabled': rule_settings['enabled'],
72
- 'description': rule_settings.get('description', '')
71
+ "trigger_tool": trigger_tool,
72
+ "condition": condition,
73
+ "target_tool": target_tool,
74
+ "args": args_template,
75
+ "priority": rule_settings["priority"],
76
+ "category": rule_settings["category"],
77
+ "enabled": rule_settings["enabled"],
78
+ "description": rule_settings.get("description", ""),
73
79
  }
74
-
80
+
75
81
  # Show summary and confirm
76
82
  if _confirm_rule(rule):
77
83
  return rule
78
-
84
+
79
85
  return None
80
-
86
+
81
87
  except (KeyboardInterrupt, click.Abort):
82
- click.echo(click.style("\n Rule creation cancelled", fg='yellow'))
88
+ click.echo(click.style("\n Rule creation cancelled", fg="yellow"))
83
89
  return None
84
90
 
85
91
 
@@ -87,64 +93,72 @@ def _select_trigger_tool() -> Optional[str]:
87
93
  """Step 1: Select trigger tool."""
88
94
  DesignSystem.clear_screen()
89
95
  width = 60
90
-
96
+
91
97
  click.echo("\n┌" + "─" * (width - 2) + "┐")
92
- click.echo("│" + click.style(" STEP 1: TRIGGER TOOL ".center(width - 2), bold=True, fg='cyan') + "│")
98
+ click.echo(
99
+ "│"
100
+ + click.style(" STEP 1: TRIGGER TOOL ".center(width - 2), bold=True, fg="cyan")
101
+ + "│"
102
+ )
93
103
  click.echo("└" + "─" * (width - 2) + "┘")
94
104
  click.echo()
95
105
  click.echo(" When this tool completes...")
96
106
  click.echo()
97
-
107
+
98
108
  # Get all available tools from plugins
99
109
  tools = [
100
- ('nmap', 'Network scanner'),
101
- ('theHarvester', 'OSINT gathering'),
102
- ('whois', 'Domain information'),
103
- ('dnsrecon', 'DNS reconnaissance'),
104
- ('gobuster', 'Directory brute-force'),
105
- ('ffuf', 'Web fuzzing'),
106
- ('nuclei', 'Vulnerability scanner'),
107
- ('wpscan', 'WordPress scanner'),
108
- ('sqlmap', 'SQL injection tool'),
109
- ('hydra', 'Credential brute-force'),
110
- ('crackmapexec', 'Windows/AD testing'),
111
- ('smbmap', 'SMB enumeration'),
112
- ('enum4linux', 'SMB/Samba enum'),
113
- ('bloodhound', 'AD attack paths'),
114
- ('responder', 'LLMNR poisoning'),
115
- ('searchsploit', 'Exploit search'),
116
- ('hashcat', 'Hash cracking'),
117
- ('john', 'Password cracking'),
118
- ('custom', 'Enter custom tool name')
110
+ ("nmap", "Network scanner"),
111
+ ("theHarvester", "OSINT gathering"),
112
+ ("whois", "Domain information"),
113
+ ("dnsrecon", "DNS reconnaissance"),
114
+ ("gobuster", "Directory brute-force"),
115
+ ("ffuf", "Web fuzzing"),
116
+ ("nuclei", "Vulnerability scanner"),
117
+ ("wpscan", "WordPress scanner"),
118
+ ("sqlmap", "SQL injection tool"),
119
+ ("hydra", "Credential brute-force"),
120
+ ("crackmapexec", "Windows/AD testing"),
121
+ ("smbmap", "SMB enumeration"),
122
+ ("enum4linux", "SMB/Samba enum"),
123
+ ("bloodhound", "AD attack paths"),
124
+ ("responder", "LLMNR poisoning"),
125
+ ("searchsploit", "Exploit search"),
126
+ ("hashcat", "Hash cracking"),
127
+ ("john", "Password cracking"),
128
+ ("custom", "Enter custom tool name"),
119
129
  ]
120
-
130
+
121
131
  for idx, (tool, desc) in enumerate(tools, 1):
122
132
  click.echo(f" [{idx}] {tool:<15} - {desc}")
123
-
133
+
124
134
  click.echo()
125
135
  click.echo(" [q] Cancel")
126
136
  click.echo()
127
-
137
+
128
138
  try:
129
- choice = click.prompt(" Select option", type=str, show_default=False).strip().lower()
130
-
131
- if choice == 'q':
139
+ choice = (
140
+ click.prompt(" Select option", type=str, show_default=False)
141
+ .strip()
142
+ .lower()
143
+ )
144
+
145
+ if choice == "q":
132
146
  return None
133
-
147
+
134
148
  try:
135
149
  idx = int(choice)
136
150
  if 1 <= idx <= len(tools):
137
151
  tool_name = tools[idx - 1][0]
138
- if tool_name == 'custom':
152
+ if tool_name == "custom":
139
153
  tool_name = click.prompt(" Enter tool name", type=str)
140
154
  return tool_name
141
155
  except ValueError:
142
156
  pass
143
-
144
- click.echo(click.style(" Invalid selection", fg='red'))
157
+
158
+ click.echo(click.style(" Invalid selection", fg="red"))
145
159
  click.pause()
146
160
  return None
147
-
161
+
148
162
  except (KeyboardInterrupt, click.Abort):
149
163
  return None
150
164
 
@@ -153,97 +167,107 @@ def _select_condition_simple(trigger_tool: str) -> Optional[str]:
153
167
  """Step 2: Select condition (simple mode)."""
154
168
  DesignSystem.clear_screen()
155
169
  width = 60
156
-
170
+
157
171
  click.echo("\n┌" + "─" * (width - 2) + "┐")
158
- click.echo("│" + click.style(" STEP 2: CONDITION ".center(width - 2), bold=True, fg='cyan') + "│")
172
+ click.echo(
173
+ "│"
174
+ + click.style(" STEP 2: CONDITION ".center(width - 2), bold=True, fg="cyan")
175
+ + "│"
176
+ )
159
177
  click.echo("└" + "─" * (width - 2) + "┘")
160
178
  click.echo()
161
179
  click.echo(f" When {click.style(trigger_tool, fg='yellow')} finds...")
162
180
  click.echo()
163
-
181
+
164
182
  # Context-aware conditions based on trigger tool
165
- if trigger_tool in ['nmap']:
183
+ if trigger_tool in ["nmap"]:
166
184
  conditions = [
167
- ('service:http', 'HTTP service discovered (port 80/443/8080)'),
168
- ('service:https', 'HTTPS service discovered'),
169
- ('service:smb', 'SMB service discovered (port 445)'),
170
- ('service:ssh', 'SSH service discovered (port 22)'),
171
- ('service:ftp', 'FTP service discovered (port 21)'),
172
- ('service:mysql', 'MySQL service discovered (port 3306)'),
173
- ('service:mssql', 'MSSQL service discovered (port 1433)'),
174
- ('service:rdp', 'RDP service discovered (port 3389)'),
175
- ('port:*', 'Any open port discovered'),
176
- ('custom', 'Enter custom condition')
185
+ ("service:http", "HTTP service discovered (port 80/443/8080)"),
186
+ ("service:https", "HTTPS service discovered"),
187
+ ("service:smb", "SMB service discovered (port 445)"),
188
+ ("service:ssh", "SSH service discovered (port 22)"),
189
+ ("service:ftp", "FTP service discovered (port 21)"),
190
+ ("service:mysql", "MySQL service discovered (port 3306)"),
191
+ ("service:mssql", "MSSQL service discovered (port 1433)"),
192
+ ("service:rdp", "RDP service discovered (port 3389)"),
193
+ ("port:*", "Any open port discovered"),
194
+ ("custom", "Enter custom condition"),
177
195
  ]
178
- elif trigger_tool in ['theHarvester', 'whois', 'dnsrecon']:
196
+ elif trigger_tool in ["theHarvester", "whois", "dnsrecon"]:
179
197
  conditions = [
180
- ('has:domains', 'Domain/subdomain discovered'),
181
- ('has:emails', 'Email addresses found'),
182
- ('has:hosts', 'Host records found'),
183
- ('has:ips', 'IP addresses found'),
184
- ('custom', 'Enter custom condition')
198
+ ("has:domains", "Domain/subdomain discovered"),
199
+ ("has:emails", "Email addresses found"),
200
+ ("has:hosts", "Host records found"),
201
+ ("has:ips", "IP addresses found"),
202
+ ("custom", "Enter custom condition"),
185
203
  ]
186
- elif trigger_tool in ['gobuster', 'ffuf', 'nuclei']:
204
+ elif trigger_tool in ["gobuster", "ffuf", "nuclei"]:
187
205
  conditions = [
188
- ('has:urls', 'URLs/paths discovered'),
189
- ('finding:vulnerability', 'Vulnerability found'),
190
- ('finding:cve', 'CVE detected'),
191
- ('custom', 'Enter custom condition')
206
+ ("has:urls", "URLs/paths discovered"),
207
+ ("finding:vulnerability", "Vulnerability found"),
208
+ ("finding:cve", "CVE detected"),
209
+ ("custom", "Enter custom condition"),
192
210
  ]
193
- elif trigger_tool in ['sqlmap']:
211
+ elif trigger_tool in ["sqlmap"]:
194
212
  conditions = [
195
- ('sqli_confirmed', 'SQL injection confirmed'),
196
- ('has:databases', 'Databases enumerated'),
197
- ('has:tables', 'Tables enumerated'),
198
- ('has:columns', 'Columns enumerated'),
199
- ('custom', 'Enter custom condition')
213
+ ("sqli_confirmed", "SQL injection confirmed"),
214
+ ("has:databases", "Databases enumerated"),
215
+ ("has:tables", "Tables enumerated"),
216
+ ("has:columns", "Columns enumerated"),
217
+ ("custom", "Enter custom condition"),
200
218
  ]
201
219
  else:
202
220
  # Generic conditions for other tools
203
221
  conditions = [
204
- ('service:http', 'HTTP service found'),
205
- ('service:smb', 'SMB service found'),
206
- ('has:domains', 'Domain/subdomain discovered'),
207
- ('has:databases', 'Database found'),
208
- ('finding:vulnerability', 'Vulnerability detected'),
209
- ('port:*', 'Any open port'),
210
- ('custom', 'Enter custom condition')
222
+ ("service:http", "HTTP service found"),
223
+ ("service:smb", "SMB service found"),
224
+ ("has:domains", "Domain/subdomain discovered"),
225
+ ("has:databases", "Database found"),
226
+ ("finding:vulnerability", "Vulnerability detected"),
227
+ ("port:*", "Any open port"),
228
+ ("custom", "Enter custom condition"),
211
229
  ]
212
-
230
+
213
231
  for idx, (cond, desc) in enumerate(conditions, 1):
214
232
  click.echo(f" [{idx}] {desc}")
215
-
233
+
216
234
  click.echo()
217
235
  click.echo(" [q] Cancel")
218
236
  click.echo()
219
-
237
+
220
238
  try:
221
- choice = click.prompt(" Select option", type=str, show_default=False).strip().lower()
222
-
223
- if choice == 'q':
239
+ choice = (
240
+ click.prompt(" Select option", type=str, show_default=False)
241
+ .strip()
242
+ .lower()
243
+ )
244
+
245
+ if choice == "q":
224
246
  return None
225
-
247
+
226
248
  try:
227
249
  idx = int(choice)
228
250
  if 1 <= idx <= len(conditions):
229
251
  condition = conditions[idx - 1][0]
230
- if condition == 'custom':
252
+ if condition == "custom":
231
253
  click.echo()
232
- click.echo(" " + click.style("Examples:", fg='yellow'))
254
+ click.echo(" " + click.style("Examples:", fg="yellow"))
233
255
  click.echo(" service:ftp, port:8080, has:tables, finding:xss")
234
256
  condition = click.prompt(" Enter condition", type=str)
235
- elif condition == 'port:*':
236
- port = click.prompt(" Enter specific port (or * for any)", default='*')
237
- if port != '*':
238
- condition = f'port:{port}'
257
+ elif condition == "port:*":
258
+ port = click.prompt(
259
+ " Enter specific port (or * for any)", default="*"
260
+ )
261
+ if port != "*":
262
+ condition = f"port:{port}"
239
263
  return condition
240
264
  except ValueError:
241
265
  pass
242
-
243
- click.echo(click.style(" Invalid selection", fg='red'))
266
+
267
+ click.echo(click.style(" Invalid selection", fg="red"))
244
268
  click.pause()
245
269
  return None
246
-
270
+
247
271
  except (KeyboardInterrupt, click.Abort):
248
272
  return None
249
273
 
@@ -252,62 +276,70 @@ def _select_target_tool() -> Optional[str]:
252
276
  """Step 3: Select target tool."""
253
277
  DesignSystem.clear_screen()
254
278
  width = 60
255
-
279
+
256
280
  click.echo("\n┌" + "─" * (width - 2) + "┐")
257
- click.echo("│" + click.style(" STEP 3: TARGET TOOL ".center(width - 2), bold=True, fg='cyan') + "│")
281
+ click.echo(
282
+ "│"
283
+ + click.style(" STEP 3: TARGET TOOL ".center(width - 2), bold=True, fg="cyan")
284
+ + "│"
285
+ )
258
286
  click.echo("└" + "─" * (width - 2) + "┘")
259
287
  click.echo()
260
288
  click.echo(" Then run...")
261
289
  click.echo()
262
-
290
+
263
291
  # Comprehensive list of target tools
264
292
  tools = [
265
- ('gobuster', 'Directory brute-force'),
266
- ('ffuf', 'Web fuzzing'),
267
- ('nuclei', 'Vulnerability scanning'),
268
- ('wpscan', 'WordPress scanning'),
269
- ('sqlmap', 'SQL injection testing'),
270
- ('hydra', 'Credential brute-force'),
271
- ('crackmapexec', 'Windows/AD testing'),
272
- ('smbmap', 'SMB share mapping'),
273
- ('enum4linux', 'SMB/Samba enumeration'),
274
- ('bloodhound', 'AD attack path mapping'),
275
- ('impacket-secretsdump', 'Credential dumping'),
276
- ('impacket-getnpusers', 'AS-REP roasting'),
277
- ('responder', 'LLMNR poisoning'),
278
- ('searchsploit', 'Exploit database search'),
279
- ('hashcat', 'Hash cracking'),
280
- ('john', 'Password cracking'),
281
- ('custom', 'Enter custom tool name')
293
+ ("gobuster", "Directory brute-force"),
294
+ ("ffuf", "Web fuzzing"),
295
+ ("nuclei", "Vulnerability scanning"),
296
+ ("wpscan", "WordPress scanning"),
297
+ ("sqlmap", "SQL injection testing"),
298
+ ("hydra", "Credential brute-force"),
299
+ ("crackmapexec", "Windows/AD testing"),
300
+ ("smbmap", "SMB share mapping"),
301
+ ("enum4linux", "SMB/Samba enumeration"),
302
+ ("bloodhound", "AD attack path mapping"),
303
+ ("impacket-secretsdump", "Credential dumping"),
304
+ ("impacket-getnpusers", "AS-REP roasting"),
305
+ ("responder", "LLMNR poisoning"),
306
+ ("searchsploit", "Exploit database search"),
307
+ ("hashcat", "Hash cracking"),
308
+ ("john", "Password cracking"),
309
+ ("custom", "Enter custom tool name"),
282
310
  ]
283
-
311
+
284
312
  for idx, (tool, desc) in enumerate(tools, 1):
285
313
  click.echo(f" [{idx}] {tool:<15} - {desc}")
286
-
314
+
287
315
  click.echo()
288
316
  click.echo(" [q] Cancel")
289
317
  click.echo()
290
-
318
+
291
319
  try:
292
- choice = click.prompt(" Select option", type=str, show_default=False).strip().lower()
293
-
294
- if choice == 'q':
320
+ choice = (
321
+ click.prompt(" Select option", type=str, show_default=False)
322
+ .strip()
323
+ .lower()
324
+ )
325
+
326
+ if choice == "q":
295
327
  return None
296
-
328
+
297
329
  try:
298
330
  idx = int(choice)
299
331
  if 1 <= idx <= len(tools):
300
332
  tool_name = tools[idx - 1][0]
301
- if tool_name == 'custom':
333
+ if tool_name == "custom":
302
334
  tool_name = click.prompt(" Enter tool name", type=str)
303
335
  return tool_name
304
336
  except ValueError:
305
337
  pass
306
-
307
- click.echo(click.style(" Invalid selection", fg='red'))
338
+
339
+ click.echo(click.style(" Invalid selection", fg="red"))
308
340
  click.pause()
309
341
  return None
310
-
342
+
311
343
  except (KeyboardInterrupt, click.Abort):
312
344
  return None
313
345
 
@@ -316,59 +348,112 @@ def _select_args_template(tool: str) -> List[str]:
316
348
  """Step 4: Select args template."""
317
349
  DesignSystem.clear_screen()
318
350
  width = 60
319
-
351
+
320
352
  click.echo("\n┌" + "─" * (width - 2) + "┐")
321
- click.echo("│" + click.style(" STEP 4: ARGUMENTS ".center(width - 2), bold=True, fg='cyan') + "│")
353
+ click.echo(
354
+ "│"
355
+ + click.style(" STEP 4: ARGUMENTS ".center(width - 2), bold=True, fg="cyan")
356
+ + "│"
357
+ )
322
358
  click.echo("└" + "─" * (width - 2) + "┘")
323
359
  click.echo()
324
360
  click.echo(f" Arguments for {click.style(tool, fg='yellow')} (optional)")
325
361
  click.echo()
326
-
362
+
327
363
  # Tool-specific presets with common use cases
328
364
  presets = {
329
- 'gobuster': [
330
- (['dir', '-u', '{target}', '-w', '/usr/share/wordlists/dirb/common.txt'], 'Default - common.txt wordlist'),
331
- (['dir', '-u', '{target}', '-w', '/usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt'], 'Large - directory-list-2.3-medium.txt'),
365
+ "gobuster": [
366
+ (
367
+ ["dir", "-u", "{target}", "-w", "data/wordlists/web_dirs_common.txt"],
368
+ "Default - web_dirs_common.txt",
369
+ ),
370
+ (
371
+ ["dir", "-u", "{target}", "-w", "data/wordlists/web_dirs_large.txt"],
372
+ "Large - web_dirs_large.txt",
373
+ ),
332
374
  ],
333
- 'ffuf': [
334
- (['-u', '{target}/FUZZ', '-w', '/usr/share/wordlists/dirb/common.txt'], 'Directory fuzzing'),
335
- (['-u', '{target}?FUZZ=value', '-w', '/usr/share/wordlists/burp-parameter-names.txt'], 'Parameter fuzzing'),
375
+ "ffuf": [
376
+ (
377
+ ["-u", "{target}/FUZZ", "-w", "data/wordlists/web_dirs_common.txt"],
378
+ "Directory fuzzing",
379
+ ),
380
+ (
381
+ [
382
+ "-u",
383
+ "{target}?FUZZ=value",
384
+ "-w",
385
+ "data/wordlists/web_files_common.txt",
386
+ ],
387
+ "Parameter fuzzing",
388
+ ),
336
389
  ],
337
- 'nuclei': [
338
- (['-u', '{target}', '-severity', 'critical,high'], 'Critical/High severity only'),
339
- (['-u', '{target}', '-tags', 'cve'], 'CVE templates only'),
340
- (['-u', '{target}'], 'All templates (default)'),
390
+ "nuclei": [
391
+ (
392
+ ["-u", "{target}", "-severity", "critical,high"],
393
+ "Critical/High severity only",
394
+ ),
395
+ (["-u", "{target}", "-tags", "cve"], "CVE templates only"),
396
+ (["-u", "{target}"], "All templates (default)"),
341
397
  ],
342
- 'sqlmap': [
343
- (['-u', '{target}', '--batch', '--dbs'], 'Enumerate databases'),
344
- (['-u', '{target}', '--batch', '--forms', '--crawl=2'], 'Form-based with crawling'),
398
+ "sqlmap": [
399
+ (["-u", "{target}", "--batch", "--dbs"], "Enumerate databases"),
400
+ (
401
+ ["-u", "{target}", "--batch", "--forms", "--crawl=2"],
402
+ "Form-based with crawling",
403
+ ),
345
404
  ],
346
- 'hydra': [
347
- (['-L', '/usr/share/wordlists/metasploit/unix_users.txt', '-P', '/usr/share/wordlists/rockyou.txt', '{target}', 'ssh'], 'SSH brute-force'),
348
- (['-L', '/usr/share/wordlists/metasploit/unix_users.txt', '-P', '/usr/share/wordlists/rockyou.txt', '{target}', 'ftp'], 'FTP brute-force'),
405
+ "hydra": [
406
+ (
407
+ [
408
+ "-L",
409
+ "data/wordlists/usernames_common.txt",
410
+ "-P",
411
+ "data/wordlists/passwords_brute.txt",
412
+ "{target}",
413
+ "ssh",
414
+ ],
415
+ "SSH brute-force",
416
+ ),
417
+ (
418
+ [
419
+ "-L",
420
+ "data/wordlists/usernames_common.txt",
421
+ "-P",
422
+ "data/wordlists/passwords_brute.txt",
423
+ "{target}",
424
+ "ftp",
425
+ ],
426
+ "FTP brute-force",
427
+ ),
349
428
  ],
350
- 'wpscan': [
351
- (['--url', '{target}', '--enumerate', 'vp,vt,u'], 'Enumerate plugins, themes, users'),
429
+ "wpscan": [
430
+ (
431
+ ["--url", "{target}", "--enumerate", "vp,vt,u"],
432
+ "Enumerate plugins, themes, users",
433
+ ),
434
+ ],
435
+ "crackmapexec": [
436
+ (
437
+ ["smb", "{target}", "-u", "Administrator", "-p", "password"],
438
+ "SMB authentication",
439
+ ),
440
+ (["smb", "{target}", "--shares"], "Enumerate SMB shares"),
352
441
  ],
353
- 'crackmapexec': [
354
- (['smb', '{target}', '-u', 'Administrator', '-p', 'password'], 'SMB authentication'),
355
- (['smb', '{target}', '--shares'], 'Enumerate SMB shares'),
356
- ]
357
442
  }
358
-
443
+
359
444
  if tool in presets:
360
- click.echo(" " + click.style("Common presets:", fg='yellow'))
445
+ click.echo(" " + click.style("Common presets:", fg="yellow"))
361
446
  for idx, (args, desc) in enumerate(presets[tool], 1):
362
447
  click.echo(f" [{idx}] {desc}")
363
448
  click.echo(f" [{len(presets[tool]) + 1}] Custom args...")
364
449
  click.echo(" [ENTER] Skip (no args)")
365
450
  click.echo()
366
-
367
- choice = click.prompt(" Select option", default='', show_default=False).strip()
368
-
451
+
452
+ choice = click.prompt(" Select option", default="", show_default=False).strip()
453
+
369
454
  if not choice:
370
455
  return []
371
-
456
+
372
457
  try:
373
458
  idx = int(choice)
374
459
  if 1 <= idx <= len(presets[tool]):
@@ -376,12 +461,16 @@ def _select_args_template(tool: str) -> List[str]:
376
461
  elif idx == len(presets[tool]) + 1:
377
462
  # Custom args
378
463
  click.echo()
379
- click.echo(" " + click.style("Placeholders available:", fg='yellow'))
464
+ click.echo(" " + click.style("Placeholders available:", fg="yellow"))
380
465
  click.echo(" {target} - Target URL/IP/host")
381
466
  click.echo(" {port} - Target port")
382
467
  click.echo(" {domain} - Domain name")
383
468
  click.echo()
384
- click.echo(" " + click.style("Example:", fg='yellow') + " -u {target} -o /tmp/output.txt")
469
+ click.echo(
470
+ " "
471
+ + click.style("Example:", fg="yellow")
472
+ + " -u {target} -o /tmp/output.txt"
473
+ )
385
474
  click.echo()
386
475
  args_str = click.prompt(" Enter arguments", type=str)
387
476
  return args_str.split()
@@ -389,23 +478,27 @@ def _select_args_template(tool: str) -> List[str]:
389
478
  pass
390
479
  else:
391
480
  # No presets for this tool - show help and get custom args
392
- click.echo(" " + click.style("No presets available for this tool.", fg='yellow'))
481
+ click.echo(
482
+ " " + click.style("No presets available for this tool.", fg="yellow")
483
+ )
393
484
  click.echo()
394
- click.echo(" " + click.style("Available placeholders:", fg='cyan'))
485
+ click.echo(" " + click.style("Available placeholders:", fg="cyan"))
395
486
  click.echo(" {target} - Target URL/IP/host")
396
487
  click.echo(" {port} - Target port")
397
488
  click.echo(" {domain} - Domain name")
398
489
  click.echo()
399
- click.echo(" " + click.style("Examples:", fg='cyan'))
490
+ click.echo(" " + click.style("Examples:", fg="cyan"))
400
491
  click.echo(" -u {target} --threads 10")
401
492
  click.echo(" --target {target}:{port}")
402
493
  click.echo(" -d {domain} -o output.txt")
403
494
  click.echo()
404
-
405
- args_str = click.prompt(" Enter arguments (or ENTER to skip)", default='', show_default=False)
495
+
496
+ args_str = click.prompt(
497
+ " Enter arguments (or ENTER to skip)", default="", show_default=False
498
+ )
406
499
  if args_str:
407
500
  return args_str.split()
408
-
501
+
409
502
  return []
410
503
 
411
504
 
@@ -413,40 +506,51 @@ def _configure_rule_settings() -> Optional[Dict[str, Any]]:
413
506
  """Step 5: Configure rule settings."""
414
507
  DesignSystem.clear_screen()
415
508
  width = 60
416
-
509
+
417
510
  click.echo("\n┌" + "─" * (width - 2) + "┐")
418
- click.echo("│" + click.style(" STEP 5: RULE SETTINGS ".center(width - 2), bold=True, fg='cyan') + "│")
511
+ click.echo(
512
+ "│"
513
+ + click.style(" STEP 5: RULE SETTINGS ".center(width - 2), bold=True, fg="cyan")
514
+ + "│"
515
+ )
419
516
  click.echo("└" + "─" * (width - 2) + "┘")
420
517
  click.echo()
421
-
518
+
422
519
  try:
423
- priority = click.prompt(" Priority (1-10, higher = runs first)",
424
- type=click.IntRange(1, 10), default=5)
425
-
520
+ priority = click.prompt(
521
+ " Priority (1-10, higher = runs first)",
522
+ type=click.IntRange(1, 10),
523
+ default=5,
524
+ )
525
+
426
526
  click.echo()
427
527
  click.echo(" Category:")
428
528
  click.echo(" [1] CTF - Aggressive scanning for practice environments")
429
529
  click.echo(" [2] Enterprise - Conservative scanning for production")
430
530
  click.echo(" [3] General - Balanced approach for most scenarios")
431
531
  click.echo()
432
-
433
- cat_choice = click.prompt(" Select option", type=click.IntRange(1, 3), default=3, show_default=False)
434
- categories = {1: 'CTF', 2: 'ENTERPRISE', 3: 'GENERAL'}
532
+
533
+ cat_choice = click.prompt(
534
+ " Select option", type=click.IntRange(1, 3), default=3, show_default=False
535
+ )
536
+ categories = {1: "CTF", 2: "ENTERPRISE", 3: "GENERAL"}
435
537
  category = categories[cat_choice]
436
-
538
+
437
539
  click.echo()
438
540
  enabled = click.confirm(" Enable immediately?", default=True)
439
-
541
+
440
542
  click.echo()
441
- description = click.prompt(" Description (optional)", default='', show_default=False)
442
-
543
+ description = click.prompt(
544
+ " Description (optional)", default="", show_default=False
545
+ )
546
+
443
547
  return {
444
- 'priority': priority,
445
- 'category': category,
446
- 'enabled': enabled,
447
- 'description': description
548
+ "priority": priority,
549
+ "category": category,
550
+ "enabled": enabled,
551
+ "description": description,
448
552
  }
449
-
553
+
450
554
  except (KeyboardInterrupt, click.Abort):
451
555
  return None
452
556
 
@@ -455,40 +559,54 @@ def _confirm_rule(rule: Dict[str, Any]) -> bool:
455
559
  """Show rule summary and confirm creation."""
456
560
  DesignSystem.clear_screen()
457
561
  width = 60
458
-
562
+
459
563
  click.echo("\n┌" + "─" * (width - 2) + "┐")
460
- click.echo("│" + click.style(" RULE CREATED! ".center(width - 2), bold=True, fg='green') + "│")
564
+ click.echo(
565
+ "│"
566
+ + click.style(" RULE CREATED! ".center(width - 2), bold=True, fg="green")
567
+ + "│"
568
+ )
461
569
  click.echo("└" + "─" * (width - 2) + "┘")
462
570
  click.echo()
463
-
571
+
464
572
  # Format rule display
465
- click.echo(" " + click.style("WHEN", fg='yellow', bold=True) + f" {rule['trigger_tool']} finds {rule['condition']}")
466
- click.echo(" " + click.style("THEN", fg='yellow', bold=True) + f" run {rule['target_tool']}")
467
-
468
- if rule['args']:
469
- args_str = ' '.join(rule['args'])
470
- click.echo(" " + click.style("WITH", fg='yellow', bold=True) + f" {args_str}")
471
-
573
+ click.echo(
574
+ " "
575
+ + click.style("WHEN", fg="yellow", bold=True)
576
+ + f" {rule['trigger_tool']} finds {rule['condition']}"
577
+ )
578
+ click.echo(
579
+ " "
580
+ + click.style("THEN", fg="yellow", bold=True)
581
+ + f" run {rule['target_tool']}"
582
+ )
583
+
584
+ if rule["args"]:
585
+ args_str = " ".join(rule["args"])
586
+ click.echo(" " + click.style("WITH", fg="yellow", bold=True) + f" {args_str}")
587
+
472
588
  click.echo()
473
589
  click.echo(f" Priority: {rule['priority']}/10")
474
590
  click.echo(f" Category: {rule['category']}")
475
591
  click.echo(f" Status: {'ENABLED' if rule['enabled'] else 'DISABLED'}")
476
-
477
- if rule['description']:
592
+
593
+ if rule["description"]:
478
594
  click.echo(f" Description: {rule['description']}")
479
-
595
+
480
596
  click.echo()
481
597
  click.echo(" [ENTER] Save rule [+] Create another [q] Cancel")
482
598
  click.echo()
483
-
484
- choice = click.prompt(" Select option", default='', show_default=False).strip().lower()
485
-
486
- return choice != 'q'
599
+
600
+ choice = (
601
+ click.prompt(" Select option", default="", show_default=False).strip().lower()
602
+ )
603
+
604
+ return choice != "q"
487
605
 
488
606
 
489
607
  def _advanced_mode_builder() -> Optional[Dict[str, Any]]:
490
608
  """Advanced mode with full control (to be implemented)."""
491
- click.echo(click.style("\n Advanced mode coming soon!", fg='yellow'))
609
+ click.echo(click.style("\n Advanced mode coming soon!", fg="yellow"))
492
610
  click.pause()
493
611
  return None
494
612
 
@@ -496,26 +614,26 @@ def _advanced_mode_builder() -> Optional[Dict[str, Any]]:
496
614
  def _save_custom_rule(rule: Dict[str, Any]) -> bool:
497
615
  """
498
616
  Save custom rule to file.
499
-
617
+
500
618
  Args:
501
619
  rule: Rule dictionary
502
-
620
+
503
621
  Returns:
504
622
  bool: True if saved successfully
505
623
  """
506
624
  try:
507
625
  from souleyez.core.tool_chaining import ToolChaining
508
-
626
+
509
627
  tc = ToolChaining()
510
628
  tc.add_custom_rule(rule)
511
-
629
+
512
630
  click.echo()
513
- click.echo(click.style(" ✓ Rule saved successfully!", fg='green'))
631
+ click.echo(click.style(" ✓ Rule saved successfully!", fg="green"))
514
632
  click.pause()
515
633
  return True
516
-
634
+
517
635
  except Exception as e:
518
636
  click.echo()
519
- click.echo(click.style(f" ✗ Failed to save rule: {e}", fg='red'))
637
+ click.echo(click.style(f" ✗ Failed to save rule: {e}", fg="red"))
520
638
  click.pause()
521
639
  return False