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.
Files changed (268) hide show
  1. atomicshop/__init__.py +1 -1
  2. atomicshop/{addons/mains → a_mains}/FACT/update_extract.py +3 -2
  3. atomicshop/a_mains/addons/process_list/compile.cmd +7 -0
  4. atomicshop/a_mains/addons/process_list/compiled/Win10x64/process_list.dll +0 -0
  5. atomicshop/a_mains/addons/process_list/compiled/Win10x64/process_list.exp +0 -0
  6. atomicshop/a_mains/addons/process_list/compiled/Win10x64/process_list.lib +0 -0
  7. atomicshop/{addons → a_mains/addons}/process_list/process_list.cpp +8 -1
  8. atomicshop/a_mains/dns_gateway_setting.py +11 -0
  9. atomicshop/a_mains/get_local_tcp_ports.py +85 -0
  10. atomicshop/a_mains/github_wrapper.py +11 -0
  11. atomicshop/a_mains/install_ca_certificate.py +172 -0
  12. atomicshop/{addons/mains → a_mains}/msi_unpacker.py +3 -1
  13. atomicshop/a_mains/process_from_port.py +119 -0
  14. atomicshop/a_mains/set_default_dns_gateway.py +90 -0
  15. atomicshop/a_mains/update_config_toml.py +38 -0
  16. atomicshop/appointment_management.py +5 -3
  17. atomicshop/basics/ansi_escape_codes.py +3 -1
  18. atomicshop/basics/argparse_template.py +2 -0
  19. atomicshop/basics/booleans.py +27 -30
  20. atomicshop/basics/bytes_arrays.py +43 -0
  21. atomicshop/basics/classes.py +149 -1
  22. atomicshop/basics/dicts.py +12 -0
  23. atomicshop/basics/enums.py +2 -2
  24. atomicshop/basics/exceptions.py +5 -1
  25. atomicshop/basics/list_of_classes.py +29 -0
  26. atomicshop/basics/list_of_dicts.py +69 -5
  27. atomicshop/basics/lists.py +14 -0
  28. atomicshop/basics/multiprocesses.py +374 -50
  29. atomicshop/basics/package_module.py +10 -0
  30. atomicshop/basics/strings.py +160 -7
  31. atomicshop/basics/threads.py +14 -0
  32. atomicshop/basics/tracebacks.py +13 -4
  33. atomicshop/certificates.py +153 -52
  34. atomicshop/config_init.py +12 -7
  35. atomicshop/console_user_response.py +7 -14
  36. atomicshop/consoles.py +9 -0
  37. atomicshop/datetimes.py +98 -0
  38. atomicshop/diff_check.py +340 -40
  39. atomicshop/dns.py +128 -12
  40. atomicshop/etws/_pywintrace_fix.py +17 -0
  41. atomicshop/etws/const.py +38 -0
  42. atomicshop/etws/providers.py +21 -0
  43. atomicshop/etws/sessions.py +43 -0
  44. atomicshop/etws/trace.py +168 -0
  45. atomicshop/etws/traces/trace_dns.py +162 -0
  46. atomicshop/etws/traces/trace_sysmon_process_creation.py +126 -0
  47. atomicshop/etws/traces/trace_tcp.py +130 -0
  48. atomicshop/file_io/csvs.py +222 -24
  49. atomicshop/file_io/docxs.py +35 -18
  50. atomicshop/file_io/file_io.py +35 -19
  51. atomicshop/file_io/jsons.py +49 -0
  52. atomicshop/file_io/tomls.py +139 -0
  53. atomicshop/filesystem.py +864 -293
  54. atomicshop/get_process_list.py +133 -0
  55. atomicshop/{process_name_cmd.py → get_process_name_cmd_dll.py} +52 -19
  56. atomicshop/http_parse.py +149 -93
  57. atomicshop/ip_addresses.py +6 -1
  58. atomicshop/mitm/centered_settings.py +132 -0
  59. atomicshop/mitm/config_static.py +207 -0
  60. atomicshop/mitm/config_toml_editor.py +55 -0
  61. atomicshop/mitm/connection_thread_worker.py +875 -357
  62. atomicshop/mitm/engines/__parent/parser___parent.py +4 -17
  63. atomicshop/mitm/engines/__parent/recorder___parent.py +108 -51
  64. atomicshop/mitm/engines/__parent/requester___parent.py +116 -0
  65. atomicshop/mitm/engines/__parent/responder___parent.py +75 -114
  66. atomicshop/mitm/engines/__reference_general/parser___reference_general.py +10 -7
  67. atomicshop/mitm/engines/__reference_general/recorder___reference_general.py +5 -5
  68. atomicshop/mitm/engines/__reference_general/requester___reference_general.py +47 -0
  69. atomicshop/mitm/engines/__reference_general/responder___reference_general.py +95 -13
  70. atomicshop/mitm/engines/create_module_template.py +58 -14
  71. atomicshop/mitm/import_config.py +359 -139
  72. atomicshop/mitm/initialize_engines.py +160 -74
  73. atomicshop/mitm/message.py +64 -23
  74. atomicshop/mitm/mitm_main.py +892 -0
  75. atomicshop/mitm/recs_files.py +183 -0
  76. atomicshop/mitm/shared_functions.py +4 -10
  77. atomicshop/mitm/ssh_tester.py +82 -0
  78. atomicshop/mitm/statistic_analyzer.py +257 -166
  79. atomicshop/mitm/statistic_analyzer_helper/analyzer_helper.py +136 -0
  80. atomicshop/mitm/statistic_analyzer_helper/moving_average_helper.py +525 -0
  81. atomicshop/monitor/change_monitor.py +96 -120
  82. atomicshop/monitor/checks/dns.py +139 -70
  83. atomicshop/monitor/checks/file.py +77 -0
  84. atomicshop/monitor/checks/network.py +81 -77
  85. atomicshop/monitor/checks/process_running.py +33 -34
  86. atomicshop/monitor/checks/url.py +94 -0
  87. atomicshop/networks.py +671 -0
  88. atomicshop/on_exit.py +205 -0
  89. atomicshop/package_mains_processor.py +84 -0
  90. atomicshop/permissions/permissions.py +22 -0
  91. atomicshop/permissions/ubuntu_permissions.py +239 -0
  92. atomicshop/permissions/win_permissions.py +33 -0
  93. atomicshop/print_api.py +24 -41
  94. atomicshop/process.py +63 -17
  95. atomicshop/process_poller/__init__.py +0 -0
  96. atomicshop/process_poller/pollers/__init__.py +0 -0
  97. atomicshop/process_poller/pollers/psutil_pywin32wmi_dll.py +95 -0
  98. atomicshop/process_poller/process_pool.py +207 -0
  99. atomicshop/process_poller/simple_process_pool.py +311 -0
  100. atomicshop/process_poller/tracer_base.py +45 -0
  101. atomicshop/process_poller/tracers/__init__.py +0 -0
  102. atomicshop/process_poller/tracers/event_log.py +46 -0
  103. atomicshop/process_poller/tracers/sysmon_etw.py +68 -0
  104. atomicshop/python_file_patcher.py +1 -1
  105. atomicshop/python_functions.py +27 -75
  106. atomicshop/question_answer_engine.py +2 -2
  107. atomicshop/scheduling.py +24 -5
  108. atomicshop/sound.py +4 -2
  109. atomicshop/speech_recognize.py +8 -0
  110. atomicshop/ssh_remote.py +158 -172
  111. atomicshop/startup/__init__.py +0 -0
  112. atomicshop/startup/win/__init__.py +0 -0
  113. atomicshop/startup/win/startup_folder.py +53 -0
  114. atomicshop/startup/win/task_scheduler.py +119 -0
  115. atomicshop/system_resource_monitor.py +61 -46
  116. atomicshop/system_resources.py +8 -8
  117. atomicshop/tempfiles.py +1 -2
  118. atomicshop/timer.py +30 -11
  119. atomicshop/urls.py +41 -0
  120. atomicshop/venvs.py +28 -0
  121. atomicshop/versioning.py +27 -0
  122. atomicshop/web.py +110 -25
  123. atomicshop/web_apis/__init__.py +0 -0
  124. atomicshop/web_apis/google_custom_search.py +44 -0
  125. atomicshop/web_apis/google_llm.py +188 -0
  126. atomicshop/websocket_parse.py +450 -0
  127. atomicshop/wrappers/certauthw/certauth.py +1 -0
  128. atomicshop/wrappers/cryptographyw.py +29 -8
  129. atomicshop/wrappers/ctyping/etw_winapi/__init__.py +0 -0
  130. atomicshop/wrappers/ctyping/etw_winapi/const.py +335 -0
  131. atomicshop/wrappers/ctyping/etw_winapi/etw_functions.py +393 -0
  132. atomicshop/wrappers/ctyping/file_details_winapi.py +67 -0
  133. atomicshop/wrappers/ctyping/msi_windows_installer/cabs.py +2 -1
  134. atomicshop/wrappers/ctyping/msi_windows_installer/extract_msi_main.py +13 -9
  135. atomicshop/wrappers/ctyping/msi_windows_installer/tables.py +35 -0
  136. atomicshop/wrappers/ctyping/setup_device.py +466 -0
  137. atomicshop/wrappers/ctyping/win_console.py +39 -0
  138. atomicshop/wrappers/dockerw/dockerw.py +113 -2
  139. atomicshop/wrappers/elasticsearchw/config_basic.py +0 -12
  140. atomicshop/wrappers/elasticsearchw/elastic_infra.py +75 -0
  141. atomicshop/wrappers/elasticsearchw/elasticsearchw.py +2 -20
  142. atomicshop/wrappers/factw/get_file_data.py +12 -5
  143. atomicshop/wrappers/factw/install/install_after_restart.py +89 -5
  144. atomicshop/wrappers/factw/install/pre_install_and_install_before_restart.py +20 -14
  145. atomicshop/wrappers/factw/postgresql/firmware.py +4 -6
  146. atomicshop/wrappers/githubw.py +583 -51
  147. atomicshop/wrappers/loggingw/consts.py +49 -0
  148. atomicshop/wrappers/loggingw/filters.py +102 -0
  149. atomicshop/wrappers/loggingw/formatters.py +58 -71
  150. atomicshop/wrappers/loggingw/handlers.py +459 -40
  151. atomicshop/wrappers/loggingw/loggers.py +19 -0
  152. atomicshop/wrappers/loggingw/loggingw.py +1010 -178
  153. atomicshop/wrappers/loggingw/reading.py +344 -19
  154. atomicshop/wrappers/mongodbw/__init__.py +0 -0
  155. atomicshop/wrappers/mongodbw/mongo_infra.py +31 -0
  156. atomicshop/wrappers/mongodbw/mongodbw.py +1432 -0
  157. atomicshop/wrappers/netshw.py +271 -0
  158. atomicshop/wrappers/playwrightw/engine.py +34 -19
  159. atomicshop/wrappers/playwrightw/infra.py +5 -0
  160. atomicshop/wrappers/playwrightw/javascript.py +7 -3
  161. atomicshop/wrappers/playwrightw/keyboard.py +14 -0
  162. atomicshop/wrappers/playwrightw/scenarios.py +172 -5
  163. atomicshop/wrappers/playwrightw/waits.py +9 -7
  164. atomicshop/wrappers/powershell_networking.py +80 -0
  165. atomicshop/wrappers/psutilw/processes.py +81 -0
  166. atomicshop/wrappers/psutilw/psutil_networks.py +85 -0
  167. atomicshop/wrappers/psutilw/psutilw.py +9 -0
  168. atomicshop/wrappers/pyopensslw.py +9 -2
  169. atomicshop/wrappers/pywin32w/__init__.py +0 -0
  170. atomicshop/wrappers/pywin32w/cert_store.py +116 -0
  171. atomicshop/wrappers/pywin32w/console.py +34 -0
  172. atomicshop/wrappers/pywin32w/win_event_log/__init__.py +0 -0
  173. atomicshop/wrappers/pywin32w/win_event_log/fetch.py +174 -0
  174. atomicshop/wrappers/pywin32w/win_event_log/subscribe.py +212 -0
  175. atomicshop/wrappers/pywin32w/win_event_log/subscribes/__init__.py +0 -0
  176. atomicshop/wrappers/pywin32w/win_event_log/subscribes/process_create.py +57 -0
  177. atomicshop/wrappers/pywin32w/win_event_log/subscribes/process_terminate.py +49 -0
  178. atomicshop/wrappers/pywin32w/win_event_log/subscribes/schannel_logging.py +97 -0
  179. atomicshop/wrappers/pywin32w/winshell.py +19 -0
  180. atomicshop/wrappers/pywin32w/wmis/__init__.py +0 -0
  181. atomicshop/wrappers/pywin32w/wmis/msft_netipaddress.py +113 -0
  182. atomicshop/wrappers/pywin32w/wmis/win32_networkadapterconfiguration.py +259 -0
  183. atomicshop/wrappers/pywin32w/wmis/win32networkadapter.py +112 -0
  184. atomicshop/wrappers/pywin32w/wmis/wmi_helpers.py +236 -0
  185. atomicshop/wrappers/socketw/accepter.py +21 -7
  186. atomicshop/wrappers/socketw/certificator.py +216 -150
  187. atomicshop/wrappers/socketw/creator.py +190 -50
  188. atomicshop/wrappers/socketw/dns_server.py +500 -173
  189. atomicshop/wrappers/socketw/exception_wrapper.py +45 -52
  190. atomicshop/wrappers/socketw/process_getter.py +86 -0
  191. atomicshop/wrappers/socketw/receiver.py +144 -102
  192. atomicshop/wrappers/socketw/sender.py +65 -35
  193. atomicshop/wrappers/socketw/sni.py +334 -165
  194. atomicshop/wrappers/socketw/socket_base.py +134 -0
  195. atomicshop/wrappers/socketw/socket_client.py +137 -95
  196. atomicshop/wrappers/socketw/socket_server_tester.py +14 -9
  197. atomicshop/wrappers/socketw/socket_wrapper.py +717 -116
  198. atomicshop/wrappers/socketw/ssl_base.py +15 -14
  199. atomicshop/wrappers/socketw/statistics_csv.py +148 -17
  200. atomicshop/wrappers/sysmonw.py +157 -0
  201. atomicshop/wrappers/ubuntu_terminal.py +65 -26
  202. atomicshop/wrappers/win_auditw.py +189 -0
  203. atomicshop/wrappers/winregw/__init__.py +0 -0
  204. atomicshop/wrappers/winregw/winreg_installed_software.py +58 -0
  205. atomicshop/wrappers/winregw/winreg_network.py +232 -0
  206. {atomicshop-2.11.47.dist-info → atomicshop-3.10.5.dist-info}/METADATA +31 -49
  207. atomicshop-3.10.5.dist-info/RECORD +306 -0
  208. {atomicshop-2.11.47.dist-info → atomicshop-3.10.5.dist-info}/WHEEL +1 -1
  209. atomicshop/_basics_temp.py +0 -101
  210. atomicshop/addons/a_setup_scripts/install_psycopg2_ubuntu.sh +0 -3
  211. atomicshop/addons/a_setup_scripts/install_pywintrace_0.3.cmd +0 -2
  212. atomicshop/addons/mains/install_docker_rootless_ubuntu.py +0 -11
  213. atomicshop/addons/mains/install_docker_ubuntu_main_sudo.py +0 -11
  214. atomicshop/addons/mains/install_elastic_search_and_kibana_ubuntu.py +0 -10
  215. atomicshop/addons/mains/install_wsl_ubuntu_lts_admin.py +0 -9
  216. atomicshop/addons/package_setup/CreateWheel.cmd +0 -7
  217. atomicshop/addons/package_setup/Setup in Edit mode.cmd +0 -6
  218. atomicshop/addons/package_setup/Setup.cmd +0 -7
  219. atomicshop/addons/process_list/compile.cmd +0 -2
  220. atomicshop/addons/process_list/compiled/Win10x64/process_list.dll +0 -0
  221. atomicshop/addons/process_list/compiled/Win10x64/process_list.exp +0 -0
  222. atomicshop/addons/process_list/compiled/Win10x64/process_list.lib +0 -0
  223. atomicshop/archiver/_search_in_zip.py +0 -189
  224. atomicshop/archiver/archiver.py +0 -34
  225. atomicshop/archiver/search_in_archive.py +0 -250
  226. atomicshop/archiver/sevenz_app_w.py +0 -86
  227. atomicshop/archiver/sevenzs.py +0 -44
  228. atomicshop/archiver/zips.py +0 -293
  229. atomicshop/etw/dns_trace.py +0 -118
  230. atomicshop/etw/etw.py +0 -61
  231. atomicshop/file_types.py +0 -24
  232. atomicshop/mitm/engines/create_module_template_example.py +0 -13
  233. atomicshop/mitm/initialize_mitm_server.py +0 -240
  234. atomicshop/monitor/checks/hash.py +0 -44
  235. atomicshop/monitor/checks/hash_checks/file.py +0 -55
  236. atomicshop/monitor/checks/hash_checks/url.py +0 -62
  237. atomicshop/pbtkmultifile_argparse.py +0 -88
  238. atomicshop/permissions.py +0 -110
  239. atomicshop/process_poller.py +0 -237
  240. atomicshop/script_as_string_processor.py +0 -38
  241. atomicshop/ssh_scripts/process_from_ipv4.py +0 -37
  242. atomicshop/ssh_scripts/process_from_port.py +0 -27
  243. atomicshop/wrappers/_process_wrapper_curl.py +0 -27
  244. atomicshop/wrappers/_process_wrapper_tar.py +0 -21
  245. atomicshop/wrappers/dockerw/install_docker.py +0 -209
  246. atomicshop/wrappers/elasticsearchw/infrastructure.py +0 -265
  247. atomicshop/wrappers/elasticsearchw/install_elastic.py +0 -232
  248. atomicshop/wrappers/ffmpegw.py +0 -125
  249. atomicshop/wrappers/loggingw/checks.py +0 -20
  250. atomicshop/wrappers/nodejsw/install_nodejs.py +0 -139
  251. atomicshop/wrappers/process_wrapper_pbtk.py +0 -16
  252. atomicshop/wrappers/socketw/base.py +0 -59
  253. atomicshop/wrappers/socketw/get_process.py +0 -107
  254. atomicshop/wrappers/wslw.py +0 -191
  255. atomicshop-2.11.47.dist-info/RECORD +0 -251
  256. /atomicshop/{addons/mains → a_mains}/FACT/factw_fact_extractor_docker_image_main_sudo.py +0 -0
  257. /atomicshop/{addons → a_mains/addons}/PlayWrightCodegen.cmd +0 -0
  258. /atomicshop/{addons → a_mains/addons}/ScriptExecution.cmd +0 -0
  259. /atomicshop/{addons/mains → a_mains/addons}/inits/init_to_import_all_modules.py +0 -0
  260. /atomicshop/{addons → a_mains/addons}/process_list/ReadMe.txt +0 -0
  261. /atomicshop/{addons/mains → a_mains}/search_for_hyperlinks_in_docx.py +0 -0
  262. /atomicshop/{archiver → etws}/__init__.py +0 -0
  263. /atomicshop/{etw → etws/traces}/__init__.py +0 -0
  264. /atomicshop/{monitor/checks/hash_checks → mitm/statistic_analyzer_helper}/__init__.py +0 -0
  265. /atomicshop/{wrappers/nodejsw → permissions}/__init__.py +0 -0
  266. /atomicshop/wrappers/pywin32w/{wmi_win32process.py → wmis/win32process.py} +0 -0
  267. {atomicshop-2.11.47.dist-info → atomicshop-3.10.5.dist-info/licenses}/LICENSE.txt +0 -0
  268. {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 ...print_api import print_api
19
+ from ... import print_api
12
20
  from ...file_io import file_io
13
- from ... import filesystem
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, service_port: int, tls: bool = False, connection_ip=None, dns_servers_list=None):
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
- self.logger.info(f"Creating non-SSL socket to [{self.service_name}:{self.service_port}]")
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
- self.logger.info(f"Creating SSL socket to [{self.service_name}:{self.service_port}]")
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
- def service_connection(self):
74
- """ Function to establish connection to server """
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
- # set it True, or the socket object will be nullified in the next step.
94
- return True
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
- self.logger.error(f"Domain {self.service_name} doesn't exist - Couldn't resolve with "
114
- f"{self.dns_servers_list}.")
115
- pass
116
- return None
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 ConnectionRefusedError:
132
- message = f"Couldn't connect to: {self.service_name}. The server is unreachable - Connection refused."
133
- print_api(message, logger=self.logger, logger_method='error', traceback_string=True, oneline=True)
134
- # Socket close will be handled in the thread_worker_main
135
- pass
136
- return None
137
- except ConnectionAbortedError:
138
- message = f"Connection was aborted (by the software on host) to {self.service_name}."
139
- print_api(message, logger=self.logger, logger_method='error', traceback_string=True, oneline=True)
140
- # Socket close will be handled in the thread_worker_main
141
- pass
142
- return None
143
- except socket.gaierror:
144
- message = f"Couldn't resolve [{self.service_name}] to IP using default methods. " \
145
- f"Domain doesn't exist or there's no IP assigned to it."
146
- print_api(message, logger=self.logger, logger_method='error', traceback_string=True, oneline=True)
147
- # Socket close will be handled in the thread_worker_main
148
- pass
149
- return None
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
- # noinspection PyUnusedLocal
184
- def send_receive_to_service(self, request_bytes: bytearray):
185
- # Define variables
186
- function_service_data = None
187
- error_string = None
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
- # If connection to service server wasn't successful
190
- if not self.service_connection():
191
- error_string = "Wasn't able to connect to service, closing the destination service socket"
192
- print_api(error_string, logger=self.logger, logger_method='error')
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
- # We'll close the socket and nullify the object
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
- # Send the data received from the client to the service over socket
209
- function_data_sent = Sender(self.socket_instance, request_bytes).send()
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
- # If the socket disconnected on data send
212
- if not function_data_sent:
213
- error_string = "Service socket closed on data send"
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
- else:
219
- function_service_data = Receiver(self.socket_instance).receive()
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 function_service_data:
223
- error_string = "Service server closed the connection on receive"
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 function_service_data, error_string, self.connection_ip, self.socket_instance
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, error_string, self.connection_ip, service_ssl_socket = \
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(error_string)
357
+ errors_list.append(error_message)
307
358
 
308
359
  self.logger.info(f"Response: {response_raw_bytes}")
309
- self.logger.info(f"Error: {error_string}")
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: str = 'der',
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 ...filesystem import get_file_paths_from_directory
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.WORKING_DIRECTORY)
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.get_logger_with_stream_handler("network")
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 = get_file_paths_from_directory(config['requests_directory'])
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
- # Append to list of threads, so they can be "joined" later
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: