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.
Potentially problematic release.
This version of souleyez might be problematic. Click here for more details.
- souleyez/__init__.py +1 -2
- souleyez/ai/__init__.py +21 -15
- souleyez/ai/action_mapper.py +249 -150
- souleyez/ai/chain_advisor.py +116 -100
- souleyez/ai/claude_provider.py +29 -28
- souleyez/ai/context_builder.py +80 -62
- souleyez/ai/executor.py +158 -117
- souleyez/ai/feedback_handler.py +136 -121
- souleyez/ai/llm_factory.py +27 -20
- souleyez/ai/llm_provider.py +4 -2
- souleyez/ai/ollama_provider.py +6 -9
- souleyez/ai/ollama_service.py +44 -37
- souleyez/ai/path_scorer.py +91 -76
- souleyez/ai/recommender.py +176 -144
- souleyez/ai/report_context.py +74 -73
- souleyez/ai/report_service.py +84 -66
- souleyez/ai/result_parser.py +222 -229
- souleyez/ai/safety.py +67 -44
- souleyez/auth/__init__.py +23 -22
- souleyez/auth/audit.py +36 -26
- souleyez/auth/engagement_access.py +65 -48
- souleyez/auth/permissions.py +14 -3
- souleyez/auth/session_manager.py +54 -37
- souleyez/auth/user_manager.py +109 -64
- souleyez/commands/audit.py +40 -43
- souleyez/commands/auth.py +35 -15
- souleyez/commands/deliverables.py +55 -50
- souleyez/commands/engagement.py +47 -28
- souleyez/commands/license.py +32 -23
- souleyez/commands/screenshots.py +36 -32
- souleyez/commands/user.py +82 -36
- souleyez/config.py +52 -44
- souleyez/core/credential_tester.py +87 -81
- souleyez/core/cve_mappings.py +179 -192
- souleyez/core/cve_matcher.py +162 -148
- souleyez/core/msf_auto_mapper.py +100 -83
- souleyez/core/msf_chain_engine.py +294 -256
- souleyez/core/msf_database.py +153 -70
- souleyez/core/msf_integration.py +679 -673
- souleyez/core/msf_rpc_client.py +40 -42
- souleyez/core/msf_rpc_manager.py +77 -79
- souleyez/core/msf_sync_manager.py +241 -181
- souleyez/core/network_utils.py +22 -15
- souleyez/core/parser_handler.py +34 -25
- souleyez/core/pending_chains.py +114 -63
- souleyez/core/templates.py +158 -107
- souleyez/core/tool_chaining.py +9564 -2881
- souleyez/core/version_utils.py +79 -94
- souleyez/core/vuln_correlation.py +136 -89
- souleyez/core/web_utils.py +33 -32
- souleyez/data/wordlists/ad_users.txt +378 -0
- souleyez/data/wordlists/api_endpoints_large.txt +769 -0
- souleyez/data/wordlists/home_dir_sensitive.txt +39 -0
- souleyez/data/wordlists/lfi_payloads.txt +82 -0
- souleyez/data/wordlists/passwords_brute.txt +1548 -0
- souleyez/data/wordlists/passwords_crack.txt +2479 -0
- souleyez/data/wordlists/passwords_spray.txt +386 -0
- souleyez/data/wordlists/subdomains_large.txt +5057 -0
- souleyez/data/wordlists/usernames_common.txt +694 -0
- souleyez/data/wordlists/web_dirs_large.txt +4769 -0
- souleyez/detection/__init__.py +1 -1
- souleyez/detection/attack_signatures.py +12 -17
- souleyez/detection/mitre_mappings.py +61 -55
- souleyez/detection/validator.py +97 -86
- souleyez/devtools.py +23 -10
- souleyez/docs/README.md +4 -4
- souleyez/docs/api-reference/cli-commands.md +2 -2
- souleyez/docs/developer-guide/adding-new-tools.md +562 -0
- souleyez/docs/user-guide/auto-chaining.md +30 -8
- souleyez/docs/user-guide/getting-started.md +1 -1
- souleyez/docs/user-guide/installation.md +26 -3
- souleyez/docs/user-guide/metasploit-integration.md +2 -2
- souleyez/docs/user-guide/rbac.md +1 -1
- souleyez/docs/user-guide/scope-management.md +1 -1
- souleyez/docs/user-guide/siem-integration.md +1 -1
- souleyez/docs/user-guide/tools-reference.md +1 -8
- souleyez/docs/user-guide/worker-management.md +1 -1
- souleyez/engine/background.py +1239 -535
- souleyez/engine/base.py +4 -1
- souleyez/engine/job_status.py +17 -49
- souleyez/engine/log_sanitizer.py +103 -77
- souleyez/engine/manager.py +38 -7
- souleyez/engine/result_handler.py +2200 -1550
- souleyez/engine/worker_manager.py +50 -41
- souleyez/export/evidence_bundle.py +72 -62
- souleyez/feature_flags/features.py +16 -20
- souleyez/feature_flags.py +5 -9
- souleyez/handlers/__init__.py +11 -0
- souleyez/handlers/base.py +188 -0
- souleyez/handlers/bash_handler.py +277 -0
- souleyez/handlers/bloodhound_handler.py +243 -0
- souleyez/handlers/certipy_handler.py +311 -0
- souleyez/handlers/crackmapexec_handler.py +486 -0
- souleyez/handlers/dnsrecon_handler.py +344 -0
- souleyez/handlers/enum4linux_handler.py +400 -0
- souleyez/handlers/evil_winrm_handler.py +493 -0
- souleyez/handlers/ffuf_handler.py +815 -0
- souleyez/handlers/gobuster_handler.py +1114 -0
- souleyez/handlers/gpp_extract_handler.py +334 -0
- souleyez/handlers/hashcat_handler.py +444 -0
- souleyez/handlers/hydra_handler.py +564 -0
- souleyez/handlers/impacket_getuserspns_handler.py +343 -0
- souleyez/handlers/impacket_psexec_handler.py +222 -0
- souleyez/handlers/impacket_secretsdump_handler.py +426 -0
- souleyez/handlers/john_handler.py +286 -0
- souleyez/handlers/katana_handler.py +425 -0
- souleyez/handlers/kerbrute_handler.py +298 -0
- souleyez/handlers/ldapsearch_handler.py +636 -0
- souleyez/handlers/lfi_extract_handler.py +464 -0
- souleyez/handlers/msf_auxiliary_handler.py +409 -0
- souleyez/handlers/msf_exploit_handler.py +380 -0
- souleyez/handlers/nikto_handler.py +413 -0
- souleyez/handlers/nmap_handler.py +821 -0
- souleyez/handlers/nuclei_handler.py +359 -0
- souleyez/handlers/nxc_handler.py +417 -0
- souleyez/handlers/rdp_sec_check_handler.py +353 -0
- souleyez/handlers/registry.py +292 -0
- souleyez/handlers/responder_handler.py +232 -0
- souleyez/handlers/service_explorer_handler.py +434 -0
- souleyez/handlers/smbclient_handler.py +344 -0
- souleyez/handlers/smbmap_handler.py +510 -0
- souleyez/handlers/smbpasswd_handler.py +296 -0
- souleyez/handlers/sqlmap_handler.py +1116 -0
- souleyez/handlers/theharvester_handler.py +601 -0
- souleyez/handlers/web_login_test_handler.py +327 -0
- souleyez/handlers/whois_handler.py +277 -0
- souleyez/handlers/wpscan_handler.py +554 -0
- souleyez/history.py +32 -16
- souleyez/importers/msf_importer.py +106 -75
- souleyez/importers/smart_importer.py +208 -147
- souleyez/integrations/siem/__init__.py +10 -10
- souleyez/integrations/siem/base.py +17 -18
- souleyez/integrations/siem/elastic.py +108 -122
- souleyez/integrations/siem/factory.py +207 -80
- souleyez/integrations/siem/googlesecops.py +146 -154
- souleyez/integrations/siem/rule_mappings/__init__.py +1 -1
- souleyez/integrations/siem/rule_mappings/wazuh_rules.py +8 -5
- souleyez/integrations/siem/sentinel.py +107 -109
- souleyez/integrations/siem/splunk.py +246 -212
- souleyez/integrations/siem/wazuh.py +65 -71
- souleyez/integrations/wazuh/__init__.py +5 -5
- souleyez/integrations/wazuh/client.py +70 -93
- souleyez/integrations/wazuh/config.py +85 -57
- souleyez/integrations/wazuh/host_mapper.py +28 -36
- souleyez/integrations/wazuh/sync.py +78 -68
- souleyez/intelligence/__init__.py +4 -5
- souleyez/intelligence/correlation_analyzer.py +309 -295
- souleyez/intelligence/exploit_knowledge.py +661 -623
- souleyez/intelligence/exploit_suggestions.py +159 -139
- souleyez/intelligence/gap_analyzer.py +132 -97
- souleyez/intelligence/gap_detector.py +251 -214
- souleyez/intelligence/sensitive_tables.py +266 -129
- souleyez/intelligence/service_parser.py +137 -123
- souleyez/intelligence/surface_analyzer.py +407 -268
- souleyez/intelligence/target_parser.py +159 -162
- souleyez/licensing/__init__.py +6 -6
- souleyez/licensing/validator.py +17 -19
- souleyez/log_config.py +79 -54
- souleyez/main.py +1505 -687
- souleyez/migrations/fix_job_counter.py +16 -14
- souleyez/parsers/bloodhound_parser.py +41 -39
- souleyez/parsers/crackmapexec_parser.py +178 -111
- souleyez/parsers/dalfox_parser.py +72 -77
- souleyez/parsers/dnsrecon_parser.py +103 -91
- souleyez/parsers/enum4linux_parser.py +183 -153
- souleyez/parsers/ffuf_parser.py +29 -25
- souleyez/parsers/gobuster_parser.py +301 -41
- souleyez/parsers/hashcat_parser.py +324 -79
- souleyez/parsers/http_fingerprint_parser.py +350 -103
- souleyez/parsers/hydra_parser.py +131 -111
- souleyez/parsers/impacket_parser.py +231 -178
- souleyez/parsers/john_parser.py +98 -86
- souleyez/parsers/katana_parser.py +316 -0
- souleyez/parsers/msf_parser.py +943 -498
- souleyez/parsers/nikto_parser.py +346 -65
- souleyez/parsers/nmap_parser.py +262 -174
- souleyez/parsers/nuclei_parser.py +40 -44
- souleyez/parsers/responder_parser.py +26 -26
- souleyez/parsers/searchsploit_parser.py +74 -74
- souleyez/parsers/service_explorer_parser.py +279 -0
- souleyez/parsers/smbmap_parser.py +180 -124
- souleyez/parsers/sqlmap_parser.py +434 -308
- souleyez/parsers/theharvester_parser.py +75 -57
- souleyez/parsers/whois_parser.py +135 -94
- souleyez/parsers/wpscan_parser.py +278 -190
- souleyez/plugins/afp.py +44 -36
- souleyez/plugins/afp_brute.py +114 -46
- souleyez/plugins/ard.py +48 -37
- souleyez/plugins/bloodhound.py +95 -61
- souleyez/plugins/certipy.py +303 -0
- souleyez/plugins/crackmapexec.py +186 -85
- souleyez/plugins/dalfox.py +120 -59
- souleyez/plugins/dns_hijack.py +146 -41
- souleyez/plugins/dnsrecon.py +97 -61
- souleyez/plugins/enum4linux.py +91 -66
- souleyez/plugins/evil_winrm.py +291 -0
- souleyez/plugins/ffuf.py +166 -90
- souleyez/plugins/firmware_extract.py +133 -29
- souleyez/plugins/gobuster.py +387 -190
- souleyez/plugins/gpp_extract.py +393 -0
- souleyez/plugins/hashcat.py +100 -73
- souleyez/plugins/http_fingerprint.py +913 -267
- souleyez/plugins/hydra.py +566 -200
- souleyez/plugins/impacket_getnpusers.py +117 -69
- souleyez/plugins/impacket_psexec.py +84 -64
- souleyez/plugins/impacket_secretsdump.py +103 -69
- souleyez/plugins/impacket_smbclient.py +89 -75
- souleyez/plugins/john.py +86 -69
- souleyez/plugins/katana.py +313 -0
- souleyez/plugins/kerbrute.py +237 -0
- souleyez/plugins/lfi_extract.py +541 -0
- souleyez/plugins/macos_ssh.py +117 -48
- souleyez/plugins/mdns.py +35 -30
- souleyez/plugins/msf_auxiliary.py +253 -130
- souleyez/plugins/msf_exploit.py +239 -161
- souleyez/plugins/nikto.py +134 -78
- souleyez/plugins/nmap.py +275 -91
- souleyez/plugins/nuclei.py +180 -89
- souleyez/plugins/nxc.py +285 -0
- souleyez/plugins/plugin_base.py +35 -36
- souleyez/plugins/plugin_template.py +13 -5
- souleyez/plugins/rdp_sec_check.py +130 -0
- souleyez/plugins/responder.py +112 -71
- souleyez/plugins/router_http_brute.py +76 -65
- souleyez/plugins/router_ssh_brute.py +118 -41
- souleyez/plugins/router_telnet_brute.py +124 -42
- souleyez/plugins/routersploit.py +91 -59
- souleyez/plugins/routersploit_exploit.py +77 -55
- souleyez/plugins/searchsploit.py +91 -77
- souleyez/plugins/service_explorer.py +1160 -0
- souleyez/plugins/smbmap.py +122 -72
- souleyez/plugins/smbpasswd.py +215 -0
- souleyez/plugins/sqlmap.py +301 -113
- souleyez/plugins/theharvester.py +127 -75
- souleyez/plugins/tr069.py +79 -57
- souleyez/plugins/upnp.py +65 -47
- souleyez/plugins/upnp_abuse.py +73 -55
- souleyez/plugins/vnc_access.py +129 -42
- souleyez/plugins/vnc_brute.py +109 -38
- souleyez/plugins/web_login_test.py +417 -0
- souleyez/plugins/whois.py +77 -58
- souleyez/plugins/wpscan.py +219 -69
- souleyez/reporting/__init__.py +2 -1
- souleyez/reporting/attack_chain.py +411 -346
- souleyez/reporting/charts.py +436 -501
- souleyez/reporting/compliance_mappings.py +334 -201
- souleyez/reporting/detection_report.py +126 -125
- souleyez/reporting/formatters.py +828 -591
- souleyez/reporting/generator.py +386 -302
- souleyez/reporting/metrics.py +72 -75
- souleyez/scanner.py +35 -29
- souleyez/security/__init__.py +37 -11
- souleyez/security/scope_validator.py +175 -106
- souleyez/security/validation.py +237 -149
- souleyez/security.py +22 -6
- souleyez/storage/credentials.py +247 -186
- souleyez/storage/crypto.py +296 -129
- souleyez/storage/database.py +73 -50
- souleyez/storage/db.py +58 -36
- souleyez/storage/deliverable_evidence.py +177 -128
- souleyez/storage/deliverable_exporter.py +282 -246
- souleyez/storage/deliverable_templates.py +134 -116
- souleyez/storage/deliverables.py +135 -130
- souleyez/storage/engagements.py +109 -56
- souleyez/storage/evidence.py +181 -152
- souleyez/storage/execution_log.py +31 -17
- souleyez/storage/exploit_attempts.py +93 -57
- souleyez/storage/exploits.py +67 -36
- souleyez/storage/findings.py +48 -61
- souleyez/storage/hosts.py +176 -144
- souleyez/storage/migrate_to_engagements.py +43 -19
- souleyez/storage/migrations/_001_add_credential_enhancements.py +22 -12
- souleyez/storage/migrations/_002_add_status_tracking.py +10 -7
- souleyez/storage/migrations/_003_add_execution_log.py +14 -8
- souleyez/storage/migrations/_005_screenshots.py +13 -5
- souleyez/storage/migrations/_006_deliverables.py +13 -5
- souleyez/storage/migrations/_007_deliverable_templates.py +12 -7
- souleyez/storage/migrations/_008_add_nuclei_table.py +10 -4
- souleyez/storage/migrations/_010_evidence_linking.py +17 -10
- souleyez/storage/migrations/_011_timeline_tracking.py +20 -13
- souleyez/storage/migrations/_012_team_collaboration.py +34 -21
- souleyez/storage/migrations/_013_add_host_tags.py +12 -6
- souleyez/storage/migrations/_014_exploit_attempts.py +22 -10
- souleyez/storage/migrations/_015_add_mac_os_fields.py +15 -7
- souleyez/storage/migrations/_016_add_domain_field.py +10 -4
- souleyez/storage/migrations/_017_msf_sessions.py +16 -8
- souleyez/storage/migrations/_018_add_osint_target.py +10 -6
- souleyez/storage/migrations/_019_add_engagement_type.py +10 -6
- souleyez/storage/migrations/_020_add_rbac.py +36 -15
- souleyez/storage/migrations/_021_wazuh_integration.py +20 -8
- souleyez/storage/migrations/_022_wazuh_indexer_columns.py +6 -4
- souleyez/storage/migrations/_023_fix_detection_results_fk.py +16 -6
- souleyez/storage/migrations/_024_wazuh_vulnerabilities.py +26 -10
- souleyez/storage/migrations/_025_multi_siem_support.py +3 -5
- souleyez/storage/migrations/_026_add_engagement_scope.py +31 -12
- souleyez/storage/migrations/_027_multi_siem_persistence.py +32 -15
- souleyez/storage/migrations/__init__.py +26 -26
- souleyez/storage/migrations/migration_manager.py +19 -19
- souleyez/storage/msf_sessions.py +100 -65
- souleyez/storage/osint.py +17 -24
- souleyez/storage/recommendation_engine.py +269 -235
- souleyez/storage/screenshots.py +33 -32
- souleyez/storage/smb_shares.py +136 -92
- souleyez/storage/sqlmap_data.py +183 -128
- souleyez/storage/team_collaboration.py +135 -141
- souleyez/storage/timeline_tracker.py +122 -94
- souleyez/storage/wazuh_vulns.py +64 -66
- souleyez/storage/web_paths.py +33 -37
- souleyez/testing/credential_tester.py +221 -205
- souleyez/ui/__init__.py +1 -1
- souleyez/ui/ai_quotes.py +12 -12
- souleyez/ui/attack_surface.py +2439 -1516
- souleyez/ui/chain_rules_view.py +914 -382
- souleyez/ui/correlation_view.py +312 -230
- souleyez/ui/dashboard.py +2382 -1130
- souleyez/ui/deliverables_view.py +148 -62
- souleyez/ui/design_system.py +13 -13
- souleyez/ui/errors.py +49 -49
- souleyez/ui/evidence_linking_view.py +284 -179
- souleyez/ui/evidence_vault.py +393 -285
- souleyez/ui/exploit_suggestions_view.py +555 -349
- souleyez/ui/export_view.py +100 -66
- souleyez/ui/gap_analysis_view.py +315 -171
- souleyez/ui/help_system.py +105 -97
- souleyez/ui/intelligence_view.py +436 -293
- souleyez/ui/interactive.py +23034 -10679
- souleyez/ui/interactive_selector.py +75 -68
- souleyez/ui/log_formatter.py +47 -39
- souleyez/ui/menu_components.py +22 -13
- souleyez/ui/msf_auxiliary_menu.py +184 -133
- souleyez/ui/pending_chains_view.py +336 -172
- souleyez/ui/progress_indicators.py +5 -3
- souleyez/ui/recommendations_view.py +195 -137
- souleyez/ui/rule_builder.py +343 -225
- souleyez/ui/setup_wizard.py +678 -284
- souleyez/ui/shortcuts.py +217 -165
- souleyez/ui/splunk_gap_analysis_view.py +452 -270
- souleyez/ui/splunk_vulns_view.py +139 -86
- souleyez/ui/team_dashboard.py +498 -335
- souleyez/ui/template_selector.py +196 -105
- souleyez/ui/terminal.py +6 -6
- souleyez/ui/timeline_view.py +198 -127
- souleyez/ui/tool_setup.py +264 -164
- souleyez/ui/tutorial.py +202 -72
- souleyez/ui/tutorial_state.py +40 -40
- souleyez/ui/wazuh_vulns_view.py +235 -141
- souleyez/ui/wordlist_browser.py +260 -107
- souleyez/ui.py +464 -312
- souleyez/utils/tool_checker.py +427 -367
- souleyez/utils.py +33 -29
- souleyez/wordlists.py +134 -167
- {souleyez-2.43.29.dist-info → souleyez-3.0.0.dist-info}/METADATA +2 -2
- souleyez-3.0.0.dist-info/RECORD +443 -0
- {souleyez-2.43.29.dist-info → souleyez-3.0.0.dist-info}/WHEEL +1 -1
- souleyez-2.43.29.dist-info/RECORD +0 -379
- {souleyez-2.43.29.dist-info → souleyez-3.0.0.dist-info}/entry_points.txt +0 -0
- {souleyez-2.43.29.dist-info → souleyez-3.0.0.dist-info}/licenses/LICENSE +0 -0
- {souleyez-2.43.29.dist-info → souleyez-3.0.0.dist-info}/top_level.txt +0 -0
souleyez/ui/tutorial.py
CHANGED
|
@@ -18,6 +18,7 @@ from souleyez.ui.tutorial_state import get_tutorial_state, TutorialStep
|
|
|
18
18
|
def clear_screen():
|
|
19
19
|
"""Clear the terminal screen."""
|
|
20
20
|
from souleyez.ui.design_system import DesignSystem
|
|
21
|
+
|
|
21
22
|
DesignSystem.clear_screen()
|
|
22
23
|
|
|
23
24
|
|
|
@@ -29,11 +30,11 @@ def wait_for_enter(prompt="Press Enter to continue..."):
|
|
|
29
30
|
def show_header(title, subtitle=None):
|
|
30
31
|
"""Display a section header."""
|
|
31
32
|
click.echo()
|
|
32
|
-
click.echo(click.style("=" * 60, fg=
|
|
33
|
-
click.echo(click.style(f" {title}", fg=
|
|
33
|
+
click.echo(click.style("=" * 60, fg="cyan"))
|
|
34
|
+
click.echo(click.style(f" {title}", fg="cyan", bold=True))
|
|
34
35
|
if subtitle:
|
|
35
|
-
click.echo(click.style(f" {subtitle}", fg=
|
|
36
|
-
click.echo(click.style("=" * 60, fg=
|
|
36
|
+
click.echo(click.style(f" {subtitle}", fg="white"))
|
|
37
|
+
click.echo(click.style("=" * 60, fg="cyan"))
|
|
37
38
|
click.echo()
|
|
38
39
|
|
|
39
40
|
|
|
@@ -58,7 +59,11 @@ def run_tutorial():
|
|
|
58
59
|
click.echo(" 2. Creating your first engagement")
|
|
59
60
|
click.echo(" 3. Enabling auto-chaining")
|
|
60
61
|
click.echo(" 4. Running reconnaissance scans")
|
|
61
|
-
click.echo(
|
|
62
|
+
click.echo(
|
|
63
|
+
" 5. "
|
|
64
|
+
+ click.style("Hands-on exploration", fg="yellow")
|
|
65
|
+
+ " of the Command Center"
|
|
66
|
+
)
|
|
62
67
|
click.echo()
|
|
63
68
|
|
|
64
69
|
wait_for_enter()
|
|
@@ -67,17 +72,39 @@ def run_tutorial():
|
|
|
67
72
|
clear_screen()
|
|
68
73
|
show_header("Step 1: Understanding Engagements")
|
|
69
74
|
|
|
70
|
-
click.echo(
|
|
75
|
+
click.echo(
|
|
76
|
+
"An "
|
|
77
|
+
+ click.style("engagement", fg="cyan", bold=True)
|
|
78
|
+
+ " is a container for all your pentest data."
|
|
79
|
+
)
|
|
71
80
|
click.echo()
|
|
72
81
|
click.echo("Think of it like a project folder that keeps everything organized:")
|
|
73
82
|
click.echo()
|
|
74
|
-
click.echo(
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
click.echo(
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
83
|
+
click.echo(
|
|
84
|
+
" • " + click.style("Hosts", fg="green") + " - Target systems you discover"
|
|
85
|
+
)
|
|
86
|
+
click.echo(
|
|
87
|
+
" • "
|
|
88
|
+
+ click.style("Services", fg="green")
|
|
89
|
+
+ " - Open ports and running software"
|
|
90
|
+
)
|
|
91
|
+
click.echo(
|
|
92
|
+
" • " + click.style("Findings", fg="green") + " - Vulnerabilities you find"
|
|
93
|
+
)
|
|
94
|
+
click.echo(
|
|
95
|
+
" • "
|
|
96
|
+
+ click.style("Credentials", fg="green")
|
|
97
|
+
+ " - Usernames, passwords, keys"
|
|
98
|
+
)
|
|
99
|
+
click.echo(
|
|
100
|
+
" • " + click.style("Evidence", fg="green") + " - Screenshots, logs, artifacts"
|
|
101
|
+
)
|
|
102
|
+
click.echo()
|
|
103
|
+
click.echo(
|
|
104
|
+
"Each engagement is "
|
|
105
|
+
+ click.style("isolated", fg="yellow")
|
|
106
|
+
+ " - data from one"
|
|
107
|
+
)
|
|
81
108
|
click.echo("pentest never mixes with another.")
|
|
82
109
|
click.echo()
|
|
83
110
|
|
|
@@ -89,9 +116,11 @@ def run_tutorial():
|
|
|
89
116
|
|
|
90
117
|
click.echo("Let's create a test engagement to practice with.")
|
|
91
118
|
click.echo()
|
|
92
|
-
click.echo(
|
|
119
|
+
click.echo(
|
|
120
|
+
"We'll use a " + click.style("safe, legal target", fg="green", bold=True) + ":"
|
|
121
|
+
)
|
|
93
122
|
click.echo()
|
|
94
|
-
click.echo(" " + click.style("vulnweb.com", fg=
|
|
123
|
+
click.echo(" " + click.style("vulnweb.com", fg="cyan"))
|
|
95
124
|
click.echo(" (Acunetix's intentionally vulnerable test domain)")
|
|
96
125
|
click.echo()
|
|
97
126
|
|
|
@@ -111,14 +140,16 @@ def run_tutorial():
|
|
|
111
140
|
# Check if tutorial engagement already exists
|
|
112
141
|
existing = em.get("Tutorial Engagement")
|
|
113
142
|
if existing:
|
|
114
|
-
engagement_id = existing[
|
|
115
|
-
click.echo(click.style("✓ Using existing Tutorial Engagement", fg=
|
|
143
|
+
engagement_id = existing["id"]
|
|
144
|
+
click.echo(click.style("✓ Using existing Tutorial Engagement", fg="green"))
|
|
116
145
|
else:
|
|
117
146
|
engagement_id = em.create(
|
|
118
147
|
name="Tutorial Engagement",
|
|
119
|
-
description="Created by SoulEyez tutorial. Target: vulnweb.com"
|
|
148
|
+
description="Created by SoulEyez tutorial. Target: vulnweb.com",
|
|
149
|
+
)
|
|
150
|
+
click.echo(
|
|
151
|
+
click.style("✓ Created engagement: Tutorial Engagement", fg="green")
|
|
120
152
|
)
|
|
121
|
-
click.echo(click.style("✓ Created engagement: Tutorial Engagement", fg='green'))
|
|
122
153
|
|
|
123
154
|
# Set as current engagement
|
|
124
155
|
em.set_current("Tutorial Engagement")
|
|
@@ -126,7 +157,7 @@ def run_tutorial():
|
|
|
126
157
|
click.echo()
|
|
127
158
|
|
|
128
159
|
except Exception as e:
|
|
129
|
-
click.echo(click.style(f"✗ Error creating engagement: {e}", fg=
|
|
160
|
+
click.echo(click.style(f"✗ Error creating engagement: {e}", fg="red"))
|
|
130
161
|
click.echo("Please check 'souleyez doctor' for issues.")
|
|
131
162
|
wait_for_enter()
|
|
132
163
|
return
|
|
@@ -137,13 +168,24 @@ def run_tutorial():
|
|
|
137
168
|
clear_screen()
|
|
138
169
|
show_header("Step 3: Enable Auto-Chaining")
|
|
139
170
|
|
|
140
|
-
click.echo(
|
|
171
|
+
click.echo(
|
|
172
|
+
"Before we scan, let's enable "
|
|
173
|
+
+ click.style("auto-chaining", fg="yellow", bold=True)
|
|
174
|
+
+ "!"
|
|
175
|
+
)
|
|
141
176
|
click.echo()
|
|
142
177
|
click.echo("Auto-chaining is SoulEyez's killer feature:")
|
|
143
178
|
click.echo()
|
|
144
|
-
click.echo(
|
|
145
|
-
|
|
146
|
-
|
|
179
|
+
click.echo(
|
|
180
|
+
" • When recon finds a host → " + click.style("auto-queue nmap", fg="cyan")
|
|
181
|
+
)
|
|
182
|
+
click.echo(
|
|
183
|
+
" • When nmap finds HTTP → "
|
|
184
|
+
+ click.style("auto-queue gobuster, nikto", fg="cyan")
|
|
185
|
+
)
|
|
186
|
+
click.echo(
|
|
187
|
+
" • When nmap finds SSH → " + click.style("auto-queue hydra", fg="cyan")
|
|
188
|
+
)
|
|
147
189
|
click.echo()
|
|
148
190
|
click.echo("It thinks like a pentester and queues the logical next steps!")
|
|
149
191
|
click.echo()
|
|
@@ -151,14 +193,19 @@ def run_tutorial():
|
|
|
151
193
|
if click.confirm("Enable auto-chaining for this tutorial?", default=True):
|
|
152
194
|
try:
|
|
153
195
|
from souleyez.core.tool_chaining import ToolChaining
|
|
196
|
+
|
|
154
197
|
chaining = ToolChaining()
|
|
155
198
|
chaining.enable_chaining()
|
|
156
199
|
click.echo()
|
|
157
|
-
click.echo(click.style(" ✓ Auto-chaining ENABLED!", fg=
|
|
158
|
-
click.echo(
|
|
200
|
+
click.echo(click.style(" ✓ Auto-chaining ENABLED!", fg="green", bold=True))
|
|
201
|
+
click.echo(
|
|
202
|
+
" Mode: "
|
|
203
|
+
+ click.style("AUTO", fg="green")
|
|
204
|
+
+ " (chains execute immediately)"
|
|
205
|
+
)
|
|
159
206
|
click.echo()
|
|
160
207
|
except Exception as e:
|
|
161
|
-
click.echo(click.style(f" Could not enable: {e}", fg=
|
|
208
|
+
click.echo(click.style(f" Could not enable: {e}", fg="yellow"))
|
|
162
209
|
click.echo()
|
|
163
210
|
else:
|
|
164
211
|
click.echo()
|
|
@@ -171,23 +218,49 @@ def run_tutorial():
|
|
|
171
218
|
clear_screen()
|
|
172
219
|
show_header("Step 4: Running Your First Recon")
|
|
173
220
|
|
|
174
|
-
click.echo(
|
|
175
|
-
|
|
176
|
-
|
|
221
|
+
click.echo(
|
|
222
|
+
"Now let's run "
|
|
223
|
+
+ click.style("passive reconnaissance", fg="cyan", bold=True)
|
|
224
|
+
+ "!"
|
|
225
|
+
)
|
|
226
|
+
click.echo()
|
|
227
|
+
click.echo(
|
|
228
|
+
"We'll use "
|
|
229
|
+
+ click.style("theHarvester", fg="green", bold=True)
|
|
230
|
+
+ " to search URLScan.io"
|
|
231
|
+
)
|
|
177
232
|
click.echo("for emails, subdomains, and IPs related to our target.")
|
|
178
233
|
click.echo()
|
|
179
|
-
click.echo(
|
|
180
|
-
|
|
181
|
-
|
|
234
|
+
click.echo(
|
|
235
|
+
"With "
|
|
236
|
+
+ click.style("auto-chaining ON", fg="yellow", bold=True)
|
|
237
|
+
+ ", when theHarvester finds hosts:"
|
|
238
|
+
)
|
|
239
|
+
click.echo(
|
|
240
|
+
" → "
|
|
241
|
+
+ click.style("whois", fg="cyan")
|
|
242
|
+
+ " and "
|
|
243
|
+
+ click.style("dnsrecon", fg="cyan")
|
|
244
|
+
+ " will auto-queue"
|
|
245
|
+
)
|
|
246
|
+
click.echo(
|
|
247
|
+
" → Found web servers trigger " + click.style("nmap", fg="cyan") + " scans"
|
|
248
|
+
)
|
|
182
249
|
click.echo(" → And so on... SoulEyez chains tools intelligently!")
|
|
183
250
|
click.echo()
|
|
184
251
|
|
|
185
252
|
target_domain = "vulnweb.com"
|
|
186
253
|
|
|
187
|
-
queue_scan = click.confirm(
|
|
254
|
+
queue_scan = click.confirm(
|
|
255
|
+
f"Queue theHarvester against {target_domain}?", default=True
|
|
256
|
+
)
|
|
188
257
|
if queue_scan:
|
|
189
258
|
click.echo()
|
|
190
|
-
click.echo(
|
|
259
|
+
click.echo(
|
|
260
|
+
click.style(
|
|
261
|
+
" ✓ Scan will start when you enter the Command Center!", fg="green"
|
|
262
|
+
)
|
|
263
|
+
)
|
|
191
264
|
click.echo()
|
|
192
265
|
else:
|
|
193
266
|
click.echo()
|
|
@@ -200,21 +273,41 @@ def run_tutorial():
|
|
|
200
273
|
clear_screen()
|
|
201
274
|
show_header("Step 5: Entering the Command Center")
|
|
202
275
|
|
|
203
|
-
click.echo(
|
|
276
|
+
click.echo(
|
|
277
|
+
"Now for the " + click.style("hands-on", fg="yellow", bold=True) + " part!"
|
|
278
|
+
)
|
|
204
279
|
click.echo()
|
|
205
|
-
click.echo(
|
|
280
|
+
click.echo(
|
|
281
|
+
"We're about to launch you into the "
|
|
282
|
+
+ click.style("Command Center", fg="cyan", bold=True)
|
|
283
|
+
+ " (dashboard)."
|
|
284
|
+
)
|
|
206
285
|
click.echo()
|
|
207
|
-
click.echo(
|
|
286
|
+
click.echo(
|
|
287
|
+
"The tutorial will continue there with "
|
|
288
|
+
+ click.style("interactive hints", fg="green")
|
|
289
|
+
+ ":"
|
|
290
|
+
)
|
|
208
291
|
click.echo()
|
|
209
292
|
click.echo(" • You'll see your queued scans running")
|
|
210
293
|
click.echo(" • Hints will guide you to explore different views")
|
|
211
294
|
click.echo(" • Press the highlighted keys to navigate")
|
|
212
295
|
click.echo()
|
|
213
296
|
click.echo(click.style("Quick reference for the Command Center:", bold=True))
|
|
214
|
-
click.echo(
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
click.echo(
|
|
297
|
+
click.echo(
|
|
298
|
+
" " + click.style("[j]", fg="yellow") + " Jobs queue - See running scans"
|
|
299
|
+
)
|
|
300
|
+
click.echo(
|
|
301
|
+
" "
|
|
302
|
+
+ click.style("[h]", fg="yellow")
|
|
303
|
+
+ " Hosts view - See discovered targets"
|
|
304
|
+
)
|
|
305
|
+
click.echo(
|
|
306
|
+
" " + click.style("[f]", fg="yellow") + " Findings - See vulnerabilities"
|
|
307
|
+
)
|
|
308
|
+
click.echo(
|
|
309
|
+
" " + click.style("[q]", fg="yellow") + " Quit - Exit dashboard"
|
|
310
|
+
)
|
|
218
311
|
click.echo()
|
|
219
312
|
|
|
220
313
|
if click.confirm("Ready to enter the Command Center?", default=True):
|
|
@@ -226,29 +319,35 @@ def run_tutorial():
|
|
|
226
319
|
if queue_scan:
|
|
227
320
|
try:
|
|
228
321
|
from souleyez.engine.background import enqueue_job
|
|
322
|
+
|
|
229
323
|
click.echo()
|
|
230
324
|
click.echo("Starting scan...")
|
|
231
325
|
job_id = enqueue_job(
|
|
232
|
-
tool=
|
|
326
|
+
tool="theharvester",
|
|
233
327
|
target=target_domain,
|
|
234
|
-
args=[
|
|
235
|
-
label=
|
|
236
|
-
engagement_id=engagement_id
|
|
328
|
+
args=["-b", "urlscan", "-l", "500"],
|
|
329
|
+
label="tutorial-recon",
|
|
330
|
+
engagement_id=engagement_id,
|
|
331
|
+
)
|
|
332
|
+
click.echo(
|
|
333
|
+
click.style(f" ✓ theHarvester queued (Job #{job_id})", fg="green")
|
|
237
334
|
)
|
|
238
|
-
click.echo(click.style(f" ✓ theHarvester queued (Job #{job_id})", fg='green'))
|
|
239
335
|
except Exception as e:
|
|
240
|
-
click.echo(
|
|
336
|
+
click.echo(
|
|
337
|
+
click.style(f" Note: Could not queue scan: {e}", fg="yellow")
|
|
338
|
+
)
|
|
241
339
|
|
|
242
340
|
click.echo()
|
|
243
|
-
click.echo(click.style("Launching Command Center...", fg=
|
|
341
|
+
click.echo(click.style("Launching Command Center...", fg="cyan"))
|
|
244
342
|
time.sleep(1)
|
|
245
343
|
|
|
246
344
|
# Launch the dashboard with tutorial mode active
|
|
247
345
|
try:
|
|
248
346
|
from souleyez.ui.dashboard import run_dashboard
|
|
347
|
+
|
|
249
348
|
run_dashboard()
|
|
250
349
|
except Exception as e:
|
|
251
|
-
click.echo(click.style(f"Could not launch dashboard: {e}", fg=
|
|
350
|
+
click.echo(click.style(f"Could not launch dashboard: {e}", fg="red"))
|
|
252
351
|
click.echo("You can launch it manually with: souleyez dashboard")
|
|
253
352
|
|
|
254
353
|
# After dashboard exits, show completion
|
|
@@ -256,7 +355,7 @@ def run_tutorial():
|
|
|
256
355
|
else:
|
|
257
356
|
click.echo()
|
|
258
357
|
click.echo("No problem! You can explore the Command Center anytime with:")
|
|
259
|
-
click.echo(click.style(" souleyez dashboard", fg=
|
|
358
|
+
click.echo(click.style(" souleyez dashboard", fg="cyan"))
|
|
260
359
|
click.echo()
|
|
261
360
|
_show_tutorial_complete()
|
|
262
361
|
|
|
@@ -270,7 +369,11 @@ def _show_tutorial_complete():
|
|
|
270
369
|
clear_screen()
|
|
271
370
|
show_header("Tutorial Complete!")
|
|
272
371
|
|
|
273
|
-
click.echo(
|
|
372
|
+
click.echo(
|
|
373
|
+
click.style(
|
|
374
|
+
"You're ready to start pentesting with SoulEyez!", fg="green", bold=True
|
|
375
|
+
)
|
|
376
|
+
)
|
|
274
377
|
click.echo()
|
|
275
378
|
click.echo("What you learned:")
|
|
276
379
|
click.echo(" ✓ Engagements organize your pentest data")
|
|
@@ -280,21 +383,38 @@ def _show_tutorial_complete():
|
|
|
280
383
|
click.echo()
|
|
281
384
|
click.echo(click.style("Quick reference:", bold=True))
|
|
282
385
|
click.echo()
|
|
283
|
-
click.echo(
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
386
|
+
click.echo(
|
|
387
|
+
" "
|
|
388
|
+
+ click.style("souleyez dashboard", fg="cyan")
|
|
389
|
+
+ " - Real-time Command Center"
|
|
390
|
+
)
|
|
391
|
+
click.echo(
|
|
392
|
+
" "
|
|
393
|
+
+ click.style("souleyez interactive", fg="cyan")
|
|
394
|
+
+ " - Menu-driven interface"
|
|
395
|
+
)
|
|
396
|
+
click.echo(
|
|
397
|
+
" "
|
|
398
|
+
+ click.style("souleyez setup", fg="cyan")
|
|
399
|
+
+ " - Install pentest tools"
|
|
400
|
+
)
|
|
401
|
+
click.echo(
|
|
402
|
+
" " + click.style("souleyez doctor", fg="cyan") + " - Diagnose issues"
|
|
403
|
+
)
|
|
287
404
|
click.echo()
|
|
288
405
|
click.echo(click.style("Practice targets (safe & legal):", bold=True))
|
|
289
406
|
click.echo(" • vulnweb.com subdomains (Acunetix)")
|
|
290
407
|
click.echo(" • demo.owasp-juice.shop (OWASP)")
|
|
291
408
|
click.echo()
|
|
292
|
-
click.echo(
|
|
409
|
+
click.echo(
|
|
410
|
+
click.style("⚠️ NEVER scan systems without permission!", fg="red", bold=True)
|
|
411
|
+
)
|
|
293
412
|
click.echo()
|
|
294
413
|
|
|
295
414
|
# Always disable auto-chaining (it's a PRO feature, tutorial enabled for demo)
|
|
296
415
|
try:
|
|
297
416
|
from souleyez.core.tool_chaining import ToolChaining
|
|
417
|
+
|
|
298
418
|
chaining = ToolChaining()
|
|
299
419
|
chaining.disable_chaining()
|
|
300
420
|
except Exception:
|
|
@@ -304,16 +424,27 @@ def _show_tutorial_complete():
|
|
|
304
424
|
click.echo()
|
|
305
425
|
if click.confirm("Clean up tutorial engagement and jobs?", default=True):
|
|
306
426
|
_cleanup_tutorial_data()
|
|
307
|
-
click.echo(click.style(" ✓ Tutorial data cleaned up!", fg=
|
|
427
|
+
click.echo(click.style(" ✓ Tutorial data cleaned up!", fg="green"))
|
|
308
428
|
else:
|
|
309
|
-
click.echo(
|
|
429
|
+
click.echo(
|
|
430
|
+
"Tutorial engagement kept. Check results with: "
|
|
431
|
+
+ click.style("souleyez interactive", fg="cyan")
|
|
432
|
+
)
|
|
310
433
|
|
|
311
434
|
click.echo()
|
|
312
435
|
click.echo("Need help?")
|
|
313
|
-
click.echo(
|
|
314
|
-
|
|
436
|
+
click.echo(
|
|
437
|
+
" • In-app: Press " + click.style("[?]", fg="yellow") + " for contextual help"
|
|
438
|
+
)
|
|
439
|
+
click.echo(
|
|
440
|
+
" • Full docs: "
|
|
441
|
+
+ click.style("souleyez interactive", fg="cyan")
|
|
442
|
+
+ " → Settings → "
|
|
443
|
+
+ click.style("[h]", fg="yellow")
|
|
444
|
+
+ " Help Center"
|
|
445
|
+
)
|
|
315
446
|
click.echo()
|
|
316
|
-
click.echo(click.style("Happy hacking! 🎯", fg=
|
|
447
|
+
click.echo(click.style("Happy hacking! 🎯", fg="cyan", bold=True))
|
|
317
448
|
click.echo()
|
|
318
449
|
|
|
319
450
|
wait_for_enter("Press Enter to exit tutorial...")
|
|
@@ -337,21 +468,20 @@ def _cleanup_tutorial_data():
|
|
|
337
468
|
|
|
338
469
|
# Find tutorial engagement
|
|
339
470
|
tutorial_eng = em.get("Tutorial Engagement")
|
|
340
|
-
engagement_id = tutorial_eng[
|
|
471
|
+
engagement_id = tutorial_eng["id"] if tutorial_eng else None
|
|
341
472
|
|
|
342
473
|
# Delete all tutorial jobs (by label OR by engagement_id)
|
|
343
474
|
all_jobs = list_jobs(limit=500)
|
|
344
475
|
for job in all_jobs:
|
|
345
|
-
is_tutorial_job = (
|
|
346
|
-
job.get(
|
|
347
|
-
(engagement_id and job.get('engagement_id') == engagement_id)
|
|
476
|
+
is_tutorial_job = job.get("label") == "tutorial-recon" or (
|
|
477
|
+
engagement_id and job.get("engagement_id") == engagement_id
|
|
348
478
|
)
|
|
349
479
|
if is_tutorial_job:
|
|
350
480
|
try:
|
|
351
481
|
# Kill if running, then delete
|
|
352
|
-
if job.get(
|
|
353
|
-
kill_job(job[
|
|
354
|
-
delete_job(job[
|
|
482
|
+
if job.get("status") in ("running", "queued"):
|
|
483
|
+
kill_job(job["id"])
|
|
484
|
+
delete_job(job["id"])
|
|
355
485
|
except Exception:
|
|
356
486
|
pass
|
|
357
487
|
|
|
@@ -359,15 +489,15 @@ def _cleanup_tutorial_data():
|
|
|
359
489
|
# (otherwise get_current() will fail trying to load deleted engagement)
|
|
360
490
|
if tutorial_eng:
|
|
361
491
|
current = em.get_current()
|
|
362
|
-
if current and current.get(
|
|
492
|
+
if current and current.get("id") == tutorial_eng["id"]:
|
|
363
493
|
em.set_current("default")
|
|
364
494
|
|
|
365
495
|
# Now safe to delete the tutorial engagement
|
|
366
496
|
em.delete("Tutorial Engagement")
|
|
367
497
|
|
|
368
498
|
except Exception as e:
|
|
369
|
-
click.echo(click.style(f" Note: Could not fully clean up: {e}", fg=
|
|
499
|
+
click.echo(click.style(f" Note: Could not fully clean up: {e}", fg="yellow"))
|
|
370
500
|
|
|
371
501
|
|
|
372
|
-
if __name__ ==
|
|
502
|
+
if __name__ == "__main__":
|
|
373
503
|
run_tutorial()
|
souleyez/ui/tutorial_state.py
CHANGED
|
@@ -13,22 +13,23 @@ import json
|
|
|
13
13
|
|
|
14
14
|
class TutorialStep(Enum):
|
|
15
15
|
"""Tutorial steps in order."""
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
|
|
17
|
+
INACTIVE = auto() # Tutorial not running
|
|
18
|
+
WELCOME = auto() # Welcome screen
|
|
19
|
+
ENGAGEMENT_EXPLAIN = auto() # Explaining engagements
|
|
19
20
|
ENGAGEMENT_CREATE = auto() # Creating first engagement
|
|
20
|
-
AUTOCHAIN_ENABLE = auto()
|
|
21
|
-
SCANS_QUEUE = auto()
|
|
22
|
-
DASHBOARD_INTRO = auto()
|
|
23
|
-
VIEW_JOBS = auto()
|
|
24
|
-
IN_JOB_QUEUE = auto()
|
|
25
|
-
VIEW_OSINT = auto()
|
|
26
|
-
IN_OSINT_VIEW = auto()
|
|
27
|
-
VIEW_HOSTS = auto()
|
|
28
|
-
IN_HOSTS_VIEW = auto()
|
|
29
|
-
VIEW_JOB_DETAILS = auto()
|
|
30
|
-
IN_JOB_DETAILS = auto()
|
|
31
|
-
COMPLETE = auto()
|
|
21
|
+
AUTOCHAIN_ENABLE = auto() # Enabling auto-chaining
|
|
22
|
+
SCANS_QUEUE = auto() # Queuing recon scans
|
|
23
|
+
DASHBOARD_INTRO = auto() # Entered dashboard for first time
|
|
24
|
+
VIEW_JOBS = auto() # Hint: press [j] for jobs
|
|
25
|
+
IN_JOB_QUEUE = auto() # User is in job queue
|
|
26
|
+
VIEW_OSINT = auto() # Hint: press [o] for OSINT
|
|
27
|
+
IN_OSINT_VIEW = auto() # User is viewing OSINT
|
|
28
|
+
VIEW_HOSTS = auto() # Hint: press [h] for hosts
|
|
29
|
+
IN_HOSTS_VIEW = auto() # User is viewing hosts
|
|
30
|
+
VIEW_JOB_DETAILS = auto() # Hint: press [j] again for job details
|
|
31
|
+
IN_JOB_DETAILS = auto() # User viewing job details (interactive mode)
|
|
32
|
+
COMPLETE = auto() # Tutorial complete
|
|
32
33
|
|
|
33
34
|
|
|
34
35
|
# Hints for each step when user is in the dashboard
|
|
@@ -36,27 +37,27 @@ DASHBOARD_HINTS: Dict[TutorialStep, Dict[str, str]] = {
|
|
|
36
37
|
TutorialStep.DASHBOARD_INTRO: {
|
|
37
38
|
"title": "Welcome to the Command Center!",
|
|
38
39
|
"hint": "This is your mission control - active jobs, stats, and recommendations.",
|
|
39
|
-
"action": "Press Enter to continue the tutorial..."
|
|
40
|
+
"action": "Press Enter to continue the tutorial...",
|
|
40
41
|
},
|
|
41
42
|
TutorialStep.VIEW_JOBS: {
|
|
42
43
|
"title": "Check Your Queued Scans",
|
|
43
44
|
"hint": "Your recon scans are now running! Let's check them out.",
|
|
44
|
-
"action": "Press [j] to open the Job Queue"
|
|
45
|
+
"action": "Press [j] to open the Job Queue",
|
|
45
46
|
},
|
|
46
47
|
TutorialStep.VIEW_OSINT: {
|
|
47
48
|
"title": "View OSINT Discoveries",
|
|
48
49
|
"hint": "Passive recon found domains, emails, IPs and more. Let's explore!",
|
|
49
|
-
"action": "Press [o] to open the OSINT view"
|
|
50
|
+
"action": "Press [o] to open the OSINT view",
|
|
50
51
|
},
|
|
51
52
|
TutorialStep.VIEW_HOSTS: {
|
|
52
53
|
"title": "View Discovered Hosts",
|
|
53
54
|
"hint": "As scans complete, hosts will appear here.",
|
|
54
|
-
"action": "Press [h] to open the Hosts view"
|
|
55
|
+
"action": "Press [h] to open the Hosts view",
|
|
55
56
|
},
|
|
56
57
|
TutorialStep.VIEW_JOB_DETAILS: {
|
|
57
58
|
"title": "View Job Details",
|
|
58
59
|
"hint": "Now let's learn to inspect individual scan results!",
|
|
59
|
-
"action": "Press [j] to go back to the Job Queue"
|
|
60
|
+
"action": "Press [j] to go back to the Job Queue",
|
|
60
61
|
},
|
|
61
62
|
}
|
|
62
63
|
|
|
@@ -65,15 +66,15 @@ JOB_QUEUE_HINTS: Dict[TutorialStep, Dict[str, str]] = {
|
|
|
65
66
|
TutorialStep.IN_JOB_QUEUE: {
|
|
66
67
|
"title": "This is the Job Queue",
|
|
67
68
|
"hint": "Here you can see all queued, running, and completed scans.\n"
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
"action": "Press [q] to go back, then try [o] for OSINT"
|
|
69
|
+
" • White = queued • Yellow = running • Green = completed • Red = failed\n"
|
|
70
|
+
" With auto-chaining ON, new jobs will auto-queue based on findings!",
|
|
71
|
+
"action": "Press [q] to go back, then try [o] for OSINT",
|
|
71
72
|
},
|
|
72
73
|
TutorialStep.IN_JOB_DETAILS: {
|
|
73
74
|
"title": "View Job Details",
|
|
74
75
|
"hint": "Type a job number to see its full output and results.\n"
|
|
75
|
-
|
|
76
|
-
"action": "Press [q] when done to complete the tutorial!"
|
|
76
|
+
" Or press [i] for interactive mode with more options.",
|
|
77
|
+
"action": "Press [q] when done to complete the tutorial!",
|
|
77
78
|
},
|
|
78
79
|
}
|
|
79
80
|
|
|
@@ -82,9 +83,9 @@ OSINT_HINTS: Dict[TutorialStep, Dict[str, str]] = {
|
|
|
82
83
|
TutorialStep.IN_OSINT_VIEW: {
|
|
83
84
|
"title": "This is the OSINT View",
|
|
84
85
|
"hint": "Passive recon discovered domains, emails, IPs and more.\n"
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
"action": "Press [q] to go back, then try [h] for Hosts"
|
|
86
|
+
" This data came from theHarvester, whois, and dnsrecon.\n"
|
|
87
|
+
" No packets were sent to the target - all public sources!",
|
|
88
|
+
"action": "Press [q] to go back, then try [h] for Hosts",
|
|
88
89
|
},
|
|
89
90
|
}
|
|
90
91
|
|
|
@@ -93,8 +94,8 @@ HOSTS_HINTS: Dict[TutorialStep, Dict[str, str]] = {
|
|
|
93
94
|
TutorialStep.IN_HOSTS_VIEW: {
|
|
94
95
|
"title": "This is the Hosts View",
|
|
95
96
|
"hint": "As your scans discover targets, they appear here.\n"
|
|
96
|
-
|
|
97
|
-
"action": "Press [q] to go back, then [j] for Job Details"
|
|
97
|
+
" Each host shows its IP, hostname, and discovered services.",
|
|
98
|
+
"action": "Press [q] to go back, then [j] for Job Details",
|
|
98
99
|
},
|
|
99
100
|
}
|
|
100
101
|
|
|
@@ -113,10 +114,10 @@ class TutorialState:
|
|
|
113
114
|
show_hint(hint)
|
|
114
115
|
"""
|
|
115
116
|
|
|
116
|
-
_instance: Optional[
|
|
117
|
-
STATE_FILE = Path.home() /
|
|
117
|
+
_instance: Optional["TutorialState"] = None
|
|
118
|
+
STATE_FILE = Path.home() / ".souleyez" / ".tutorial_state.json"
|
|
118
119
|
|
|
119
|
-
def __new__(cls) ->
|
|
120
|
+
def __new__(cls) -> "TutorialState":
|
|
120
121
|
if cls._instance is None:
|
|
121
122
|
cls._instance = super().__new__(cls)
|
|
122
123
|
cls._instance._initialized = False
|
|
@@ -136,20 +137,19 @@ class TutorialState:
|
|
|
136
137
|
try:
|
|
137
138
|
with open(self.STATE_FILE) as f:
|
|
138
139
|
data = json.load(f)
|
|
139
|
-
step_name = data.get(
|
|
140
|
+
step_name = data.get("step", "INACTIVE")
|
|
140
141
|
self.current_step = TutorialStep[step_name]
|
|
141
|
-
self.engagement_id = data.get(
|
|
142
|
+
self.engagement_id = data.get("engagement_id")
|
|
142
143
|
except (json.JSONDecodeError, KeyError, FileNotFoundError):
|
|
143
144
|
self.current_step = TutorialStep.INACTIVE
|
|
144
145
|
|
|
145
146
|
def _save_state(self):
|
|
146
147
|
"""Save tutorial state to file."""
|
|
147
148
|
self.STATE_FILE.parent.mkdir(parents=True, exist_ok=True)
|
|
148
|
-
with open(self.STATE_FILE,
|
|
149
|
-
json.dump(
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
}, f)
|
|
149
|
+
with open(self.STATE_FILE, "w") as f:
|
|
150
|
+
json.dump(
|
|
151
|
+
{"step": self.current_step.name, "engagement_id": self.engagement_id}, f
|
|
152
|
+
)
|
|
153
153
|
|
|
154
154
|
def start(self, engagement_id: Optional[int] = None):
|
|
155
155
|
"""Start the tutorial."""
|