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
|
@@ -10,73 +10,73 @@ from urllib.parse import urlparse
|
|
|
10
10
|
|
|
11
11
|
class TargetParser:
|
|
12
12
|
"""Parse job targets to extract host and port information."""
|
|
13
|
-
|
|
13
|
+
|
|
14
14
|
# Common service-to-port mappings
|
|
15
15
|
SERVICE_PORTS = {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
16
|
+
"ftp": 21,
|
|
17
|
+
"ssh": 22,
|
|
18
|
+
"telnet": 23,
|
|
19
|
+
"smtp": 25,
|
|
20
|
+
"dns": 53,
|
|
21
|
+
"http": 80,
|
|
22
|
+
"pop3": 110,
|
|
23
|
+
"imap": 143,
|
|
24
|
+
"snmp": 161,
|
|
25
|
+
"ldap": 389,
|
|
26
|
+
"https": 443,
|
|
27
|
+
"smb": 445,
|
|
28
|
+
"smbold": 139,
|
|
29
|
+
"mssql": 1433,
|
|
30
|
+
"mysql": 3306,
|
|
31
|
+
"rdp": 3389,
|
|
32
|
+
"postgres": 5432,
|
|
33
|
+
"postgresql": 5432,
|
|
34
|
+
"vnc": 5900,
|
|
35
|
+
"redis": 6379,
|
|
36
|
+
"mongodb": 27017,
|
|
37
37
|
}
|
|
38
|
-
|
|
38
|
+
|
|
39
39
|
# Reverse mapping: port to service
|
|
40
40
|
PORT_SERVICES = {v: k for k, v in SERVICE_PORTS.items()}
|
|
41
41
|
# Handle duplicates manually
|
|
42
|
-
PORT_SERVICES[139] =
|
|
43
|
-
PORT_SERVICES[445] =
|
|
42
|
+
PORT_SERVICES[139] = "smb"
|
|
43
|
+
PORT_SERVICES[445] = "smb"
|
|
44
44
|
|
|
45
45
|
# Add common non-standard web ports for vulnerable web apps
|
|
46
|
-
PORT_SERVICES[3000] =
|
|
47
|
-
PORT_SERVICES[8080] =
|
|
48
|
-
PORT_SERVICES[8000] =
|
|
49
|
-
PORT_SERVICES[8888] =
|
|
50
|
-
PORT_SERVICES[9090] =
|
|
51
|
-
|
|
46
|
+
PORT_SERVICES[3000] = "http" # Node.js/Express default, OWASP Juice Shop
|
|
47
|
+
PORT_SERVICES[8080] = "http" # Tomcat/alternative HTTP
|
|
48
|
+
PORT_SERVICES[8000] = "http" # Django/Python dev servers
|
|
49
|
+
PORT_SERVICES[8888] = "http" # Jupyter/alternative web servers
|
|
50
|
+
PORT_SERVICES[9090] = "http" # Cockpit/monitoring interfaces
|
|
51
|
+
|
|
52
52
|
# MSF module patterns
|
|
53
53
|
MSF_PATTERNS = {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
54
|
+
"ftp": 21,
|
|
55
|
+
"ssh": 22,
|
|
56
|
+
"telnet": 23,
|
|
57
|
+
"smtp": 25,
|
|
58
|
+
"http": 80,
|
|
59
|
+
"pop3": 110,
|
|
60
|
+
"imap": 143,
|
|
61
|
+
"snmp": 161,
|
|
62
|
+
"smb": 445,
|
|
63
|
+
"mssql": 1433,
|
|
64
|
+
"mysql": 3306,
|
|
65
|
+
"rdp": 3389,
|
|
66
|
+
"postgres": 5432,
|
|
67
|
+
"vnc": 5900,
|
|
68
|
+
"redis": 6379,
|
|
69
69
|
}
|
|
70
|
-
|
|
70
|
+
|
|
71
71
|
def parse_target(self, tool: str, target: str, args: Optional[List] = None) -> Dict:
|
|
72
72
|
"""
|
|
73
73
|
Parse job target to extract host and port.
|
|
74
|
-
|
|
74
|
+
|
|
75
75
|
Args:
|
|
76
76
|
tool: Tool name (nmap, nuclei, hydra, etc.)
|
|
77
77
|
target: Target string (IP, URL, domain, etc.)
|
|
78
78
|
args: Additional arguments (list or dict)
|
|
79
|
-
|
|
79
|
+
|
|
80
80
|
Returns:
|
|
81
81
|
{
|
|
82
82
|
'host': str,
|
|
@@ -85,270 +85,267 @@ class TargetParser:
|
|
|
85
85
|
'service': str (optional),
|
|
86
86
|
'protocol': str (optional)
|
|
87
87
|
}
|
|
88
|
-
|
|
88
|
+
|
|
89
89
|
Examples:
|
|
90
90
|
parse_target('nmap', '10.0.0.5', ['-p', '22,80'])
|
|
91
91
|
→ {'host': '10.0.0.5', 'ports': [22, 80]}
|
|
92
|
-
|
|
92
|
+
|
|
93
93
|
parse_target('nuclei', 'http://10.0.0.5:443')
|
|
94
94
|
→ {'host': '10.0.0.5', 'port': 443, 'protocol': 'https'}
|
|
95
|
-
|
|
95
|
+
|
|
96
96
|
parse_target('hydra', '10.0.0.5', ['ssh'])
|
|
97
97
|
→ {'host': '10.0.0.5', 'port': 22, 'service': 'ssh'}
|
|
98
98
|
"""
|
|
99
99
|
result = {}
|
|
100
|
-
|
|
100
|
+
|
|
101
101
|
# Check if target is a URL
|
|
102
|
-
if target.startswith((
|
|
102
|
+
if target.startswith(("http://", "https://", "ftp://", "ftps://")):
|
|
103
103
|
url_info = self.extract_from_url(target)
|
|
104
104
|
result.update(url_info)
|
|
105
105
|
return result
|
|
106
|
-
|
|
106
|
+
|
|
107
107
|
# Extract host and port from various formats
|
|
108
108
|
host, port = self._extract_host_port(target)
|
|
109
|
-
result[
|
|
110
|
-
|
|
109
|
+
result["host"] = host
|
|
110
|
+
|
|
111
111
|
if port:
|
|
112
|
-
result[
|
|
113
|
-
|
|
112
|
+
result["port"] = port
|
|
113
|
+
|
|
114
114
|
# Tool-specific parsing
|
|
115
|
-
if tool ==
|
|
115
|
+
if tool == "nmap":
|
|
116
116
|
result.update(self._parse_nmap_args(args))
|
|
117
|
-
elif tool in [
|
|
117
|
+
elif tool in ["nuclei", "gobuster", "wpscan"]:
|
|
118
118
|
result.update(self._parse_web_tool_target(target))
|
|
119
|
-
elif tool ==
|
|
119
|
+
elif tool == "hydra":
|
|
120
120
|
result.update(self._parse_hydra_args(target, args))
|
|
121
|
-
elif tool ==
|
|
121
|
+
elif tool == "msf_auxiliary":
|
|
122
122
|
result.update(self._parse_msf_args(args))
|
|
123
|
-
elif tool ==
|
|
124
|
-
result[
|
|
125
|
-
result[
|
|
126
|
-
elif tool ==
|
|
127
|
-
result[
|
|
128
|
-
result[
|
|
129
|
-
elif tool ==
|
|
123
|
+
elif tool == "enum4linux":
|
|
124
|
+
result["port"] = 445
|
|
125
|
+
result["service"] = "smb"
|
|
126
|
+
elif tool == "smbmap":
|
|
127
|
+
result["port"] = 445
|
|
128
|
+
result["service"] = "smb"
|
|
129
|
+
elif tool == "sqlmap":
|
|
130
130
|
result.update(self._parse_sqlmap_target(target))
|
|
131
|
-
elif tool ==
|
|
131
|
+
elif tool == "whois":
|
|
132
132
|
# Whois is domain-level, no port
|
|
133
133
|
pass
|
|
134
|
-
elif tool ==
|
|
135
|
-
result[
|
|
136
|
-
result[
|
|
137
|
-
elif tool ==
|
|
134
|
+
elif tool == "dnsrecon":
|
|
135
|
+
result["port"] = 53
|
|
136
|
+
result["service"] = "dns"
|
|
137
|
+
elif tool == "theharvester":
|
|
138
138
|
# OSINT, no specific port
|
|
139
139
|
pass
|
|
140
|
-
|
|
140
|
+
|
|
141
141
|
# If we have a port but no service, infer service
|
|
142
|
-
if result.get(
|
|
143
|
-
result[
|
|
144
|
-
|
|
142
|
+
if result.get("port") and not result.get("service"):
|
|
143
|
+
result["service"] = self.infer_service_from_port(result["port"])
|
|
144
|
+
|
|
145
145
|
# If we have a service but no port, infer port
|
|
146
|
-
if result.get(
|
|
147
|
-
result[
|
|
148
|
-
|
|
146
|
+
if result.get("service") and not result.get("port"):
|
|
147
|
+
result["port"] = self.infer_port_from_service(result["service"])
|
|
148
|
+
|
|
149
149
|
return result
|
|
150
|
-
|
|
150
|
+
|
|
151
151
|
def _extract_host_port(self, target: str) -> tuple:
|
|
152
152
|
"""
|
|
153
153
|
Extract host and port from target string.
|
|
154
|
-
|
|
154
|
+
|
|
155
155
|
Handles:
|
|
156
156
|
- 10.0.0.5
|
|
157
157
|
- 10.0.0.5:3306
|
|
158
158
|
- example.com
|
|
159
159
|
- example.com:8080
|
|
160
|
-
|
|
160
|
+
|
|
161
161
|
Returns:
|
|
162
162
|
(host, port) tuple
|
|
163
163
|
"""
|
|
164
164
|
# Check for IP:port or domain:port
|
|
165
|
-
match = re.match(r
|
|
165
|
+
match = re.match(r"^([a-zA-Z0-9\.\-]+):(\d+)$", target)
|
|
166
166
|
if match:
|
|
167
167
|
return match.group(1), int(match.group(2))
|
|
168
|
-
|
|
168
|
+
|
|
169
169
|
# Just host
|
|
170
170
|
return target, None
|
|
171
|
-
|
|
171
|
+
|
|
172
172
|
def extract_from_url(self, url: str) -> Dict:
|
|
173
173
|
"""
|
|
174
174
|
Parse URL to extract host, port, protocol.
|
|
175
|
-
|
|
175
|
+
|
|
176
176
|
Examples:
|
|
177
177
|
'http://10.0.0.5' → {'host': '10.0.0.5', 'port': 80, 'protocol': 'http'}
|
|
178
178
|
'https://10.0.0.5:8443' → {'host': '10.0.0.5', 'port': 8443, 'protocol': 'https'}
|
|
179
179
|
'ftp://10.0.0.5:21' → {'host': '10.0.0.5', 'port': 21, 'protocol': 'ftp'}
|
|
180
180
|
"""
|
|
181
181
|
parsed = urlparse(url)
|
|
182
|
-
|
|
183
|
-
result = {
|
|
184
|
-
|
|
185
|
-
'protocol': parsed.scheme
|
|
186
|
-
}
|
|
187
|
-
|
|
182
|
+
|
|
183
|
+
result = {"host": parsed.hostname or parsed.netloc, "protocol": parsed.scheme}
|
|
184
|
+
|
|
188
185
|
# Determine port
|
|
189
186
|
if parsed.port:
|
|
190
|
-
result[
|
|
187
|
+
result["port"] = parsed.port
|
|
191
188
|
else:
|
|
192
189
|
# Use default port for protocol
|
|
193
|
-
if parsed.scheme ==
|
|
194
|
-
result[
|
|
195
|
-
elif parsed.scheme ==
|
|
196
|
-
result[
|
|
197
|
-
elif parsed.scheme ==
|
|
198
|
-
result[
|
|
199
|
-
elif parsed.scheme ==
|
|
200
|
-
result[
|
|
201
|
-
|
|
190
|
+
if parsed.scheme == "http":
|
|
191
|
+
result["port"] = 80
|
|
192
|
+
elif parsed.scheme == "https":
|
|
193
|
+
result["port"] = 443
|
|
194
|
+
elif parsed.scheme == "ftp":
|
|
195
|
+
result["port"] = 21
|
|
196
|
+
elif parsed.scheme == "ftps":
|
|
197
|
+
result["port"] = 990
|
|
198
|
+
|
|
202
199
|
# Infer service from protocol
|
|
203
|
-
if parsed.scheme in [
|
|
204
|
-
result[
|
|
205
|
-
elif parsed.scheme in [
|
|
206
|
-
result[
|
|
207
|
-
|
|
200
|
+
if parsed.scheme in ["http", "https"]:
|
|
201
|
+
result["service"] = "http"
|
|
202
|
+
elif parsed.scheme in ["ftp", "ftps"]:
|
|
203
|
+
result["service"] = "ftp"
|
|
204
|
+
|
|
208
205
|
return result
|
|
209
|
-
|
|
206
|
+
|
|
210
207
|
def _parse_nmap_args(self, args: Optional[List]) -> Dict:
|
|
211
208
|
"""
|
|
212
209
|
Parse Nmap arguments to extract port info.
|
|
213
|
-
|
|
210
|
+
|
|
214
211
|
Examples:
|
|
215
212
|
['-p', '22,80,443'] → {'ports': [22, 80, 443]}
|
|
216
213
|
['-p', '1-1000'] → {'ports': range(1, 1001)}
|
|
217
214
|
['-sV', '-p-'] → {} # Full port scan
|
|
218
215
|
"""
|
|
219
216
|
result = {}
|
|
220
|
-
|
|
217
|
+
|
|
221
218
|
if not args:
|
|
222
219
|
return result
|
|
223
|
-
|
|
220
|
+
|
|
224
221
|
# Look for -p flag
|
|
225
222
|
try:
|
|
226
|
-
p_idx = args.index(
|
|
223
|
+
p_idx = args.index("-p")
|
|
227
224
|
if p_idx + 1 < len(args):
|
|
228
225
|
port_spec = args[p_idx + 1]
|
|
229
|
-
|
|
226
|
+
|
|
230
227
|
# Handle full port scan
|
|
231
|
-
if port_spec ==
|
|
228
|
+
if port_spec == "-":
|
|
232
229
|
return result
|
|
233
|
-
|
|
230
|
+
|
|
234
231
|
# Handle comma-separated ports
|
|
235
|
-
if
|
|
232
|
+
if "," in port_spec:
|
|
236
233
|
ports = []
|
|
237
|
-
for p in port_spec.split(
|
|
238
|
-
if
|
|
234
|
+
for p in port_spec.split(","):
|
|
235
|
+
if "-" in p:
|
|
239
236
|
# Range like 20-25
|
|
240
|
-
start, end = map(int, p.split(
|
|
237
|
+
start, end = map(int, p.split("-"))
|
|
241
238
|
ports.extend(range(start, end + 1))
|
|
242
239
|
else:
|
|
243
240
|
ports.append(int(p))
|
|
244
|
-
result[
|
|
245
|
-
|
|
241
|
+
result["ports"] = ports
|
|
242
|
+
|
|
246
243
|
# Handle port range
|
|
247
|
-
elif
|
|
248
|
-
start, end = map(int, port_spec.split(
|
|
249
|
-
result[
|
|
250
|
-
|
|
244
|
+
elif "-" in port_spec:
|
|
245
|
+
start, end = map(int, port_spec.split("-"))
|
|
246
|
+
result["ports"] = list(range(start, end + 1))
|
|
247
|
+
|
|
251
248
|
# Single port
|
|
252
249
|
else:
|
|
253
|
-
result[
|
|
254
|
-
|
|
250
|
+
result["ports"] = [int(port_spec)]
|
|
251
|
+
|
|
255
252
|
except (ValueError, IndexError):
|
|
256
253
|
pass
|
|
257
|
-
|
|
254
|
+
|
|
258
255
|
return result
|
|
259
|
-
|
|
256
|
+
|
|
260
257
|
def _parse_web_tool_target(self, target: str) -> Dict:
|
|
261
258
|
"""Parse web tool targets (nuclei, gobuster, wpscan)."""
|
|
262
|
-
if target.startswith((
|
|
259
|
+
if target.startswith(("http://", "https://")):
|
|
263
260
|
return self.extract_from_url(target)
|
|
264
261
|
return {}
|
|
265
|
-
|
|
262
|
+
|
|
266
263
|
def _parse_hydra_args(self, target: str, args: Optional[List]) -> Dict:
|
|
267
264
|
"""
|
|
268
265
|
Parse Hydra arguments.
|
|
269
|
-
|
|
266
|
+
|
|
270
267
|
Examples:
|
|
271
268
|
target='10.0.0.5', args=['ssh'] → {'port': 22, 'service': 'ssh'}
|
|
272
269
|
target='10.0.0.5', args=['mysql'] → {'port': 3306, 'service': 'mysql'}
|
|
273
270
|
"""
|
|
274
271
|
result = {}
|
|
275
|
-
|
|
272
|
+
|
|
276
273
|
if args and len(args) > 0:
|
|
277
274
|
# First arg is usually the service
|
|
278
275
|
service = args[0].lower()
|
|
279
|
-
result[
|
|
280
|
-
result[
|
|
281
|
-
|
|
276
|
+
result["service"] = service
|
|
277
|
+
result["port"] = self.infer_port_from_service(service)
|
|
278
|
+
|
|
282
279
|
return result
|
|
283
|
-
|
|
280
|
+
|
|
284
281
|
def _parse_msf_args(self, args: Optional[List]) -> Dict:
|
|
285
282
|
"""
|
|
286
283
|
Parse Metasploit auxiliary module args.
|
|
287
|
-
|
|
284
|
+
|
|
288
285
|
Args can be:
|
|
289
286
|
- List: ['scanner/mysql/mysql_login']
|
|
290
287
|
- Dict: {'module': 'scanner/mysql/mysql_login'}
|
|
291
|
-
|
|
288
|
+
|
|
292
289
|
Examples:
|
|
293
290
|
{'module': 'scanner/mysql/mysql_login'} → {'service': 'mysql', 'port': 3306}
|
|
294
291
|
{'module': 'scanner/ssh/ssh_login'} → {'service': 'ssh', 'port': 22}
|
|
295
292
|
"""
|
|
296
293
|
result = {}
|
|
297
|
-
|
|
294
|
+
|
|
298
295
|
if not args:
|
|
299
296
|
return result
|
|
300
|
-
|
|
297
|
+
|
|
301
298
|
# Extract module name
|
|
302
299
|
module = None
|
|
303
300
|
if isinstance(args, dict):
|
|
304
|
-
module = args.get(
|
|
301
|
+
module = args.get("module")
|
|
305
302
|
elif isinstance(args, list) and len(args) > 0:
|
|
306
303
|
module = args[0]
|
|
307
|
-
|
|
304
|
+
|
|
308
305
|
if module:
|
|
309
306
|
msf_info = self.parse_msf_module(module)
|
|
310
307
|
result.update(msf_info)
|
|
311
|
-
|
|
308
|
+
|
|
312
309
|
return result
|
|
313
|
-
|
|
310
|
+
|
|
314
311
|
def _parse_sqlmap_target(self, target: str) -> Dict:
|
|
315
312
|
"""
|
|
316
313
|
Parse SQLMap target (usually a URL).
|
|
317
|
-
|
|
314
|
+
|
|
318
315
|
Examples:
|
|
319
316
|
'http://10.0.0.5/page.php?id=1' → {'host': '10.0.0.5', 'port': 80, 'service': 'http'}
|
|
320
317
|
"""
|
|
321
|
-
if target.startswith((
|
|
318
|
+
if target.startswith(("http://", "https://")):
|
|
322
319
|
return self.extract_from_url(target)
|
|
323
320
|
return {}
|
|
324
|
-
|
|
321
|
+
|
|
325
322
|
def parse_msf_module(self, module: str) -> Dict:
|
|
326
323
|
"""
|
|
327
324
|
Extract service info from MSF module name.
|
|
328
|
-
|
|
325
|
+
|
|
329
326
|
Examples:
|
|
330
327
|
'scanner/mysql/mysql_login' → {'service': 'mysql', 'port': 3306}
|
|
331
328
|
'scanner/ssh/ssh_login' → {'service': 'ssh', 'port': 22}
|
|
332
329
|
'exploit/unix/ftp/vsftpd_234_backdoor' → {'service': 'ftp', 'port': 21}
|
|
333
330
|
"""
|
|
334
331
|
result = {}
|
|
335
|
-
|
|
332
|
+
|
|
336
333
|
# Extract service name from module path
|
|
337
|
-
parts = module.split(
|
|
338
|
-
|
|
334
|
+
parts = module.split("/")
|
|
335
|
+
|
|
339
336
|
for part in parts:
|
|
340
337
|
part_lower = part.lower()
|
|
341
338
|
if part_lower in self.MSF_PATTERNS:
|
|
342
|
-
result[
|
|
343
|
-
result[
|
|
339
|
+
result["service"] = part_lower
|
|
340
|
+
result["port"] = self.MSF_PATTERNS[part_lower]
|
|
344
341
|
break
|
|
345
|
-
|
|
342
|
+
|
|
346
343
|
return result
|
|
347
|
-
|
|
344
|
+
|
|
348
345
|
def infer_port_from_service(self, service: str) -> Optional[int]:
|
|
349
346
|
"""
|
|
350
347
|
Infer default port from service name.
|
|
351
|
-
|
|
348
|
+
|
|
352
349
|
Examples:
|
|
353
350
|
'ssh' → 22
|
|
354
351
|
'mysql' → 3306
|
|
@@ -357,11 +354,11 @@ class TargetParser:
|
|
|
357
354
|
"""
|
|
358
355
|
service_lower = service.lower()
|
|
359
356
|
return self.SERVICE_PORTS.get(service_lower)
|
|
360
|
-
|
|
357
|
+
|
|
361
358
|
def infer_service_from_port(self, port: int) -> Optional[str]:
|
|
362
359
|
"""
|
|
363
360
|
Infer service from common port.
|
|
364
|
-
|
|
361
|
+
|
|
365
362
|
Examples:
|
|
366
363
|
22 → 'ssh'
|
|
367
364
|
3306 → 'mysql'
|
souleyez/licensing/__init__.py
CHANGED
|
@@ -15,10 +15,10 @@ from souleyez.licensing.validator import (
|
|
|
15
15
|
)
|
|
16
16
|
|
|
17
17
|
__all__ = [
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
18
|
+
"LicenseValidator",
|
|
19
|
+
"LicenseInfo",
|
|
20
|
+
"validate_license",
|
|
21
|
+
"activate_license",
|
|
22
|
+
"get_active_license",
|
|
23
|
+
"deactivate_license",
|
|
24
24
|
]
|
souleyez/licensing/validator.py
CHANGED
|
@@ -28,9 +28,10 @@ def _add_base64_padding(data: str) -> str:
|
|
|
28
28
|
"""Add padding to base64 string if missing."""
|
|
29
29
|
padding = 4 - len(data) % 4
|
|
30
30
|
if padding != 4:
|
|
31
|
-
data +=
|
|
31
|
+
data += "=" * padding
|
|
32
32
|
return data
|
|
33
33
|
|
|
34
|
+
|
|
34
35
|
# Ed25519 public key for license verification (Base64 encoded)
|
|
35
36
|
# Private key is kept secure by the license issuer
|
|
36
37
|
# This public key can only VERIFY signatures, not create them
|
|
@@ -42,6 +43,7 @@ MCowBQYDK2VwAyEABS0eqd9OPCtqOvQI1Aw8vGnXiX1qecBjZ0UY7esPk1I=
|
|
|
42
43
|
@dataclass
|
|
43
44
|
class LicenseInfo:
|
|
44
45
|
"""Validated license information."""
|
|
46
|
+
|
|
45
47
|
email: str
|
|
46
48
|
tier: str
|
|
47
49
|
issued_at: datetime
|
|
@@ -128,7 +130,7 @@ class LicenseValidator:
|
|
|
128
130
|
expires_at=None,
|
|
129
131
|
machine_id=None,
|
|
130
132
|
is_valid=False,
|
|
131
|
-
error=f"Invalid license format: {e}"
|
|
133
|
+
error=f"Invalid license format: {e}",
|
|
132
134
|
)
|
|
133
135
|
|
|
134
136
|
# Extract components
|
|
@@ -143,7 +145,7 @@ class LicenseValidator:
|
|
|
143
145
|
expires_at=None,
|
|
144
146
|
machine_id=None,
|
|
145
147
|
is_valid=False,
|
|
146
|
-
error="Missing license data or signature"
|
|
148
|
+
error="Missing license data or signature",
|
|
147
149
|
)
|
|
148
150
|
|
|
149
151
|
# Verify signature
|
|
@@ -155,7 +157,7 @@ class LicenseValidator:
|
|
|
155
157
|
expires_at=None,
|
|
156
158
|
machine_id=None,
|
|
157
159
|
is_valid=False,
|
|
158
|
-
error="Invalid license signature"
|
|
160
|
+
error="Invalid license signature",
|
|
159
161
|
)
|
|
160
162
|
|
|
161
163
|
# Parse dates
|
|
@@ -173,7 +175,7 @@ class LicenseValidator:
|
|
|
173
175
|
expires_at=expires_at,
|
|
174
176
|
machine_id=data.get("machine_id"),
|
|
175
177
|
is_valid=False,
|
|
176
|
-
error="License has expired"
|
|
178
|
+
error="License has expired",
|
|
177
179
|
)
|
|
178
180
|
|
|
179
181
|
# Check machine binding if present
|
|
@@ -187,7 +189,7 @@ class LicenseValidator:
|
|
|
187
189
|
expires_at=expires_at,
|
|
188
190
|
machine_id=data.get("machine_id"),
|
|
189
191
|
is_valid=False,
|
|
190
|
-
error="License is bound to a different machine"
|
|
192
|
+
error="License is bound to a different machine",
|
|
191
193
|
)
|
|
192
194
|
|
|
193
195
|
# License is valid
|
|
@@ -198,7 +200,7 @@ class LicenseValidator:
|
|
|
198
200
|
expires_at=expires_at,
|
|
199
201
|
machine_id=data.get("machine_id"),
|
|
200
202
|
is_valid=True,
|
|
201
|
-
error=None
|
|
203
|
+
error=None,
|
|
202
204
|
)
|
|
203
205
|
|
|
204
206
|
except Exception as e:
|
|
@@ -209,7 +211,7 @@ class LicenseValidator:
|
|
|
209
211
|
expires_at=None,
|
|
210
212
|
machine_id=None,
|
|
211
213
|
is_valid=False,
|
|
212
|
-
error=f"License validation error: {e}"
|
|
214
|
+
error=f"License validation error: {e}",
|
|
213
215
|
)
|
|
214
216
|
|
|
215
217
|
def _verify_signature(self, data: dict, signature_b64: str) -> bool:
|
|
@@ -224,7 +226,9 @@ class LicenseValidator:
|
|
|
224
226
|
True if signature is valid
|
|
225
227
|
"""
|
|
226
228
|
try:
|
|
227
|
-
from cryptography.hazmat.primitives.asymmetric.ed25519 import
|
|
229
|
+
from cryptography.hazmat.primitives.asymmetric.ed25519 import (
|
|
230
|
+
Ed25519PublicKey,
|
|
231
|
+
)
|
|
228
232
|
from cryptography.hazmat.primitives.serialization import load_pem_public_key
|
|
229
233
|
|
|
230
234
|
# Check if public key is configured
|
|
@@ -233,12 +237,10 @@ class LicenseValidator:
|
|
|
233
237
|
return self._verify_dev_signature(data, signature_b64)
|
|
234
238
|
|
|
235
239
|
# Load public key
|
|
236
|
-
public_key = load_pem_public_key(
|
|
237
|
-
LICENSE_PUBLIC_KEY.encode()
|
|
238
|
-
)
|
|
240
|
+
public_key = load_pem_public_key(LICENSE_PUBLIC_KEY.encode())
|
|
239
241
|
|
|
240
242
|
# Recreate the signed message
|
|
241
|
-
message = json.dumps(data, sort_keys=True, separators=(
|
|
243
|
+
message = json.dumps(data, sort_keys=True, separators=(",", ":")).encode()
|
|
242
244
|
|
|
243
245
|
# Decode signature
|
|
244
246
|
signature = base64.urlsafe_b64decode(_add_base64_padding(signature_b64))
|
|
@@ -259,12 +261,8 @@ class LicenseValidator:
|
|
|
259
261
|
|
|
260
262
|
DEV_SECRET = "souleyez-dev-license-key-for-testing-only"
|
|
261
263
|
|
|
262
|
-
message = json.dumps(data, sort_keys=True, separators=(
|
|
263
|
-
expected = hmac.new(
|
|
264
|
-
DEV_SECRET.encode(),
|
|
265
|
-
message,
|
|
266
|
-
hashlib.sha256
|
|
267
|
-
).digest()
|
|
264
|
+
message = json.dumps(data, sort_keys=True, separators=(",", ":")).encode()
|
|
265
|
+
expected = hmac.new(DEV_SECRET.encode(), message, hashlib.sha256).digest()
|
|
268
266
|
|
|
269
267
|
try:
|
|
270
268
|
actual = base64.urlsafe_b64decode(_add_base64_padding(signature_b64))
|