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,7 +1,7 @@
1
1
  import ssl
2
2
  import functools
3
3
 
4
- from . import base
4
+ from . import socket_base
5
5
  from ...print_api import print_api
6
6
  from ...inspect_wrapper import get_target_function_default_args_and_combine_with_current
7
7
 
@@ -14,7 +14,13 @@ def connection_exception_decorator(function_name):
14
14
  args, kwargs = get_target_function_default_args_and_combine_with_current(function_name, *args, **kwargs)
15
15
 
16
16
  wrapper_handle_connection_exceptions.message = None
17
- port = kwargs['socket_object'].getsockname()[1]
17
+ listen_ipv4, port = kwargs['socket_object'].getsockname()
18
+
19
+ domain_from_dns_server = kwargs['domain_from_dns_server']
20
+ if not domain_from_dns_server:
21
+ # If the domain is not passed, we will use the TCP data.
22
+ # This is needed for the decorator to work properly.
23
+ domain_from_dns_server = listen_ipv4
18
24
 
19
25
  try:
20
26
  # Since our 'kwargs' has already all the needed arguments, we don't need 'args'.
@@ -24,17 +30,15 @@ def connection_exception_decorator(function_name):
24
30
  # After that second exception will be "pass"-ed. This is an exception inside an exception handling.
25
31
  # Looks like was introduced in Python 3 in PEP 3134.
26
32
  except ConnectionAbortedError:
27
- message = f"Socket Accept: {kwargs['dns_domain']}:{port}: " \
33
+ message = f"Socket Accept: {domain_from_dns_server}:{port}: " \
28
34
  f"* Established connection was aborted by software on the host..."
29
35
  wrapper_handle_connection_exceptions.message = message
30
36
  print_api(message, logger_method='error', traceback_string=True, oneline=True, **kwargs['print_kwargs'])
31
- pass
32
37
  except ConnectionResetError:
33
- message = f"Socket Accept: {kwargs['dns_domain']}:{port}: " \
38
+ message = f"Socket Accept: {domain_from_dns_server}:{port}: " \
34
39
  f"* An existing connection was forcibly closed by the remote host..."
35
40
  wrapper_handle_connection_exceptions.message = message
36
41
  print_api(message, logger_method='error', traceback_string=True, oneline=True, **kwargs['print_kwargs'])
37
- pass
38
42
  except ssl.SSLEOFError as e:
39
43
  # A subclass of SSLError raised when the SSL connection has been terminated abruptly. Generally, you
40
44
  # shouldn't try to reuse the underlying transport when this error is encountered.
@@ -45,10 +49,11 @@ def connection_exception_decorator(function_name):
45
49
  wrapper_handle_connection_exceptions.message = message
46
50
  try:
47
51
  message = \
48
- f"Socket Accept: {kwargs['dns_domain']}:{port}: {message}"
52
+ f"Socket Accept: {domain_from_dns_server}:{port}: {message}"
49
53
  wrapper_handle_connection_exceptions.message = message
50
- print_api(message, error_type=True, logger_method='error', **kwargs['print_kwargs'])
51
- except Exception:
54
+ print_api(message, error_type=True, logger_method='error', oneline=True, **kwargs['print_kwargs'])
55
+ except Exception as e:
56
+ _ = e
52
57
  message = f"Socket Accept: port {port}: {message}"
53
58
  wrapper_handle_connection_exceptions.message = message
54
59
  print_api(message, logger_method='error', traceback_string=True, oneline=True, **kwargs['print_kwargs'])
@@ -59,36 +64,36 @@ def connection_exception_decorator(function_name):
59
64
  wrapper_handle_connection_exceptions.message = message
60
65
  try:
61
66
  message = \
62
- f"Socket Accept: {kwargs['dns_domain']}:{port}: {message}"
67
+ f"Socket Accept: {domain_from_dns_server}:{port}: {message}"
63
68
  wrapper_handle_connection_exceptions.message = message
64
- print_api(message, logger_method='error', **kwargs['print_kwargs'])
65
- except Exception:
69
+ print_api(message, logger_method='error', oneline=True, **kwargs['print_kwargs'])
70
+ except Exception as e:
71
+ _ = e
66
72
  message = f"Socket Accept: port {port}: {message}"
67
73
  wrapper_handle_connection_exceptions.message = message
68
74
  print_api(message, logger_method='error', traceback_string=True, oneline=True, **kwargs['print_kwargs'])
69
75
  pass
70
76
  pass
71
77
  except ssl.SSLError as exception_object:
72
- # Getting the exact reason of "ssl.SSLError"
73
- if exception_object.reason == "HTTP_REQUEST":
74
- message = f"Socket Accept: HTTP Request on SSL Socket: " \
75
- f"{base.get_source_destination(kwargs['socket_object'])}"
76
- wrapper_handle_connection_exceptions.message = message
77
- print_api(message, logger_method='error', traceback_string=True, oneline=True, **kwargs['print_kwargs'])
78
- elif exception_object.reason == "TSV1_ALERT_UNKNOWN_CA":
79
- message = f"Socket Accept: Check CA certificate on the client " \
80
- f"{base.get_source_destination(kwargs['socket_object'])}"
81
- wrapper_handle_connection_exceptions.message = message
82
- print_api(message, logger_method='error', traceback_string=True, oneline=True, **kwargs['print_kwargs'])
83
- # elif exception_object.reason == "SSLV3_ALERT_CERTIFICATE_UNKNOWN":
84
- # message = f"ssl.SSLError:{exception_object}"
85
- # message = f"Socket Accept: {domain_name}:{socket_object.getsockname()[1]}: {message}"
86
- # print_api(message, logger=self.logger, logger_method='error', traceback_string=True, oneline=True)
87
- # elif exception_object.reason == "NO_SHARED_CIPHER":
88
- # message = f"ssl.SSLError:{exception_object}"
89
- # message = f"Socket Accept: {domain_name}:{socket_object.getsockname()[1]}: {message}"
90
- # print_api(message, logger=self.logger, logger_method='error', traceback_string=True, oneline=True)
91
- else:
78
+ excepted: bool = False
79
+ if getattr(exception_object, "reason", None):
80
+ # Getting the exact reason of "ssl.SSLError"
81
+ if exception_object.reason == "HTTP_REQUEST":
82
+ message = f"Socket Accept: HTTP Request on SSL Socket: " \
83
+ f"{socket_base.get_source_destination(kwargs['socket_object'])}"
84
+ wrapper_handle_connection_exceptions.message = message
85
+ print_api(message, logger_method='error', traceback_string=True, oneline=True, **kwargs['print_kwargs'])
86
+
87
+ excepted = True
88
+ elif exception_object.reason == "TSV1_ALERT_UNKNOWN_CA":
89
+ message = f"Socket Accept: Check CA certificate on the client " \
90
+ f"{socket_base.get_source_destination(kwargs['socket_object'])}"
91
+ wrapper_handle_connection_exceptions.message = message
92
+ print_api(message, logger_method='error', traceback_string=True, oneline=True, **kwargs['print_kwargs'])
93
+
94
+ excepted = True
95
+
96
+ if not excepted:
92
97
  # Not all requests have the server name passed through Client Hello.
93
98
  # If it is not passed an error of undefined variable will be raised.
94
99
  # So, we'll check if the variable as a string is in the "locals()" variable pool.
@@ -96,39 +101,27 @@ def connection_exception_decorator(function_name):
96
101
 
97
102
  message = "SSLError on accept. Not documented..."
98
103
  wrapper_handle_connection_exceptions.message = message
99
- print_api(message, logger_method='error', **kwargs['print_kwargs'])
100
- # try:
101
- # message = f"Socket Accept: {domain_name}:{socket_object.getsockname()[1]}: {message}"
102
- # print_api(message, logger=self.logger, logger_method='error', traceback_string=True, oneline=True)
103
- # except Exception:
104
- # message = f"Socket Accept: port {socket_object.getsockname()[1]}: {message}"
105
- # print_api(message, logger=self.logger, logger_method='error', traceback_string=True, oneline=True)
106
- # pass
104
+ print_api(message, logger_method='error', oneline=True, **kwargs['print_kwargs'])
107
105
 
108
106
  message = f'ssl.SSLError:{exception_object}'
109
107
  wrapper_handle_connection_exceptions.message = message
110
108
  message = \
111
- f"Socket Accept: {kwargs['dns_domain']}:{port}: {message}"
109
+ f"Socket Accept: {domain_from_dns_server}:{port}: {message}"
112
110
  wrapper_handle_connection_exceptions.message = message
113
- print_api(message, logger_method='error', **kwargs['print_kwargs'])
114
- pass
111
+ print_api(message, logger_method='error', oneline=True, **kwargs['print_kwargs'])
112
+
115
113
  except FileNotFoundError:
116
114
  message = "'SSLSocket.accept()' crashed: 'FileNotFoundError'. Some problem with SSL during Handshake - " \
117
115
  "Could be certificate, client, or server."
118
- message = f"Socket Accept: {kwargs['dns_domain']}:{port}: {message}"
116
+ message = f"Socket Accept: {domain_from_dns_server}:{port}: {message}"
119
117
  wrapper_handle_connection_exceptions.message = message
120
118
  print_api(message, logger_method='error', traceback_string=True, oneline=True, **kwargs['print_kwargs'])
121
- # except Exception:
122
- # message = f"Socket Accept: port {socket_object.getsockname()[1]}: {message}"
123
- # print_api(message, logger=self.logger, logger_method='error', traceback_string=True, oneline=True)
124
- # pass
125
- pass
126
- except Exception:
119
+ except Exception as e:
120
+ _ = e
127
121
  message = "Undocumented exception on accept."
128
- message = f"Socket Accept: {kwargs['dns_domain']}:{port}: {message}"
122
+ message = f"Socket Accept: {domain_from_dns_server}:{port}: {message}"
129
123
  wrapper_handle_connection_exceptions.message = message
130
124
  print_api(message, logger_method='error', traceback_string=True, oneline=True, **kwargs['print_kwargs'])
131
- pass
132
125
 
133
126
  wrapper_handle_connection_exceptions.message = None
134
127
  return wrapper_handle_connection_exceptions
@@ -0,0 +1,86 @@
1
+ import logging
2
+
3
+ from . import socket_base
4
+ from ...print_api import print_api
5
+ from ...ssh_remote import SSHRemote
6
+ from ... import package_mains_processor
7
+
8
+
9
+ GET_LOCALHOST_FUNCTION_NAME = 'find_cmdline_by_port'
10
+
11
+
12
+ class GetCommandLine:
13
+ def __init__(
14
+ self,
15
+ client_ip: str,
16
+ client_port: int = None,
17
+ package_processor: package_mains_processor.PackageMainsProcessor = None,
18
+ ssh_client: SSHRemote = None,
19
+ logger: logging.Logger = None
20
+ ):
21
+ self.client_ip: str = client_ip
22
+ self.client_port: int = client_port
23
+ self.package_processor: package_mains_processor.PackageMainsProcessor = package_processor
24
+ self.ssh_client: SSHRemote = ssh_client
25
+ self.logger: logging.Logger = logger
26
+
27
+ def get_process_name(self, print_kwargs: dict = None):
28
+ if print_kwargs is None:
29
+ print_kwargs = {}
30
+
31
+ # Checking if we're on localhost. If not, we'll execute SSH connection to get calling process name.
32
+ if self.client_ip not in socket_base.THIS_DEVICE_IP_LIST:
33
+ # Tried using paramiko SSH concurrently within threads, but with bigger loads it just breaks.
34
+ # So, better using it separately for each thread.
35
+
36
+ print_api(f"Initializing SSH connection to [{self.client_ip}]", **print_kwargs)
37
+
38
+ script_string: str = self.package_processor.read_script_file_to_string()
39
+
40
+ execution_output, execution_error = self.ssh_client.connect_get_client_commandline(port=self.client_port, script_string=script_string)
41
+ # Else, if we're on localhost, then execute the script directly without SSH.
42
+ else:
43
+ print_api(f"Executing LOCALHOST command to get the calling process.", **print_kwargs)
44
+ # execution_output, execution_error, rc = self.package_processor.execute_script_with_subprocess(arguments=[str(client_port)])
45
+ execution_output = self.package_processor.execute_script_file(
46
+ function_name=GET_LOCALHOST_FUNCTION_NAME, args=(self.client_port,))
47
+ execution_error = None
48
+
49
+ # This section is generic for both remote SSH and localhost executions of the script.
50
+ process_name = self.get_commandline_and_error(execution_output, execution_error, print_kwargs=print_kwargs)
51
+
52
+ return process_name
53
+
54
+ @staticmethod
55
+ def get_commandline_and_error(
56
+ execution_output,
57
+ execution_error,
58
+ print_kwargs: dict = None
59
+ ):
60
+ # If there was known error on localhost / known error on remote or any kind of error on remote, it was
61
+ # already logged, so we'll just put the error into 'process_name'.
62
+ if execution_error:
63
+ process_name = execution_error
64
+ print_api(
65
+ f"Error During Command Execution: {process_name}", error_type=True,
66
+ logger_method='error', **(print_kwargs or {}))
67
+ # If there wasn't any error of above types, then we can put the output from either local or remote script
68
+ # execution into 'process_name' and log it / output to console.
69
+ else:
70
+ # If the output that was returned is not empty.
71
+ if execution_output:
72
+ # Replacing '\r\n' escape lines with string, so that the line will not be escaped in logs.
73
+ if '\r\n' in execution_output:
74
+ execution_output = execution_output.replace('\r\n', '')
75
+ elif '\n' in execution_output:
76
+ execution_output = execution_output.replace('\n', '')
77
+
78
+ process_name = execution_output
79
+ print_api(f"Client Process Command Line: {process_name}", **(print_kwargs or {}))
80
+ # Else if the script output came back empty.
81
+ else:
82
+ process_name = ''
83
+ message = "Client Process Command Line came back empty after script execution."
84
+ print_api(message, error_type=True, logger_method='error', **(print_kwargs or {}))
85
+
86
+ return process_name
@@ -1,28 +1,75 @@
1
+ import logging
1
2
  import socket
2
3
  import ssl
3
4
 
5
+ import select
6
+ from pathlib import Path
7
+
4
8
  from ...print_api import print_api
9
+ from ...basics import tracebacks
5
10
  from ..loggingw import loggingw
6
11
 
7
12
 
8
- def peek_first_bytes(client_socket, bytes_amount: int = 1) -> bytes:
13
+ def peek_first_bytes(
14
+ client_socket,
15
+ bytes_amount: int = 1,
16
+ timeout: float = None
17
+ ) -> bytes:
9
18
  """
10
19
  Peek first byte from the socket without removing it from the buffer.
11
20
 
12
21
  :param client_socket: Socket object.
13
22
  :param bytes_amount: Amount of bytes to peek.
23
+ :param timeout: float, Timeout in seconds.
14
24
 
15
25
  :return: the first X bytes from the socket buffer.
16
26
  """
17
27
 
18
- return client_socket.recv(bytes_amount, socket.MSG_PEEK)
28
+ error: bool = False
29
+ client_socket.settimeout(timeout)
30
+
31
+ try:
32
+ peek_a_bytes: bytes = client_socket.recv(bytes_amount, socket.MSG_PEEK)
33
+ except socket.timeout:
34
+ error = True
35
+ finally:
36
+ client_socket.settimeout(None)
37
+
38
+ if error:
39
+ raise TimeoutError
40
+
41
+ return peek_a_bytes
42
+
43
+
44
+ def is_socket_ready_for_read(socket_instance, timeout: float = 0) -> bool:
45
+ """
46
+ Check if socket is ready for read.
47
+
48
+ :param socket_instance: Socket object.
49
+ :param timeout: Timeout in seconds. The default is no timeout.
50
+
51
+ :return: True if socket is ready for read, False otherwise.
52
+ """
53
+
54
+ # Check if the socket is closed.
55
+ if socket_instance.fileno() == -1:
56
+ return False
57
+
58
+ # Use select to check if the socket is ready for reading.
59
+ # 'readable' returns a list of sockets that are ready for reading.
60
+ # Since we use only one socket, it will return a list with one element if the socket is ready for reading,
61
+ # or an empty list if the socket is not ready for reading.
62
+ readable, _, _ = select.select([socket_instance], [], [], timeout)
63
+ return bool(readable)
19
64
 
20
65
 
21
66
  class Receiver:
22
67
  """ Receiver Class is responsible for receiving the message from socket and populate the message class """
23
- logger = loggingw.get_logger_with_level("network." + __name__.rpartition('.')[2])
24
-
25
- def __init__(self, ssl_socket: ssl.SSLSocket):
68
+ def __init__(
69
+ self,
70
+ ssl_socket: ssl.SSLSocket,
71
+ logger: logging.Logger = None
72
+ ):
26
73
  self.ssl_socket: ssl.SSLSocket = ssl_socket
27
74
  self.buffer_size_receive: int = 16384
28
75
  # Timeout of 2 is enough for regular HTTP sessions`.
@@ -39,130 +86,125 @@ class Receiver:
39
86
  # Will get client Local port from the socket
40
87
  self.class_client_local_port: int = int()
41
88
 
89
+ if logger:
90
+ # Create child logger for the provided logger with the module's name.
91
+ self.logger: logging.Logger = loggingw.get_logger_with_level(f'{logger.name}.{Path(__file__).stem}')
92
+ else:
93
+ self.logger: logging.Logger = logger
94
+
42
95
  # Function to receive only the buffer, with error handling
43
- def socket_receive_message_buffer(self):
96
+ def chunk_from_buffer(self) -> tuple[bytes, str]:
97
+ """
98
+ Receive a chunk from the socket buffer.
99
+
100
+ :return: Tuple(received chunk binary bytes data, error message string).
101
+ """
44
102
  # Defining the data variable
45
- class_data: bytes = bytes()
103
+ # noinspection PyTypeChecker
104
+ received_data: bytes = None
105
+ # noinspection PyTypeChecker
106
+ error_message: str = None
46
107
 
108
+ # All excepts will be treated as empty message, indicate that socket was closed and will be handled properly.
47
109
  try:
48
110
  # "recv(byte buffer size)" to read the server's response.
49
- class_data = self.ssl_socket.recv(self.buffer_size_receive)
111
+ # A signal to close connection will be empty bytes string: b''.
112
+ received_data = self.ssl_socket.recv(self.buffer_size_receive)
50
113
  except ConnectionAbortedError:
51
- message = "* Connection was aborted by the client. Exiting..."
52
- print_api(message, logger=self.logger, logger_method='critical', traceback_string=True, oneline=True)
53
- # This will be treated as empty message - indicate that socket was closed and will be handled properly.
54
- pass
114
+ error_message = "ConnectionAbortedError: Connection was aborted by local TCP stack (not remote close)..."
55
115
  except ConnectionResetError:
56
- message = "* Connection was forcibly closed by the client. Exiting..."
57
- print_api(message, logger=self.logger, logger_method='critical', traceback_string=True, oneline=True)
58
- # This will be treated as empty message - indicate that socket was closed and will be handled properly.
59
- pass
116
+ error_message = "ConnectionResetError: Connection was forcibly closed by the other side..."
117
+ except TimeoutError as e:
118
+ if e.errno == 10060:
119
+ error_message = "TimeoutError: [WinError 10060] Socket receive operation timed out..."
120
+ else:
121
+ raise e
60
122
  except ssl.SSLError:
61
- message = "* Encountered SSL error on packet receive. Exiting..."
62
- print_api(message, logger=self.logger, logger_method='critical', traceback_string=True, oneline=True)
63
- # This will be treated as empty message - indicate that socket was closed and will be handled properly.
64
- pass
123
+ error_message = f"ssl.SSLError: Encountered SSL error on receive...\n{tracebacks.get_as_string()}"
65
124
 
66
- if not class_data:
125
+ if received_data == b'':
67
126
  self.logger.info("Empty message received, socket closed on the other side.")
68
127
 
69
- return class_data
128
+ return received_data, error_message
70
129
 
71
- # Function to receive message
72
- def socket_receive_message_full(self):
73
- # Setting timeout for the client to receive connections, since there is no way to know when the message has
74
- # ended and the message is longer than the receiving buffer.
75
- # So we need to set the timeout for the client socket.
76
- # If you set "timeout" on the listening main socket, it is not inherited to the child socket when client
77
- # connected, so you need to set it for the new socket as well.
78
- # Each function need to set the timeout independently
79
- self.ssl_socket.settimeout(self.socket_timeout)
80
- # variable that is responsible to retry over the same receive session if packet is less than buffer
81
- partial_data_received: bool = False
130
+ def socket_receive_message_full(self) -> tuple[bytes, bool, str]:
131
+ """
132
+ Receive the full message from the socket.
82
133
 
134
+ :return: Tuple(full data binary bytes, is socket closed boolean, error message string).
135
+ """
83
136
  # Define the variable that is going to aggregate the whole data received
84
- class_data: bytearray = bytearray()
85
- # Define the variable that will be responsible for receive buffer
86
- class_data_received: bytes = bytes()
137
+ full_data: bytes = bytes()
138
+ # noinspection PyTypeChecker
139
+ error_message: str = None
87
140
 
88
141
  # Infinite loop to accept data from the client
142
+ # We'll skip the 'is_socket_ready_for_read' check on the first run, since we want to read the data anyway,
143
+ # to leave the socket in the blocking mode.
144
+ first_run: bool = True
89
145
  while True:
90
- # SocketTimeout creates an exception that we need to handle with try and except.
91
- try:
92
- # The variable needs to be defined before receiving the socket data or else you will get an error
93
- # - variable not defined.
94
- # function_data_received: bytearray = bytearray()
95
- # Receiving data from the socket with "recv" method, while 1024 byte is a buffer size for the data.
96
- # "decode()" method converts byte message to string.
97
- class_data_received: bytes = self.socket_receive_message_buffer()
98
- # If there is no byte data received from the client and also the full message is not empty, then the loop
99
- # needs to break, since it is the last message that was received from the client
100
- except TimeoutError:
101
- if partial_data_received:
102
- self.logger.info(f"Timed out after {self.socket_timeout} seconds - no more packets. "
103
- f"Passing current request of total {len(class_data)} bytes down the network chain")
104
- # Pass the exception
105
- pass
106
- # Break the while loop, since we already have the request
146
+ # Check if there is data to be read from the socket.
147
+ is_there_data: bool = is_socket_ready_for_read(self.ssl_socket, timeout=0.5)
148
+
149
+ # noinspection PyTypeChecker
150
+ if is_there_data or first_run:
151
+ first_run = False
152
+ # Receive the data from the socket.
153
+ received_chunk, error_message = self.chunk_from_buffer()
154
+ received_chunk: bytes
155
+ error_message: str
156
+
157
+ # And if the message received is not empty then aggregate it to the main "data received" variable
158
+ if received_chunk != b'' and received_chunk is not None:
159
+ full_data += received_chunk
160
+
161
+ self.logger.info(f"Received packet bytes: [{len(received_chunk)}] | "
162
+ f"Total aggregated bytes: [{len(full_data)}]")
163
+
164
+ elif received_chunk == b'' or received_chunk is None:
165
+ # If there received_chunk is None, this means that the socket was closed,
166
+ # since it is a connection error.
167
+ # Same goes for the empty message.
168
+ is_socket_closed = True
107
169
  break
108
- else:
109
- self.logger.info(
110
- # Dividing number of seconds by 60 to get minutes
111
- f"{self.socket_timeout/60} minutes timeout reached on 'socket.recv()' - no data received from "
112
- f"{self.class_client_address}:{self.class_client_local_port}. Still waiting...")
113
- # Pass the exception
114
- pass
115
- # Changing the socket timeout back to none since receiving operation has been finished.
116
- self.ssl_socket.settimeout(None)
117
- # Continue to the next iteration inside while
118
- continue
119
-
120
- # And if the message received is not empty then aggregate it to the main "data received" variable
121
- if class_data_received:
122
- class_data.extend(class_data_received)
123
-
124
- self.logger.info(f"Received packet with {len(class_data_received)} bytes. "
125
- f"Current aggregated request of total: {len(class_data)} bytes")
126
-
127
- # If the first received session is less than the buffer size, then the full message was received
128
- if len(class_data_received) < self.buffer_size_receive:
129
- # Since we already received some data from the other side, the retried variable will be true
130
- partial_data_received = True
131
- self.logger.info(f"Receiving the buffer again...")
132
-
133
- # In this case the socket timeout will be 2 seconds to wait for more packets.
134
- # If there are no more packets, receiver will end its activity and pass the message to
135
- # the rest of the components in the network chain
136
- if self.socket_timeout != 0.5:
137
- self.socket_timeout = 0.5
138
- self.ssl_socket.settimeout(self.socket_timeout)
139
- self.logger.info(f"Timeout changed to {self.socket_timeout} seconds")
140
-
141
- # Continue to the next receive on the socket
142
- continue
143
170
  else:
144
- if class_data:
145
- self.logger.info(f"Since there's request received from the client of total {len(class_data)} "
146
- f"bytes, we'll first process it, and when the receiver will ask for data from "
147
- f"client in the next cycle - empty message will be received again, and current "
148
- f"socket will be finally closed.")
171
+ # If there is no data to be read from the socket, it doesn't mean that the socket is closed.
172
+ is_socket_closed = False
173
+ received_chunk = None
149
174
  break
150
175
 
151
- return class_data
176
+ if full_data:
177
+ self.logger.info(f"Received total: [{len(full_data)}] bytes")
178
+
179
+ # In case the full data is empty, and the received chunk is None, it doesn't mean that the socket is closed.
180
+ # But it means that there was no data to be read from the socket, because of error or timeout.
181
+ if full_data == b'' and received_chunk is None:
182
+ full_data = None
183
+
184
+ return full_data, is_socket_closed, error_message
185
+
186
+ def receive(self) -> tuple[bytes, bool, str]:
187
+ """
188
+ Receive the message from the socket.
152
189
 
153
- # noinspection PyBroadException
154
- def receive(self):
155
- # Getting client address from the socket
190
+ :return: Tuple(
191
+ data binary bytes,
192
+ is socket closed boolean,
193
+ error message string if there was a connection exception).
194
+ """
195
+ # Getting client address and Local port from the socket
156
196
  self.class_client_address = self.ssl_socket.getpeername()[0]
157
- # Getting client Local port from the socket
158
197
  self.class_client_local_port = self.ssl_socket.getpeername()[1]
159
198
 
160
199
  # Receiving data from the socket and closing the socket if send is finished.
161
200
  self.logger.info(f"Waiting for data from {self.class_client_address}:{self.class_client_local_port}")
162
- function_client_data: bytearray = self.socket_receive_message_full()
201
+ socket_data_bytes, is_socket_closed, error_message = self.socket_receive_message_full()
202
+ socket_data_bytes: bytes
203
+ is_socket_closed: bool
204
+ error_message: str
163
205
 
164
- if function_client_data:
206
+ if socket_data_bytes:
165
207
  # Put only 100 characters to the log, since we record the message any way in full - later.
166
- self.logger.info(f"Received: {function_client_data[0: 100]}...")
208
+ self.logger.info(f"Received: {socket_data_bytes[0: 100]}...")
167
209
 
168
- return function_client_data
210
+ return socket_data_bytes, is_socket_closed, error_message