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.
- 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 +9526 -2879
- 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 +563 -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 +408 -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 +371 -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 +854 -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 +173 -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 +223 -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 +22827 -10678
- 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-2.43.34.dist-info}/METADATA +1 -1
- souleyez-2.43.34.dist-info/RECORD +443 -0
- {souleyez-2.43.29.dist-info → souleyez-2.43.34.dist-info}/WHEEL +1 -1
- souleyez-2.43.29.dist-info/RECORD +0 -379
- {souleyez-2.43.29.dist-info → souleyez-2.43.34.dist-info}/entry_points.txt +0 -0
- {souleyez-2.43.29.dist-info → souleyez-2.43.34.dist-info}/licenses/LICENSE +0 -0
- {souleyez-2.43.29.dist-info → souleyez-2.43.34.dist-info}/top_level.txt +0 -0
souleyez/storage/engagements.py
CHANGED
|
@@ -13,7 +13,9 @@ class EngagementManager:
|
|
|
13
13
|
def __init__(self):
|
|
14
14
|
self.db = get_db()
|
|
15
15
|
|
|
16
|
-
def create(
|
|
16
|
+
def create(
|
|
17
|
+
self, name: str, description: str = "", engagement_type: str = "custom"
|
|
18
|
+
) -> int:
|
|
17
19
|
"""Create new engagement with current user as owner."""
|
|
18
20
|
# Check if engagement already exists
|
|
19
21
|
existing = self.get(name)
|
|
@@ -22,48 +24,57 @@ class EngagementManager:
|
|
|
22
24
|
|
|
23
25
|
# Get current user as owner
|
|
24
26
|
from souleyez.auth import get_current_user
|
|
27
|
+
|
|
25
28
|
user = get_current_user()
|
|
26
29
|
owner_id = user.id if user else None
|
|
27
30
|
|
|
28
|
-
eng_id = self.db.insert(
|
|
29
|
-
"
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
eng_id = self.db.insert(
|
|
32
|
+
"engagements",
|
|
33
|
+
{
|
|
34
|
+
"name": name,
|
|
35
|
+
"description": description,
|
|
36
|
+
"engagement_type": engagement_type,
|
|
37
|
+
"owner_id": owner_id,
|
|
38
|
+
},
|
|
39
|
+
)
|
|
34
40
|
|
|
35
41
|
# Audit log
|
|
36
42
|
from souleyez.auth.audit import audit_log, AuditAction
|
|
43
|
+
|
|
37
44
|
audit_log(
|
|
38
45
|
AuditAction.ENGAGEMENT_CREATED,
|
|
39
46
|
resource_type="engagement",
|
|
40
47
|
resource_id=eng_id,
|
|
41
|
-
details={"name": name, "type": engagement_type}
|
|
48
|
+
details={"name": name, "type": engagement_type},
|
|
42
49
|
)
|
|
43
50
|
|
|
44
51
|
return eng_id
|
|
45
52
|
|
|
46
|
-
def create_engagement(
|
|
53
|
+
def create_engagement(
|
|
54
|
+
self, name: str, description: str = "", engagement_type: str = "custom"
|
|
55
|
+
) -> int:
|
|
47
56
|
"""Alias for create() for compatibility."""
|
|
48
57
|
return self.create(name, description, engagement_type)
|
|
49
58
|
|
|
50
59
|
def list(self, user_filtered: bool = True) -> List[Dict[str, Any]]:
|
|
51
60
|
"""
|
|
52
61
|
List engagements.
|
|
53
|
-
|
|
62
|
+
|
|
54
63
|
Args:
|
|
55
64
|
user_filtered: If True, only show engagements user has access to.
|
|
56
65
|
If False, show all (for admin operations).
|
|
57
66
|
"""
|
|
58
67
|
if not user_filtered:
|
|
59
68
|
return self.db.execute("SELECT * FROM engagements ORDER BY created_at DESC")
|
|
60
|
-
|
|
69
|
+
|
|
61
70
|
from souleyez.auth import get_current_user
|
|
71
|
+
|
|
62
72
|
user = get_current_user()
|
|
63
73
|
if not user:
|
|
64
74
|
return []
|
|
65
|
-
|
|
75
|
+
|
|
66
76
|
from souleyez.auth.engagement_access import EngagementAccessManager
|
|
77
|
+
|
|
67
78
|
access_mgr = EngagementAccessManager(self.db.db_path)
|
|
68
79
|
return access_mgr.get_accessible_engagements(user.id, user.role)
|
|
69
80
|
|
|
@@ -77,7 +88,9 @@ class EngagementManager:
|
|
|
77
88
|
|
|
78
89
|
def get_by_id(self, engagement_id: int) -> Optional[Dict[str, Any]]:
|
|
79
90
|
"""Get engagement by ID."""
|
|
80
|
-
return self.db.execute_one(
|
|
91
|
+
return self.db.execute_one(
|
|
92
|
+
"SELECT * FROM engagements WHERE id = ?", (engagement_id,)
|
|
93
|
+
)
|
|
81
94
|
|
|
82
95
|
def update(self, engagement_id: int, fields: Dict[str, Any]) -> bool:
|
|
83
96
|
"""Update engagement fields."""
|
|
@@ -93,7 +106,7 @@ class EngagementManager:
|
|
|
93
106
|
|
|
94
107
|
self.db.execute(
|
|
95
108
|
f"UPDATE engagements SET {set_clauses}, updated_at = CURRENT_TIMESTAMP WHERE id = ?",
|
|
96
|
-
tuple(values)
|
|
109
|
+
tuple(values),
|
|
97
110
|
)
|
|
98
111
|
return True
|
|
99
112
|
|
|
@@ -104,7 +117,7 @@ class EngagementManager:
|
|
|
104
117
|
return False
|
|
105
118
|
|
|
106
119
|
ENGAGEMENT_FILE.parent.mkdir(parents=True, exist_ok=True)
|
|
107
|
-
ENGAGEMENT_FILE.write_text(str(eng[
|
|
120
|
+
ENGAGEMENT_FILE.write_text(str(eng["id"]))
|
|
108
121
|
return True
|
|
109
122
|
|
|
110
123
|
def get_current(self) -> Optional[Dict[str, Any]]:
|
|
@@ -128,7 +141,7 @@ class EngagementManager:
|
|
|
128
141
|
# Reset to default engagement - use existing or create new
|
|
129
142
|
default_eng = self.get("default")
|
|
130
143
|
if default_eng:
|
|
131
|
-
default_id = default_eng[
|
|
144
|
+
default_id = default_eng["id"]
|
|
132
145
|
else:
|
|
133
146
|
default_id = self.create("default", "Default engagement")
|
|
134
147
|
self.set_current("default")
|
|
@@ -141,24 +154,32 @@ class EngagementManager:
|
|
|
141
154
|
return False
|
|
142
155
|
|
|
143
156
|
# Delete associated data in correct order (respecting foreign keys)
|
|
144
|
-
|
|
157
|
+
|
|
145
158
|
# 1. Delete execution log entries for this engagement
|
|
146
|
-
self.db.execute(
|
|
147
|
-
|
|
159
|
+
self.db.execute(
|
|
160
|
+
"DELETE FROM execution_log WHERE engagement_id = ?", (eng["id"],)
|
|
161
|
+
)
|
|
162
|
+
|
|
148
163
|
# 2. Delete SQLi data (CASCADE chain: databases → tables → columns & dumped_data)
|
|
149
|
-
self.db.execute(
|
|
164
|
+
self.db.execute(
|
|
165
|
+
"""
|
|
150
166
|
DELETE FROM sqli_databases
|
|
151
167
|
WHERE engagement_id = ?
|
|
152
|
-
""",
|
|
153
|
-
|
|
168
|
+
""",
|
|
169
|
+
(eng["id"],),
|
|
170
|
+
)
|
|
171
|
+
|
|
154
172
|
# 3. Delete screenshots (references engagement, host, finding)
|
|
155
|
-
self.db.execute("DELETE FROM screenshots WHERE engagement_id = ?", (eng[
|
|
156
|
-
|
|
173
|
+
self.db.execute("DELETE FROM screenshots WHERE engagement_id = ?", (eng["id"],))
|
|
174
|
+
|
|
157
175
|
# 4. Delete deliverables (references engagement_id)
|
|
158
|
-
self.db.execute(
|
|
159
|
-
|
|
176
|
+
self.db.execute(
|
|
177
|
+
"DELETE FROM deliverables WHERE engagement_id = ?", (eng["id"],)
|
|
178
|
+
)
|
|
179
|
+
|
|
160
180
|
# 5. Delete SMB files (references smb_shares)
|
|
161
|
-
self.db.execute(
|
|
181
|
+
self.db.execute(
|
|
182
|
+
"""
|
|
162
183
|
DELETE FROM smb_files
|
|
163
184
|
WHERE share_id IN (
|
|
164
185
|
SELECT id FROM smb_shares
|
|
@@ -166,54 +187,77 @@ class EngagementManager:
|
|
|
166
187
|
SELECT id FROM hosts WHERE engagement_id = ?
|
|
167
188
|
)
|
|
168
189
|
)
|
|
169
|
-
""",
|
|
170
|
-
|
|
190
|
+
""",
|
|
191
|
+
(eng["id"],),
|
|
192
|
+
)
|
|
193
|
+
|
|
171
194
|
# 6. Delete SMB shares (references hosts)
|
|
172
|
-
self.db.execute(
|
|
195
|
+
self.db.execute(
|
|
196
|
+
"""
|
|
173
197
|
DELETE FROM smb_shares
|
|
174
198
|
WHERE host_id IN (SELECT id FROM hosts WHERE engagement_id = ?)
|
|
175
|
-
""",
|
|
176
|
-
|
|
199
|
+
""",
|
|
200
|
+
(eng["id"],),
|
|
201
|
+
)
|
|
202
|
+
|
|
177
203
|
# 7. Delete web paths (references hosts)
|
|
178
|
-
self.db.execute(
|
|
204
|
+
self.db.execute(
|
|
205
|
+
"""
|
|
179
206
|
DELETE FROM web_paths
|
|
180
207
|
WHERE host_id IN (SELECT id FROM hosts WHERE engagement_id = ?)
|
|
181
|
-
""",
|
|
182
|
-
|
|
208
|
+
""",
|
|
209
|
+
(eng["id"],),
|
|
210
|
+
)
|
|
211
|
+
|
|
183
212
|
# 8. Delete credentials (references hosts)
|
|
184
|
-
self.db.execute(
|
|
213
|
+
self.db.execute(
|
|
214
|
+
"""
|
|
185
215
|
DELETE FROM credentials
|
|
186
216
|
WHERE host_id IN (SELECT id FROM hosts WHERE engagement_id = ?)
|
|
187
217
|
OR engagement_id = ?
|
|
188
|
-
""",
|
|
189
|
-
|
|
218
|
+
""",
|
|
219
|
+
(eng["id"], eng["id"]),
|
|
220
|
+
)
|
|
221
|
+
|
|
190
222
|
# 9. Delete findings (references engagement_id)
|
|
191
|
-
self.db.execute("DELETE FROM findings WHERE engagement_id = ?", (eng[
|
|
192
|
-
|
|
223
|
+
self.db.execute("DELETE FROM findings WHERE engagement_id = ?", (eng["id"],))
|
|
224
|
+
|
|
193
225
|
# 10. Delete OSINT data (references engagement_id)
|
|
194
|
-
self.db.execute("DELETE FROM osint_data WHERE engagement_id = ?", (eng[
|
|
195
|
-
|
|
226
|
+
self.db.execute("DELETE FROM osint_data WHERE engagement_id = ?", (eng["id"],))
|
|
227
|
+
|
|
196
228
|
# 11. Delete services (references hosts)
|
|
197
|
-
self.db.execute(
|
|
229
|
+
self.db.execute(
|
|
230
|
+
"""
|
|
198
231
|
DELETE FROM services
|
|
199
232
|
WHERE host_id IN (SELECT id FROM hosts WHERE engagement_id = ?)
|
|
200
|
-
""",
|
|
201
|
-
|
|
233
|
+
""",
|
|
234
|
+
(eng["id"],),
|
|
235
|
+
)
|
|
236
|
+
|
|
202
237
|
# 12. Delete hosts (now all foreign key references are gone)
|
|
203
|
-
self.db.execute("DELETE FROM hosts WHERE engagement_id = ?", (eng[
|
|
204
|
-
|
|
238
|
+
self.db.execute("DELETE FROM hosts WHERE engagement_id = ?", (eng["id"],))
|
|
239
|
+
|
|
205
240
|
# 13. Finally delete the engagement itself
|
|
206
|
-
self.db.execute("DELETE FROM engagements WHERE id = ?", (eng[
|
|
241
|
+
self.db.execute("DELETE FROM engagements WHERE id = ?", (eng["id"],))
|
|
207
242
|
|
|
208
243
|
# Audit log
|
|
209
244
|
from souleyez.auth.audit import audit_log, AuditAction
|
|
245
|
+
|
|
210
246
|
audit_log(
|
|
211
247
|
AuditAction.ENGAGEMENT_DELETED,
|
|
212
248
|
resource_type="engagement",
|
|
213
|
-
resource_id=eng[
|
|
214
|
-
details={"name": name}
|
|
249
|
+
resource_id=eng["id"],
|
|
250
|
+
details={"name": name},
|
|
215
251
|
)
|
|
216
252
|
|
|
253
|
+
# Clean up orphaned pending chains for deleted engagement
|
|
254
|
+
try:
|
|
255
|
+
from souleyez.core.pending_chains import purge_orphaned_chains
|
|
256
|
+
|
|
257
|
+
purge_orphaned_chains()
|
|
258
|
+
except Exception:
|
|
259
|
+
pass # Non-critical cleanup
|
|
260
|
+
|
|
217
261
|
return True
|
|
218
262
|
|
|
219
263
|
def stats(self, engagement_id: int) -> Dict[str, int]:
|
|
@@ -221,19 +265,22 @@ class EngagementManager:
|
|
|
221
265
|
# Only count live hosts (status='up')
|
|
222
266
|
hosts = self.db.execute_one(
|
|
223
267
|
"SELECT COUNT(*) as count FROM hosts WHERE engagement_id = ? AND status = 'up'",
|
|
224
|
-
(engagement_id,)
|
|
268
|
+
(engagement_id,),
|
|
225
269
|
)
|
|
226
270
|
# Only count services on live hosts
|
|
227
271
|
services = self.db.execute_one(
|
|
228
272
|
"SELECT COUNT(*) as count FROM services WHERE host_id IN (SELECT id FROM hosts WHERE engagement_id = ? AND status = 'up')",
|
|
229
|
-
(engagement_id,)
|
|
273
|
+
(engagement_id,),
|
|
274
|
+
)
|
|
275
|
+
findings = self.db.execute_one(
|
|
276
|
+
"SELECT COUNT(*) as count FROM findings WHERE engagement_id = ?",
|
|
277
|
+
(engagement_id,),
|
|
230
278
|
)
|
|
231
|
-
findings = self.db.execute_one("SELECT COUNT(*) as count FROM findings WHERE engagement_id = ?", (engagement_id,))
|
|
232
279
|
|
|
233
280
|
return {
|
|
234
|
-
"hosts": hosts[
|
|
235
|
-
"services": services[
|
|
236
|
-
"findings": findings[
|
|
281
|
+
"hosts": hosts["count"] if hosts else 0,
|
|
282
|
+
"services": services["count"] if services else 0,
|
|
283
|
+
"findings": findings["count"] if findings else 0,
|
|
237
284
|
}
|
|
238
285
|
|
|
239
286
|
# =========================================================================
|
|
@@ -243,32 +290,38 @@ class EngagementManager:
|
|
|
243
290
|
def can_access(self, engagement_id: int) -> bool:
|
|
244
291
|
"""Check if current user can access this engagement."""
|
|
245
292
|
from souleyez.auth import get_current_user
|
|
293
|
+
|
|
246
294
|
user = get_current_user()
|
|
247
295
|
if not user:
|
|
248
296
|
return False
|
|
249
297
|
|
|
250
298
|
from souleyez.auth.engagement_access import EngagementAccessManager
|
|
299
|
+
|
|
251
300
|
access_mgr = EngagementAccessManager(self.db.db_path)
|
|
252
301
|
return access_mgr.can_access(engagement_id, user.id, user.role)
|
|
253
302
|
|
|
254
303
|
def can_edit(self, engagement_id: int) -> bool:
|
|
255
304
|
"""Check if current user can edit this engagement."""
|
|
256
305
|
from souleyez.auth import get_current_user
|
|
306
|
+
|
|
257
307
|
user = get_current_user()
|
|
258
308
|
if not user:
|
|
259
309
|
return False
|
|
260
310
|
|
|
261
311
|
from souleyez.auth.engagement_access import EngagementAccessManager
|
|
312
|
+
|
|
262
313
|
access_mgr = EngagementAccessManager(self.db.db_path)
|
|
263
314
|
return access_mgr.can_edit(engagement_id, user.id, user.role)
|
|
264
315
|
|
|
265
316
|
def can_delete_engagement(self, engagement_id: int) -> bool:
|
|
266
317
|
"""Check if current user can delete this engagement."""
|
|
267
318
|
from souleyez.auth import get_current_user
|
|
319
|
+
|
|
268
320
|
user = get_current_user()
|
|
269
321
|
if not user:
|
|
270
322
|
return False
|
|
271
323
|
|
|
272
324
|
from souleyez.auth.engagement_access import EngagementAccessManager
|
|
325
|
+
|
|
273
326
|
access_mgr = EngagementAccessManager(self.db.db_path)
|
|
274
327
|
return access_mgr.can_delete(engagement_id, user.id, user.role)
|