atomicshop 2.11.47__py3-none-any.whl → 3.10.5__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.
- atomicshop/__init__.py +1 -1
- atomicshop/{addons/mains → a_mains}/FACT/update_extract.py +3 -2
- atomicshop/a_mains/addons/process_list/compile.cmd +7 -0
- atomicshop/a_mains/addons/process_list/compiled/Win10x64/process_list.dll +0 -0
- atomicshop/a_mains/addons/process_list/compiled/Win10x64/process_list.exp +0 -0
- atomicshop/a_mains/addons/process_list/compiled/Win10x64/process_list.lib +0 -0
- atomicshop/{addons → a_mains/addons}/process_list/process_list.cpp +8 -1
- atomicshop/a_mains/dns_gateway_setting.py +11 -0
- atomicshop/a_mains/get_local_tcp_ports.py +85 -0
- atomicshop/a_mains/github_wrapper.py +11 -0
- atomicshop/a_mains/install_ca_certificate.py +172 -0
- atomicshop/{addons/mains → a_mains}/msi_unpacker.py +3 -1
- atomicshop/a_mains/process_from_port.py +119 -0
- atomicshop/a_mains/set_default_dns_gateway.py +90 -0
- atomicshop/a_mains/update_config_toml.py +38 -0
- atomicshop/appointment_management.py +5 -3
- atomicshop/basics/ansi_escape_codes.py +3 -1
- atomicshop/basics/argparse_template.py +2 -0
- atomicshop/basics/booleans.py +27 -30
- atomicshop/basics/bytes_arrays.py +43 -0
- atomicshop/basics/classes.py +149 -1
- atomicshop/basics/dicts.py +12 -0
- atomicshop/basics/enums.py +2 -2
- atomicshop/basics/exceptions.py +5 -1
- atomicshop/basics/list_of_classes.py +29 -0
- atomicshop/basics/list_of_dicts.py +69 -5
- atomicshop/basics/lists.py +14 -0
- atomicshop/basics/multiprocesses.py +374 -50
- atomicshop/basics/package_module.py +10 -0
- atomicshop/basics/strings.py +160 -7
- atomicshop/basics/threads.py +14 -0
- atomicshop/basics/tracebacks.py +13 -4
- atomicshop/certificates.py +153 -52
- atomicshop/config_init.py +12 -7
- atomicshop/console_user_response.py +7 -14
- atomicshop/consoles.py +9 -0
- atomicshop/datetimes.py +98 -0
- atomicshop/diff_check.py +340 -40
- atomicshop/dns.py +128 -12
- atomicshop/etws/_pywintrace_fix.py +17 -0
- atomicshop/etws/const.py +38 -0
- atomicshop/etws/providers.py +21 -0
- atomicshop/etws/sessions.py +43 -0
- atomicshop/etws/trace.py +168 -0
- atomicshop/etws/traces/trace_dns.py +162 -0
- atomicshop/etws/traces/trace_sysmon_process_creation.py +126 -0
- atomicshop/etws/traces/trace_tcp.py +130 -0
- atomicshop/file_io/csvs.py +222 -24
- atomicshop/file_io/docxs.py +35 -18
- atomicshop/file_io/file_io.py +35 -19
- atomicshop/file_io/jsons.py +49 -0
- atomicshop/file_io/tomls.py +139 -0
- atomicshop/filesystem.py +864 -293
- atomicshop/get_process_list.py +133 -0
- atomicshop/{process_name_cmd.py → get_process_name_cmd_dll.py} +52 -19
- atomicshop/http_parse.py +149 -93
- atomicshop/ip_addresses.py +6 -1
- atomicshop/mitm/centered_settings.py +132 -0
- atomicshop/mitm/config_static.py +207 -0
- atomicshop/mitm/config_toml_editor.py +55 -0
- atomicshop/mitm/connection_thread_worker.py +875 -357
- atomicshop/mitm/engines/__parent/parser___parent.py +4 -17
- atomicshop/mitm/engines/__parent/recorder___parent.py +108 -51
- atomicshop/mitm/engines/__parent/requester___parent.py +116 -0
- atomicshop/mitm/engines/__parent/responder___parent.py +75 -114
- atomicshop/mitm/engines/__reference_general/parser___reference_general.py +10 -7
- atomicshop/mitm/engines/__reference_general/recorder___reference_general.py +5 -5
- atomicshop/mitm/engines/__reference_general/requester___reference_general.py +47 -0
- atomicshop/mitm/engines/__reference_general/responder___reference_general.py +95 -13
- atomicshop/mitm/engines/create_module_template.py +58 -14
- atomicshop/mitm/import_config.py +359 -139
- atomicshop/mitm/initialize_engines.py +160 -74
- atomicshop/mitm/message.py +64 -23
- atomicshop/mitm/mitm_main.py +892 -0
- atomicshop/mitm/recs_files.py +183 -0
- atomicshop/mitm/shared_functions.py +4 -10
- atomicshop/mitm/ssh_tester.py +82 -0
- atomicshop/mitm/statistic_analyzer.py +257 -166
- atomicshop/mitm/statistic_analyzer_helper/analyzer_helper.py +136 -0
- atomicshop/mitm/statistic_analyzer_helper/moving_average_helper.py +525 -0
- atomicshop/monitor/change_monitor.py +96 -120
- atomicshop/monitor/checks/dns.py +139 -70
- atomicshop/monitor/checks/file.py +77 -0
- atomicshop/monitor/checks/network.py +81 -77
- atomicshop/monitor/checks/process_running.py +33 -34
- atomicshop/monitor/checks/url.py +94 -0
- atomicshop/networks.py +671 -0
- atomicshop/on_exit.py +205 -0
- atomicshop/package_mains_processor.py +84 -0
- atomicshop/permissions/permissions.py +22 -0
- atomicshop/permissions/ubuntu_permissions.py +239 -0
- atomicshop/permissions/win_permissions.py +33 -0
- atomicshop/print_api.py +24 -41
- atomicshop/process.py +63 -17
- atomicshop/process_poller/__init__.py +0 -0
- atomicshop/process_poller/pollers/__init__.py +0 -0
- atomicshop/process_poller/pollers/psutil_pywin32wmi_dll.py +95 -0
- atomicshop/process_poller/process_pool.py +207 -0
- atomicshop/process_poller/simple_process_pool.py +311 -0
- atomicshop/process_poller/tracer_base.py +45 -0
- atomicshop/process_poller/tracers/__init__.py +0 -0
- atomicshop/process_poller/tracers/event_log.py +46 -0
- atomicshop/process_poller/tracers/sysmon_etw.py +68 -0
- atomicshop/python_file_patcher.py +1 -1
- atomicshop/python_functions.py +27 -75
- atomicshop/question_answer_engine.py +2 -2
- atomicshop/scheduling.py +24 -5
- atomicshop/sound.py +4 -2
- atomicshop/speech_recognize.py +8 -0
- atomicshop/ssh_remote.py +158 -172
- atomicshop/startup/__init__.py +0 -0
- atomicshop/startup/win/__init__.py +0 -0
- atomicshop/startup/win/startup_folder.py +53 -0
- atomicshop/startup/win/task_scheduler.py +119 -0
- atomicshop/system_resource_monitor.py +61 -46
- atomicshop/system_resources.py +8 -8
- atomicshop/tempfiles.py +1 -2
- atomicshop/timer.py +30 -11
- atomicshop/urls.py +41 -0
- atomicshop/venvs.py +28 -0
- atomicshop/versioning.py +27 -0
- atomicshop/web.py +110 -25
- atomicshop/web_apis/__init__.py +0 -0
- atomicshop/web_apis/google_custom_search.py +44 -0
- atomicshop/web_apis/google_llm.py +188 -0
- atomicshop/websocket_parse.py +450 -0
- atomicshop/wrappers/certauthw/certauth.py +1 -0
- atomicshop/wrappers/cryptographyw.py +29 -8
- atomicshop/wrappers/ctyping/etw_winapi/__init__.py +0 -0
- atomicshop/wrappers/ctyping/etw_winapi/const.py +335 -0
- atomicshop/wrappers/ctyping/etw_winapi/etw_functions.py +393 -0
- atomicshop/wrappers/ctyping/file_details_winapi.py +67 -0
- atomicshop/wrappers/ctyping/msi_windows_installer/cabs.py +2 -1
- atomicshop/wrappers/ctyping/msi_windows_installer/extract_msi_main.py +13 -9
- atomicshop/wrappers/ctyping/msi_windows_installer/tables.py +35 -0
- atomicshop/wrappers/ctyping/setup_device.py +466 -0
- atomicshop/wrappers/ctyping/win_console.py +39 -0
- atomicshop/wrappers/dockerw/dockerw.py +113 -2
- atomicshop/wrappers/elasticsearchw/config_basic.py +0 -12
- atomicshop/wrappers/elasticsearchw/elastic_infra.py +75 -0
- atomicshop/wrappers/elasticsearchw/elasticsearchw.py +2 -20
- atomicshop/wrappers/factw/get_file_data.py +12 -5
- atomicshop/wrappers/factw/install/install_after_restart.py +89 -5
- atomicshop/wrappers/factw/install/pre_install_and_install_before_restart.py +20 -14
- atomicshop/wrappers/factw/postgresql/firmware.py +4 -6
- atomicshop/wrappers/githubw.py +583 -51
- atomicshop/wrappers/loggingw/consts.py +49 -0
- atomicshop/wrappers/loggingw/filters.py +102 -0
- atomicshop/wrappers/loggingw/formatters.py +58 -71
- atomicshop/wrappers/loggingw/handlers.py +459 -40
- atomicshop/wrappers/loggingw/loggers.py +19 -0
- atomicshop/wrappers/loggingw/loggingw.py +1010 -178
- atomicshop/wrappers/loggingw/reading.py +344 -19
- atomicshop/wrappers/mongodbw/__init__.py +0 -0
- atomicshop/wrappers/mongodbw/mongo_infra.py +31 -0
- atomicshop/wrappers/mongodbw/mongodbw.py +1432 -0
- atomicshop/wrappers/netshw.py +271 -0
- atomicshop/wrappers/playwrightw/engine.py +34 -19
- atomicshop/wrappers/playwrightw/infra.py +5 -0
- atomicshop/wrappers/playwrightw/javascript.py +7 -3
- atomicshop/wrappers/playwrightw/keyboard.py +14 -0
- atomicshop/wrappers/playwrightw/scenarios.py +172 -5
- atomicshop/wrappers/playwrightw/waits.py +9 -7
- atomicshop/wrappers/powershell_networking.py +80 -0
- atomicshop/wrappers/psutilw/processes.py +81 -0
- atomicshop/wrappers/psutilw/psutil_networks.py +85 -0
- atomicshop/wrappers/psutilw/psutilw.py +9 -0
- atomicshop/wrappers/pyopensslw.py +9 -2
- atomicshop/wrappers/pywin32w/__init__.py +0 -0
- atomicshop/wrappers/pywin32w/cert_store.py +116 -0
- atomicshop/wrappers/pywin32w/console.py +34 -0
- atomicshop/wrappers/pywin32w/win_event_log/__init__.py +0 -0
- atomicshop/wrappers/pywin32w/win_event_log/fetch.py +174 -0
- atomicshop/wrappers/pywin32w/win_event_log/subscribe.py +212 -0
- atomicshop/wrappers/pywin32w/win_event_log/subscribes/__init__.py +0 -0
- atomicshop/wrappers/pywin32w/win_event_log/subscribes/process_create.py +57 -0
- atomicshop/wrappers/pywin32w/win_event_log/subscribes/process_terminate.py +49 -0
- atomicshop/wrappers/pywin32w/win_event_log/subscribes/schannel_logging.py +97 -0
- atomicshop/wrappers/pywin32w/winshell.py +19 -0
- atomicshop/wrappers/pywin32w/wmis/__init__.py +0 -0
- atomicshop/wrappers/pywin32w/wmis/msft_netipaddress.py +113 -0
- atomicshop/wrappers/pywin32w/wmis/win32_networkadapterconfiguration.py +259 -0
- atomicshop/wrappers/pywin32w/wmis/win32networkadapter.py +112 -0
- atomicshop/wrappers/pywin32w/wmis/wmi_helpers.py +236 -0
- atomicshop/wrappers/socketw/accepter.py +21 -7
- atomicshop/wrappers/socketw/certificator.py +216 -150
- atomicshop/wrappers/socketw/creator.py +190 -50
- atomicshop/wrappers/socketw/dns_server.py +500 -173
- atomicshop/wrappers/socketw/exception_wrapper.py +45 -52
- atomicshop/wrappers/socketw/process_getter.py +86 -0
- atomicshop/wrappers/socketw/receiver.py +144 -102
- atomicshop/wrappers/socketw/sender.py +65 -35
- atomicshop/wrappers/socketw/sni.py +334 -165
- atomicshop/wrappers/socketw/socket_base.py +134 -0
- atomicshop/wrappers/socketw/socket_client.py +137 -95
- atomicshop/wrappers/socketw/socket_server_tester.py +14 -9
- atomicshop/wrappers/socketw/socket_wrapper.py +717 -116
- atomicshop/wrappers/socketw/ssl_base.py +15 -14
- atomicshop/wrappers/socketw/statistics_csv.py +148 -17
- atomicshop/wrappers/sysmonw.py +157 -0
- atomicshop/wrappers/ubuntu_terminal.py +65 -26
- atomicshop/wrappers/win_auditw.py +189 -0
- atomicshop/wrappers/winregw/__init__.py +0 -0
- atomicshop/wrappers/winregw/winreg_installed_software.py +58 -0
- atomicshop/wrappers/winregw/winreg_network.py +232 -0
- {atomicshop-2.11.47.dist-info → atomicshop-3.10.5.dist-info}/METADATA +31 -49
- atomicshop-3.10.5.dist-info/RECORD +306 -0
- {atomicshop-2.11.47.dist-info → atomicshop-3.10.5.dist-info}/WHEEL +1 -1
- atomicshop/_basics_temp.py +0 -101
- atomicshop/addons/a_setup_scripts/install_psycopg2_ubuntu.sh +0 -3
- atomicshop/addons/a_setup_scripts/install_pywintrace_0.3.cmd +0 -2
- atomicshop/addons/mains/install_docker_rootless_ubuntu.py +0 -11
- atomicshop/addons/mains/install_docker_ubuntu_main_sudo.py +0 -11
- atomicshop/addons/mains/install_elastic_search_and_kibana_ubuntu.py +0 -10
- atomicshop/addons/mains/install_wsl_ubuntu_lts_admin.py +0 -9
- atomicshop/addons/package_setup/CreateWheel.cmd +0 -7
- atomicshop/addons/package_setup/Setup in Edit mode.cmd +0 -6
- atomicshop/addons/package_setup/Setup.cmd +0 -7
- atomicshop/addons/process_list/compile.cmd +0 -2
- atomicshop/addons/process_list/compiled/Win10x64/process_list.dll +0 -0
- atomicshop/addons/process_list/compiled/Win10x64/process_list.exp +0 -0
- atomicshop/addons/process_list/compiled/Win10x64/process_list.lib +0 -0
- atomicshop/archiver/_search_in_zip.py +0 -189
- atomicshop/archiver/archiver.py +0 -34
- atomicshop/archiver/search_in_archive.py +0 -250
- atomicshop/archiver/sevenz_app_w.py +0 -86
- atomicshop/archiver/sevenzs.py +0 -44
- atomicshop/archiver/zips.py +0 -293
- atomicshop/etw/dns_trace.py +0 -118
- atomicshop/etw/etw.py +0 -61
- atomicshop/file_types.py +0 -24
- atomicshop/mitm/engines/create_module_template_example.py +0 -13
- atomicshop/mitm/initialize_mitm_server.py +0 -240
- atomicshop/monitor/checks/hash.py +0 -44
- atomicshop/monitor/checks/hash_checks/file.py +0 -55
- atomicshop/monitor/checks/hash_checks/url.py +0 -62
- atomicshop/pbtkmultifile_argparse.py +0 -88
- atomicshop/permissions.py +0 -110
- atomicshop/process_poller.py +0 -237
- atomicshop/script_as_string_processor.py +0 -38
- atomicshop/ssh_scripts/process_from_ipv4.py +0 -37
- atomicshop/ssh_scripts/process_from_port.py +0 -27
- atomicshop/wrappers/_process_wrapper_curl.py +0 -27
- atomicshop/wrappers/_process_wrapper_tar.py +0 -21
- atomicshop/wrappers/dockerw/install_docker.py +0 -209
- atomicshop/wrappers/elasticsearchw/infrastructure.py +0 -265
- atomicshop/wrappers/elasticsearchw/install_elastic.py +0 -232
- atomicshop/wrappers/ffmpegw.py +0 -125
- atomicshop/wrappers/loggingw/checks.py +0 -20
- atomicshop/wrappers/nodejsw/install_nodejs.py +0 -139
- atomicshop/wrappers/process_wrapper_pbtk.py +0 -16
- atomicshop/wrappers/socketw/base.py +0 -59
- atomicshop/wrappers/socketw/get_process.py +0 -107
- atomicshop/wrappers/wslw.py +0 -191
- atomicshop-2.11.47.dist-info/RECORD +0 -251
- /atomicshop/{addons/mains → a_mains}/FACT/factw_fact_extractor_docker_image_main_sudo.py +0 -0
- /atomicshop/{addons → a_mains/addons}/PlayWrightCodegen.cmd +0 -0
- /atomicshop/{addons → a_mains/addons}/ScriptExecution.cmd +0 -0
- /atomicshop/{addons/mains → a_mains/addons}/inits/init_to_import_all_modules.py +0 -0
- /atomicshop/{addons → a_mains/addons}/process_list/ReadMe.txt +0 -0
- /atomicshop/{addons/mains → a_mains}/search_for_hyperlinks_in_docx.py +0 -0
- /atomicshop/{archiver → etws}/__init__.py +0 -0
- /atomicshop/{etw → etws/traces}/__init__.py +0 -0
- /atomicshop/{monitor/checks/hash_checks → mitm/statistic_analyzer_helper}/__init__.py +0 -0
- /atomicshop/{wrappers/nodejsw → permissions}/__init__.py +0 -0
- /atomicshop/wrappers/pywin32w/{wmi_win32process.py → wmis/win32process.py} +0 -0
- {atomicshop-2.11.47.dist-info → atomicshop-3.10.5.dist-info/licenses}/LICENSE.txt +0 -0
- {atomicshop-2.11.47.dist-info → atomicshop-3.10.5.dist-info}/top_level.txt +0 -0
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
import socket
|
|
2
2
|
import ssl
|
|
3
3
|
import time
|
|
4
|
+
from typing import Literal, Union
|
|
5
|
+
import logging
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
# noinspection PyPackageRequirements
|
|
9
|
+
from cryptography import x509
|
|
10
|
+
# noinspection PyPackageRequirements
|
|
11
|
+
import dns.resolver
|
|
4
12
|
|
|
5
13
|
from . import creator
|
|
6
14
|
from .receiver import Receiver
|
|
@@ -8,19 +16,24 @@ from .sender import Sender
|
|
|
8
16
|
from . import ssl_base
|
|
9
17
|
from .. import cryptographyw
|
|
10
18
|
from ..loggingw import loggingw
|
|
11
|
-
from ...
|
|
19
|
+
from ... import print_api
|
|
12
20
|
from ...file_io import file_io
|
|
13
|
-
from ... import
|
|
14
|
-
|
|
15
|
-
import dns.resolver
|
|
21
|
+
from ...basics import tracebacks
|
|
16
22
|
|
|
17
23
|
|
|
18
24
|
class SocketClient:
|
|
19
|
-
logger = loggingw.get_logger_with_level("network." + __name__.rpartition('.')[2])
|
|
20
|
-
|
|
21
25
|
def __init__(
|
|
22
26
|
self,
|
|
23
|
-
service_name: str,
|
|
27
|
+
service_name: str,
|
|
28
|
+
service_port: int,
|
|
29
|
+
tls: bool = False,
|
|
30
|
+
connection_ip=None,
|
|
31
|
+
dns_servers_list: list[str] = None,
|
|
32
|
+
logger: logging.Logger = None,
|
|
33
|
+
custom_pem_client_certificate_file_path: str = None,
|
|
34
|
+
enable_sslkeylogfile_env_to_client_ssl_context: bool = False,
|
|
35
|
+
sslkeylog_file_path:str = None
|
|
36
|
+
):
|
|
24
37
|
"""
|
|
25
38
|
If you have a certificate for domain, but not for the IPv4 address, the SSL Socket context can be created for
|
|
26
39
|
domain and the connection itself (socket.connect()) made for the IP. This way YOU decide to which IPv4 your
|
|
@@ -36,6 +49,16 @@ class SocketClient:
|
|
|
36
49
|
'service_name' by these DNS servers, with the first IPv4 result.
|
|
37
50
|
:param dns_servers_list: (Optional) List object with dns IPv4 addresses that 'service_name' will be resolved
|
|
38
51
|
with, using 'dnspython' module. 'connection_ip' will be populated with first resolved IP.
|
|
52
|
+
:param logger: (Optional) Logger object. If not provided, the default logger will be used.
|
|
53
|
+
:param custom_pem_client_certificate_file_path: (Optional) If specified, the SSL Socket will be created with
|
|
54
|
+
custom client certificate. The path to the file with the certificate should be provided.
|
|
55
|
+
:param enable_sslkeylogfile_env_to_client_ssl_context: boolean, enables the SSLKEYLOGFILE environment variable
|
|
56
|
+
to the SSL context. Default is False.
|
|
57
|
+
if True, SSLKEYLOGFILE will be added to SSL context with:
|
|
58
|
+
ssl_context.keylog_filename = os.environ.get('SSLKEYLOGFILE')
|
|
59
|
+
This is useful for debugging SSL/TLS connections with WireShark.
|
|
60
|
+
Since WireShark also uses this environment variable to read the key log file and apply to the SSL/TLS
|
|
61
|
+
connections, so you can see the decrypted traffic.
|
|
39
62
|
|
|
40
63
|
If both 'connection_ip' and 'dns_servers_list' specified, ValueException with raise.
|
|
41
64
|
"""
|
|
@@ -44,6 +67,15 @@ class SocketClient:
|
|
|
44
67
|
self.tls: bool = tls
|
|
45
68
|
self.connection_ip = connection_ip
|
|
46
69
|
self.dns_servers_list = dns_servers_list
|
|
70
|
+
self.custom_pem_client_certificate_file_path: str = custom_pem_client_certificate_file_path
|
|
71
|
+
self.enable_sslkeylogfile_env_to_client_ssl_context: bool = enable_sslkeylogfile_env_to_client_ssl_context
|
|
72
|
+
self.sslkeylog_file_path: str = sslkeylog_file_path
|
|
73
|
+
|
|
74
|
+
if logger:
|
|
75
|
+
# Create child logger for the provided logger with the module's name.
|
|
76
|
+
self.logger: logging.Logger = loggingw.get_logger_with_level(f'{logger.name}.{Path(__file__).stem}')
|
|
77
|
+
else:
|
|
78
|
+
self.logger: logging.Logger = logger
|
|
47
79
|
|
|
48
80
|
self.socket_instance = None
|
|
49
81
|
|
|
@@ -62,16 +94,31 @@ class SocketClient:
|
|
|
62
94
|
def create_service_socket(self):
|
|
63
95
|
# If TLS is enabled.
|
|
64
96
|
if not self.tls:
|
|
65
|
-
|
|
97
|
+
log_message: str = f"Creating non-SSL socket to [{self.service_name}:{self.service_port}]"
|
|
98
|
+
print_api.print_api(log_message, logger=self.logger, logger_method='info')
|
|
66
99
|
return creator.create_socket_ipv4_tcp()
|
|
67
100
|
else:
|
|
68
|
-
|
|
101
|
+
log_message: str = f"Creating SSL socket to [{self.service_name}:{self.service_port}]"
|
|
102
|
+
print_api.print_api(log_message, logger=self.logger, logger_method='info')
|
|
69
103
|
socket_object = creator.create_socket_ipv4_tcp()
|
|
70
104
|
return creator.wrap_socket_with_ssl_context_client___default_certs___ignore_verification(
|
|
71
|
-
socket_object, self.service_name
|
|
105
|
+
socket_object, self.service_name, self.custom_pem_client_certificate_file_path,
|
|
106
|
+
enable_sslkeylogfile_env_to_client_ssl_context=self.enable_sslkeylogfile_env_to_client_ssl_context,
|
|
107
|
+
sslkeylog_file_path=self.sslkeylog_file_path
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
def service_connection(
|
|
111
|
+
self
|
|
112
|
+
) -> tuple[
|
|
113
|
+
Union[socket.socket, ssl.SSLSocket, None],
|
|
114
|
+
Union[str, None]]:
|
|
115
|
+
"""
|
|
116
|
+
Function to establish connection to server
|
|
72
117
|
|
|
73
|
-
|
|
74
|
-
|
|
118
|
+
:return: Tuple with socket object and error string.
|
|
119
|
+
If connection was successful, the error string will be None.
|
|
120
|
+
If connection wasn't successful, the socket object will be None.
|
|
121
|
+
"""
|
|
75
122
|
# Check if socket to service domain exists.
|
|
76
123
|
# If not
|
|
77
124
|
if not self.socket_instance:
|
|
@@ -90,8 +137,8 @@ class SocketClient:
|
|
|
90
137
|
f"Socket already defined to [{self.service_name}:{self.service_port}]. "
|
|
91
138
|
f"Should be connected - Reusing.")
|
|
92
139
|
# Since, restart the function each send_receive iteration, and there's still a connection we need to
|
|
93
|
-
#
|
|
94
|
-
return
|
|
140
|
+
# return the socket, or the socket object will be nullified in the next step.
|
|
141
|
+
return self.socket_instance, None
|
|
95
142
|
|
|
96
143
|
# If 'dns_servers_list' was provided, we will resolve the domain to ip through these servers.
|
|
97
144
|
if self.dns_servers_list:
|
|
@@ -109,11 +156,20 @@ class SocketClient:
|
|
|
109
156
|
# Get only the first entry of the list of IPs [0]
|
|
110
157
|
self.connection_ip = function_server_address[0].to_text()
|
|
111
158
|
self.logger.info(f"Resolved to [{self.connection_ip}]")
|
|
112
|
-
except dns.resolver.NXDOMAIN:
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
159
|
+
except dns.resolver.NXDOMAIN as e:
|
|
160
|
+
exception_type: str = type(e).__name__
|
|
161
|
+
error_string = (
|
|
162
|
+
f"Socket Client Connect: {exception_type}: "
|
|
163
|
+
f"Domain {self.service_name} doesn't exist - Couldn't resolve with {self.dns_servers_list}.")
|
|
164
|
+
print_api.print_api(error_string, logger=self.logger, logger_method='error')
|
|
165
|
+
return None, error_string
|
|
166
|
+
except dns.resolver.LifetimeTimeout as e:
|
|
167
|
+
exception_type: str = type(e).__name__
|
|
168
|
+
error_string = (
|
|
169
|
+
f"Socket Client Connect: {exception_type}: "
|
|
170
|
+
f"Timeout while resolving domain {self.service_name} with {self.dns_servers_list}.")
|
|
171
|
+
print_api.print_api(error_string, logger=self.logger, logger_method='error')
|
|
172
|
+
return None, error_string
|
|
117
173
|
|
|
118
174
|
# If DNS was resolved correctly or DNS servers weren't specified - we can try connecting.
|
|
119
175
|
# If 'connection_ip' was manually specified or resolved with 'dnspython' - the connection
|
|
@@ -128,49 +184,31 @@ class SocketClient:
|
|
|
128
184
|
try:
|
|
129
185
|
# "connect()" to the server using address and port
|
|
130
186
|
self.socket_instance.connect((destination, self.service_port))
|
|
131
|
-
except
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
except ssl.SSLError:
|
|
151
|
-
message = f"SSLError raised on connection to {self.service_name}."
|
|
152
|
-
print_api(message, logger=self.logger, logger_method='error', traceback_string=True, oneline=True)
|
|
153
|
-
# Socket close will be handled in the thread_worker_main
|
|
154
|
-
pass
|
|
155
|
-
return None
|
|
156
|
-
except TimeoutError:
|
|
157
|
-
message = f"TimeoutError raised on connection to {self.service_name}."
|
|
158
|
-
print_api(message, logger=self.logger, logger_method='error', traceback_string=True, oneline=True)
|
|
159
|
-
# Socket close will be handled in the thread_worker_main
|
|
160
|
-
pass
|
|
161
|
-
return None
|
|
162
|
-
except ValueError as e:
|
|
163
|
-
message = f'{str(e)} | on connect to [{self.service_name}].'
|
|
164
|
-
print_api(message, logger=self.logger, logger_method='error')
|
|
165
|
-
# Socket close will be handled in the thread_worker_main
|
|
166
|
-
pass
|
|
167
|
-
return None
|
|
187
|
+
except Exception as e:
|
|
188
|
+
exception_type: str = type(e).__name__
|
|
189
|
+
exception_error: str = tracebacks.get_as_string(one_line=True)
|
|
190
|
+
error_string: str = f"Socket Client Connect: {destination}: {exception_type}"
|
|
191
|
+
|
|
192
|
+
if exception_type in ['ConnectionRefusedError', 'ConnectionAbortedError', 'ConnectionResetError',
|
|
193
|
+
'TimeoutError'] or 'ssl' in exception_type.lower():
|
|
194
|
+
error_message: str = f"{error_string}: {exception_error}"
|
|
195
|
+
print_api.print_api(error_message, logger=self.logger, logger_method='error')
|
|
196
|
+
return None, error_message
|
|
197
|
+
elif exception_type == 'socket.gaierror':
|
|
198
|
+
custom_error_message: str = (
|
|
199
|
+
f"Couldn't resolve [{self.service_name}] to IP using default methods. "
|
|
200
|
+
f"Domain doesn't exist or there's no IP assigned to it.")
|
|
201
|
+
error_message: str = f"{error_string}: {custom_error_message}"
|
|
202
|
+
print_api.print_api(error_message, logger=self.logger, logger_method='error')
|
|
203
|
+
return None, error_message
|
|
204
|
+
else:
|
|
205
|
+
raise e
|
|
168
206
|
|
|
169
207
|
# If everything was fine, we'll log the connection.
|
|
170
208
|
self.logger.info("Connected...")
|
|
171
209
|
|
|
172
210
|
# Return the connected socket.
|
|
173
|
-
return self.socket_instance
|
|
211
|
+
return self.socket_instance, None
|
|
174
212
|
|
|
175
213
|
def get_socket(self):
|
|
176
214
|
return self.socket_instance
|
|
@@ -180,18 +218,25 @@ class SocketClient:
|
|
|
180
218
|
self.socket_instance = None
|
|
181
219
|
self.logger.info(f"Closed socket to service server [{self.service_name}:{self.service_port}]")
|
|
182
220
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
221
|
+
def send_receive_to_service(
|
|
222
|
+
self,
|
|
223
|
+
request_bytes: Union[bytearray, bytes],
|
|
224
|
+
skip_send: bool = False
|
|
225
|
+
):
|
|
226
|
+
"""
|
|
227
|
+
Function to send data to service server and receive response.
|
|
188
228
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
229
|
+
:param request_bytes: The data that will be sent to the service server.
|
|
230
|
+
:param skip_send: If True, the data will not be sent to the service server. After the connection is established,
|
|
231
|
+
the function will wait for the response only.
|
|
232
|
+
"""
|
|
233
|
+
|
|
234
|
+
origin_data: bytes | None = None
|
|
193
235
|
|
|
194
|
-
|
|
236
|
+
service_socket, error_message = self.service_connection()
|
|
237
|
+
# If connection to service server wasn't successful
|
|
238
|
+
if error_message:
|
|
239
|
+
# Wasn't able to connect to service, closing the destination service socket and nullify the object.
|
|
195
240
|
self.close_socket()
|
|
196
241
|
# If the connection to the service was successful
|
|
197
242
|
else:
|
|
@@ -205,27 +250,33 @@ class SocketClient:
|
|
|
205
250
|
self.logger.info(
|
|
206
251
|
f"[{self.service_name}] resolves to ip: [{self.connection_ip}]. Pulled IP from the socket.")
|
|
207
252
|
|
|
208
|
-
#
|
|
209
|
-
|
|
253
|
+
# noinspection PyTypeChecker
|
|
254
|
+
error_on_send: str = None
|
|
255
|
+
if not skip_send:
|
|
256
|
+
# Send the data received from the client to the service over socket
|
|
257
|
+
error_on_send = Sender(
|
|
258
|
+
ssl_socket=self.socket_instance, bytes_to_send=request_bytes, logger=self.logger).send()
|
|
210
259
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
260
|
+
# If the socket disconnected on data send
|
|
261
|
+
if error_on_send:
|
|
262
|
+
error_message = f"Service socket closed on data send: {error_on_send}"
|
|
263
|
+
|
|
264
|
+
# We'll close the socket and nullify the object
|
|
265
|
+
self.close_socket()
|
|
214
266
|
|
|
215
|
-
# We'll close the socket and nullify the object
|
|
216
|
-
self.close_socket()
|
|
217
267
|
# Else if send was successful
|
|
218
|
-
|
|
219
|
-
|
|
268
|
+
if not error_on_send:
|
|
269
|
+
origin_data, is_socket_closed, error_message = Receiver(
|
|
270
|
+
ssl_socket=self.socket_instance, logger=self.logger).receive()
|
|
220
271
|
|
|
221
272
|
# If data received is empty meaning the socket was closed on the other side
|
|
222
|
-
if not
|
|
223
|
-
|
|
273
|
+
if not origin_data:
|
|
274
|
+
error_message = "Service server closed the connection on receive"
|
|
224
275
|
|
|
225
276
|
# We'll close the socket and nullify the object
|
|
226
277
|
self.close_socket()
|
|
227
278
|
|
|
228
|
-
return
|
|
279
|
+
return origin_data, error_message, self.connection_ip, self.socket_instance
|
|
229
280
|
|
|
230
281
|
def send_receive_message_list_with_interval(
|
|
231
282
|
self, requests_bytes_list: list, intervals_list: list, intervals_defaults: int, cycles: int = 1):
|
|
@@ -298,15 +349,15 @@ class SocketClient:
|
|
|
298
349
|
# be passed.
|
|
299
350
|
# If there was connection error or socket close, then "ssl_socket" of the "service_client"
|
|
300
351
|
# will be empty.
|
|
301
|
-
response_raw_bytes,
|
|
352
|
+
response_raw_bytes, error_message, self.connection_ip, service_ssl_socket = \
|
|
302
353
|
self.send_receive_to_service(request_raw_bytes)
|
|
303
354
|
|
|
304
355
|
# Adding the response to responses list. Same for error.
|
|
305
356
|
responses_list.append(response_raw_bytes)
|
|
306
|
-
errors_list.append(
|
|
357
|
+
errors_list.append(error_message)
|
|
307
358
|
|
|
308
359
|
self.logger.info(f"Response: {response_raw_bytes}")
|
|
309
|
-
self.logger.info(f"Error: {
|
|
360
|
+
self.logger.info(f"Error: {error_message}")
|
|
310
361
|
|
|
311
362
|
# So if the socket was closed and there was an error we can break the loop.
|
|
312
363
|
# This is needed for more complex operations
|
|
@@ -323,9 +374,9 @@ class SocketClient:
|
|
|
323
374
|
self,
|
|
324
375
|
save_as_file: bool = False,
|
|
325
376
|
cert_file_path: str = None,
|
|
326
|
-
cert_output_type:
|
|
377
|
+
cert_output_type: Literal['der', 'cryptography'] = 'der',
|
|
327
378
|
**kwargs
|
|
328
|
-
):
|
|
379
|
+
) -> Union[x509.Certificate]:
|
|
329
380
|
"""
|
|
330
381
|
This function will get the certificate from the server and return it.
|
|
331
382
|
|
|
@@ -339,21 +390,12 @@ class SocketClient:
|
|
|
339
390
|
# If "save_as_file" is True, then "cert_file_path" must be provided, if not, raise an exception.
|
|
340
391
|
if save_as_file and not cert_file_path:
|
|
341
392
|
raise ValueError("If 'save_as_file' is True, then 'cert_file_path' must be provided.")
|
|
342
|
-
# If 'save_as_file' is True and 'cert_file_path' is provided, then check if the file exists.
|
|
343
|
-
# Since there is no point fetching the certificate from the socket if it already exists.
|
|
344
|
-
elif save_as_file and cert_file_path:
|
|
345
|
-
# If certificate from socket exists, then we don't need to get it from the socket and write to file.
|
|
346
|
-
# and we will return None, since no certificate was fetched.
|
|
347
|
-
if filesystem.check_file_existence(cert_file_path):
|
|
348
|
-
return None
|
|
349
|
-
else:
|
|
350
|
-
print_api("Certificate from socket doesn't exist, fetching.", logger=self.logger)
|
|
351
393
|
|
|
352
394
|
# Connect and get the connected socket.
|
|
353
|
-
server_socket_for_certificate = self.service_connection()
|
|
395
|
+
server_socket_for_certificate, error_message = self.service_connection()
|
|
354
396
|
# Get the DER byte certificate from the socket.
|
|
355
397
|
certificate_from_socket_der_bytes = ssl_base.get_certificate_from_socket(server_socket_for_certificate)
|
|
356
|
-
print_api('Fetched certificate from socket.', logger=self.logger, **kwargs)
|
|
398
|
+
print_api.print_api('Fetched certificate from socket.', logger=self.logger, **kwargs)
|
|
357
399
|
# Close the socket.
|
|
358
400
|
self.close_socket()
|
|
359
401
|
|
|
@@ -3,7 +3,7 @@ import threading
|
|
|
3
3
|
from .socket_client import SocketClient
|
|
4
4
|
from ..configparserw import ConfigParserWrapper
|
|
5
5
|
from ..loggingw import loggingw
|
|
6
|
-
from ...
|
|
6
|
+
from ... import filesystem
|
|
7
7
|
from ...file_io import jsons, file_io
|
|
8
8
|
|
|
9
9
|
|
|
@@ -37,7 +37,7 @@ def get_key_values_from_json(json_dict: dict, extract_keys: list):
|
|
|
37
37
|
def execute_test(config_static):
|
|
38
38
|
# Import config ini file and read it to dict.
|
|
39
39
|
config_importer = ConfigParserWrapper(
|
|
40
|
-
file_name=config_static.CONFIG_INI_TESTER_FILE_NAME, directory_path=config_static.
|
|
40
|
+
file_name=config_static.CONFIG_INI_TESTER_FILE_NAME, directory_path=config_static.SCRIPT_DIRECTORY)
|
|
41
41
|
config_importer.read_to_dict()
|
|
42
42
|
# Convert keys.
|
|
43
43
|
config_importer.convert_string_values(
|
|
@@ -54,17 +54,21 @@ def execute_test(config_static):
|
|
|
54
54
|
config = config_importer.config['config']
|
|
55
55
|
|
|
56
56
|
# SocketClient is working with 'network' logger by default, so we will initialize it.
|
|
57
|
-
loggingw.
|
|
57
|
+
loggingw.create_logger(
|
|
58
|
+
logger_name="network",
|
|
59
|
+
add_stream=True,
|
|
60
|
+
formatter_streamhandler='DEFAULT'
|
|
61
|
+
)
|
|
58
62
|
|
|
59
63
|
# Get all the files in requests folder recursively.
|
|
60
|
-
request_file_list =
|
|
64
|
+
request_file_list = filesystem.get_paths_from_directory(config['requests_directory'], get_file=True)
|
|
61
65
|
print(f"Found request files: {len(request_file_list)}")
|
|
62
66
|
|
|
63
67
|
# Get contents of all request files to list of contents.
|
|
64
68
|
requests_bytes_list: list = list()
|
|
65
69
|
for request_file_path in request_file_list:
|
|
66
70
|
if config['request_type'] == 'json':
|
|
67
|
-
request_file_content = jsons.read_json_file(request_file_path)
|
|
71
|
+
request_file_content = jsons.read_json_file(request_file_path.path)
|
|
68
72
|
|
|
69
73
|
# If imported json is regular and not combined json.
|
|
70
74
|
if isinstance(request_file_content, dict):
|
|
@@ -79,13 +83,13 @@ def execute_test(config_static):
|
|
|
79
83
|
requests_bytes_list.extend(
|
|
80
84
|
get_key_values_from_json(json_dict, config['request_json_hex_key_list']))
|
|
81
85
|
elif config['request_type'] == 'string':
|
|
82
|
-
request_file_content = file_io.read_file(request_file_path)
|
|
86
|
+
request_file_content = file_io.read_file(request_file_path.path)
|
|
83
87
|
# Convert string content to bytes and append to list.
|
|
84
88
|
requests_bytes_list.append(request_file_content.encode())
|
|
85
89
|
print(f"Extracted 1 request.")
|
|
86
90
|
elif config['request_type'] == 'binary':
|
|
87
91
|
# The content is already in bytes, so just appending.
|
|
88
|
-
requests_bytes_list.append(file_io.read_file(request_file_path, 'rb'))
|
|
92
|
+
requests_bytes_list.append(file_io.read_file(request_file_path.path, 'rb'))
|
|
89
93
|
print(f"Extracted 1 request.")
|
|
90
94
|
|
|
91
95
|
print(f"Finished parsing. Parsed requests: {len(requests_bytes_list)}")
|
|
@@ -117,10 +121,11 @@ def execute_test(config_static):
|
|
|
117
121
|
requests_bytes_list,
|
|
118
122
|
config['interval_between_request_custom_list_seconds'],
|
|
119
123
|
config['interval_between_requests_defaults_seconds'],))
|
|
120
|
-
|
|
121
|
-
threads_list.append(thread_current)
|
|
124
|
+
thread_current.daemon = True
|
|
122
125
|
# Start the thread
|
|
123
126
|
thread_current.start()
|
|
127
|
+
# Append to list of threads, so they can be "joined" later
|
|
128
|
+
threads_list.append(thread_current)
|
|
124
129
|
|
|
125
130
|
# Joining all the threads.
|
|
126
131
|
for thread in threads_list:
|