atomicshop 2.15.11__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 (221) hide show
  1. atomicshop/__init__.py +1 -1
  2. atomicshop/{addons/mains → a_mains}/FACT/update_extract.py +3 -2
  3. atomicshop/a_mains/dns_gateway_setting.py +11 -0
  4. atomicshop/a_mains/get_local_tcp_ports.py +85 -0
  5. atomicshop/a_mains/github_wrapper.py +11 -0
  6. atomicshop/a_mains/install_ca_certificate.py +172 -0
  7. atomicshop/a_mains/process_from_port.py +119 -0
  8. atomicshop/a_mains/set_default_dns_gateway.py +90 -0
  9. atomicshop/a_mains/update_config_toml.py +38 -0
  10. atomicshop/basics/ansi_escape_codes.py +3 -1
  11. atomicshop/basics/argparse_template.py +2 -0
  12. atomicshop/basics/booleans.py +27 -30
  13. atomicshop/basics/bytes_arrays.py +43 -0
  14. atomicshop/basics/classes.py +149 -1
  15. atomicshop/basics/enums.py +2 -2
  16. atomicshop/basics/exceptions.py +5 -1
  17. atomicshop/basics/list_of_classes.py +29 -0
  18. atomicshop/basics/multiprocesses.py +374 -50
  19. atomicshop/basics/strings.py +72 -3
  20. atomicshop/basics/threads.py +14 -0
  21. atomicshop/basics/tracebacks.py +13 -3
  22. atomicshop/certificates.py +153 -52
  23. atomicshop/config_init.py +11 -6
  24. atomicshop/console_user_response.py +7 -14
  25. atomicshop/consoles.py +9 -0
  26. atomicshop/datetimes.py +1 -1
  27. atomicshop/diff_check.py +3 -3
  28. atomicshop/dns.py +128 -3
  29. atomicshop/etws/_pywintrace_fix.py +17 -0
  30. atomicshop/etws/trace.py +40 -42
  31. atomicshop/etws/traces/trace_dns.py +56 -44
  32. atomicshop/etws/traces/trace_tcp.py +130 -0
  33. atomicshop/file_io/csvs.py +27 -5
  34. atomicshop/file_io/docxs.py +34 -17
  35. atomicshop/file_io/file_io.py +31 -17
  36. atomicshop/file_io/jsons.py +49 -0
  37. atomicshop/file_io/tomls.py +139 -0
  38. atomicshop/filesystem.py +616 -291
  39. atomicshop/get_process_list.py +3 -3
  40. atomicshop/http_parse.py +149 -93
  41. atomicshop/ip_addresses.py +6 -1
  42. atomicshop/mitm/centered_settings.py +132 -0
  43. atomicshop/mitm/config_static.py +207 -0
  44. atomicshop/mitm/config_toml_editor.py +55 -0
  45. atomicshop/mitm/connection_thread_worker.py +875 -357
  46. atomicshop/mitm/engines/__parent/parser___parent.py +4 -17
  47. atomicshop/mitm/engines/__parent/recorder___parent.py +108 -51
  48. atomicshop/mitm/engines/__parent/requester___parent.py +116 -0
  49. atomicshop/mitm/engines/__parent/responder___parent.py +75 -114
  50. atomicshop/mitm/engines/__reference_general/parser___reference_general.py +10 -7
  51. atomicshop/mitm/engines/__reference_general/recorder___reference_general.py +5 -5
  52. atomicshop/mitm/engines/__reference_general/requester___reference_general.py +47 -0
  53. atomicshop/mitm/engines/__reference_general/responder___reference_general.py +95 -13
  54. atomicshop/mitm/engines/create_module_template.py +58 -14
  55. atomicshop/mitm/import_config.py +359 -139
  56. atomicshop/mitm/initialize_engines.py +160 -80
  57. atomicshop/mitm/message.py +64 -23
  58. atomicshop/mitm/mitm_main.py +892 -0
  59. atomicshop/mitm/recs_files.py +183 -0
  60. atomicshop/mitm/shared_functions.py +4 -10
  61. atomicshop/mitm/ssh_tester.py +82 -0
  62. atomicshop/mitm/statistic_analyzer.py +136 -40
  63. atomicshop/mitm/statistic_analyzer_helper/moving_average_helper.py +265 -83
  64. atomicshop/monitor/checks/dns.py +1 -1
  65. atomicshop/networks.py +671 -0
  66. atomicshop/on_exit.py +39 -9
  67. atomicshop/package_mains_processor.py +84 -0
  68. atomicshop/permissions/permissions.py +22 -0
  69. atomicshop/permissions/ubuntu_permissions.py +239 -0
  70. atomicshop/permissions/win_permissions.py +33 -0
  71. atomicshop/print_api.py +24 -42
  72. atomicshop/process.py +24 -6
  73. atomicshop/process_poller/process_pool.py +0 -1
  74. atomicshop/process_poller/simple_process_pool.py +204 -5
  75. atomicshop/python_file_patcher.py +1 -1
  76. atomicshop/python_functions.py +27 -75
  77. atomicshop/speech_recognize.py +8 -0
  78. atomicshop/ssh_remote.py +158 -172
  79. atomicshop/system_resource_monitor.py +61 -47
  80. atomicshop/system_resources.py +8 -8
  81. atomicshop/tempfiles.py +1 -2
  82. atomicshop/urls.py +6 -0
  83. atomicshop/venvs.py +28 -0
  84. atomicshop/versioning.py +27 -0
  85. atomicshop/web.py +98 -27
  86. atomicshop/web_apis/google_custom_search.py +44 -0
  87. atomicshop/web_apis/google_llm.py +188 -0
  88. atomicshop/websocket_parse.py +450 -0
  89. atomicshop/wrappers/certauthw/certauth.py +1 -0
  90. atomicshop/wrappers/cryptographyw.py +29 -8
  91. atomicshop/wrappers/ctyping/etw_winapi/const.py +97 -47
  92. atomicshop/wrappers/ctyping/etw_winapi/etw_functions.py +178 -49
  93. atomicshop/wrappers/ctyping/file_details_winapi.py +67 -0
  94. atomicshop/wrappers/ctyping/msi_windows_installer/cabs.py +2 -1
  95. atomicshop/wrappers/ctyping/msi_windows_installer/extract_msi_main.py +2 -2
  96. atomicshop/wrappers/ctyping/setup_device.py +466 -0
  97. atomicshop/wrappers/ctyping/win_console.py +39 -0
  98. atomicshop/wrappers/dockerw/dockerw.py +113 -2
  99. atomicshop/wrappers/elasticsearchw/config_basic.py +0 -12
  100. atomicshop/wrappers/elasticsearchw/elastic_infra.py +75 -0
  101. atomicshop/wrappers/elasticsearchw/elasticsearchw.py +2 -20
  102. atomicshop/wrappers/factw/get_file_data.py +12 -5
  103. atomicshop/wrappers/factw/install/install_after_restart.py +89 -5
  104. atomicshop/wrappers/factw/install/pre_install_and_install_before_restart.py +20 -14
  105. atomicshop/wrappers/githubw.py +537 -54
  106. atomicshop/wrappers/loggingw/consts.py +1 -1
  107. atomicshop/wrappers/loggingw/filters.py +23 -0
  108. atomicshop/wrappers/loggingw/formatters.py +12 -0
  109. atomicshop/wrappers/loggingw/handlers.py +214 -107
  110. atomicshop/wrappers/loggingw/loggers.py +19 -0
  111. atomicshop/wrappers/loggingw/loggingw.py +860 -22
  112. atomicshop/wrappers/loggingw/reading.py +134 -112
  113. atomicshop/wrappers/mongodbw/mongo_infra.py +31 -0
  114. atomicshop/wrappers/mongodbw/mongodbw.py +1324 -36
  115. atomicshop/wrappers/netshw.py +271 -0
  116. atomicshop/wrappers/playwrightw/engine.py +34 -19
  117. atomicshop/wrappers/playwrightw/infra.py +5 -0
  118. atomicshop/wrappers/playwrightw/javascript.py +7 -3
  119. atomicshop/wrappers/playwrightw/keyboard.py +14 -0
  120. atomicshop/wrappers/playwrightw/scenarios.py +172 -5
  121. atomicshop/wrappers/playwrightw/waits.py +9 -7
  122. atomicshop/wrappers/powershell_networking.py +80 -0
  123. atomicshop/wrappers/psutilw/processes.py +37 -1
  124. atomicshop/wrappers/psutilw/psutil_networks.py +85 -0
  125. atomicshop/wrappers/pyopensslw.py +9 -2
  126. atomicshop/wrappers/pywin32w/cert_store.py +116 -0
  127. atomicshop/wrappers/pywin32w/win_event_log/fetch.py +174 -0
  128. atomicshop/wrappers/pywin32w/win_event_log/subscribes/process_create.py +3 -105
  129. atomicshop/wrappers/pywin32w/win_event_log/subscribes/process_terminate.py +3 -57
  130. atomicshop/wrappers/pywin32w/wmis/msft_netipaddress.py +113 -0
  131. atomicshop/wrappers/pywin32w/wmis/win32_networkadapterconfiguration.py +259 -0
  132. atomicshop/wrappers/pywin32w/wmis/win32networkadapter.py +112 -0
  133. atomicshop/wrappers/pywin32w/wmis/wmi_helpers.py +236 -0
  134. atomicshop/wrappers/socketw/accepter.py +21 -7
  135. atomicshop/wrappers/socketw/certificator.py +216 -150
  136. atomicshop/wrappers/socketw/creator.py +190 -50
  137. atomicshop/wrappers/socketw/dns_server.py +491 -182
  138. atomicshop/wrappers/socketw/exception_wrapper.py +45 -52
  139. atomicshop/wrappers/socketw/process_getter.py +86 -0
  140. atomicshop/wrappers/socketw/receiver.py +144 -102
  141. atomicshop/wrappers/socketw/sender.py +65 -35
  142. atomicshop/wrappers/socketw/sni.py +334 -165
  143. atomicshop/wrappers/socketw/socket_base.py +134 -0
  144. atomicshop/wrappers/socketw/socket_client.py +137 -95
  145. atomicshop/wrappers/socketw/socket_server_tester.py +11 -7
  146. atomicshop/wrappers/socketw/socket_wrapper.py +717 -116
  147. atomicshop/wrappers/socketw/ssl_base.py +15 -14
  148. atomicshop/wrappers/socketw/statistics_csv.py +148 -17
  149. atomicshop/wrappers/sysmonw.py +1 -1
  150. atomicshop/wrappers/ubuntu_terminal.py +65 -26
  151. atomicshop/wrappers/win_auditw.py +189 -0
  152. atomicshop/wrappers/winregw/__init__.py +0 -0
  153. atomicshop/wrappers/winregw/winreg_installed_software.py +58 -0
  154. atomicshop/wrappers/winregw/winreg_network.py +232 -0
  155. {atomicshop-2.15.11.dist-info → atomicshop-3.10.5.dist-info}/METADATA +31 -51
  156. atomicshop-3.10.5.dist-info/RECORD +306 -0
  157. {atomicshop-2.15.11.dist-info → atomicshop-3.10.5.dist-info}/WHEEL +1 -1
  158. atomicshop/_basics_temp.py +0 -101
  159. atomicshop/a_installs/win/fibratus.py +0 -9
  160. atomicshop/a_installs/win/mongodb.py +0 -9
  161. atomicshop/a_installs/win/pycharm.py +0 -9
  162. atomicshop/addons/a_setup_scripts/install_psycopg2_ubuntu.sh +0 -3
  163. atomicshop/addons/a_setup_scripts/install_pywintrace_0.3.cmd +0 -2
  164. atomicshop/addons/mains/__pycache__/install_fibratus_windows.cpython-312.pyc +0 -0
  165. atomicshop/addons/mains/__pycache__/msi_unpacker.cpython-312.pyc +0 -0
  166. atomicshop/addons/mains/install_docker_rootless_ubuntu.py +0 -11
  167. atomicshop/addons/mains/install_docker_ubuntu_main_sudo.py +0 -11
  168. atomicshop/addons/mains/install_elastic_search_and_kibana_ubuntu.py +0 -10
  169. atomicshop/addons/mains/install_wsl_ubuntu_lts_admin.py +0 -9
  170. atomicshop/addons/package_setup/CreateWheel.cmd +0 -7
  171. atomicshop/addons/package_setup/Setup in Edit mode.cmd +0 -6
  172. atomicshop/addons/package_setup/Setup.cmd +0 -7
  173. atomicshop/archiver/_search_in_zip.py +0 -189
  174. atomicshop/archiver/archiver.py +0 -34
  175. atomicshop/archiver/search_in_archive.py +0 -250
  176. atomicshop/archiver/sevenz_app_w.py +0 -86
  177. atomicshop/archiver/sevenzs.py +0 -44
  178. atomicshop/archiver/zips.py +0 -293
  179. atomicshop/file_types.py +0 -24
  180. atomicshop/mitm/config_editor.py +0 -37
  181. atomicshop/mitm/engines/create_module_template_example.py +0 -13
  182. atomicshop/mitm/initialize_mitm_server.py +0 -268
  183. atomicshop/pbtkmultifile_argparse.py +0 -88
  184. atomicshop/permissions.py +0 -151
  185. atomicshop/script_as_string_processor.py +0 -38
  186. atomicshop/ssh_scripts/process_from_ipv4.py +0 -37
  187. atomicshop/ssh_scripts/process_from_port.py +0 -27
  188. atomicshop/wrappers/_process_wrapper_curl.py +0 -27
  189. atomicshop/wrappers/_process_wrapper_tar.py +0 -21
  190. atomicshop/wrappers/dockerw/install_docker.py +0 -209
  191. atomicshop/wrappers/elasticsearchw/infrastructure.py +0 -265
  192. atomicshop/wrappers/elasticsearchw/install_elastic.py +0 -232
  193. atomicshop/wrappers/ffmpegw.py +0 -125
  194. atomicshop/wrappers/fibratusw/install.py +0 -81
  195. atomicshop/wrappers/mongodbw/infrastructure.py +0 -53
  196. atomicshop/wrappers/mongodbw/install_mongodb.py +0 -190
  197. atomicshop/wrappers/msiw.py +0 -149
  198. atomicshop/wrappers/nodejsw/install_nodejs.py +0 -139
  199. atomicshop/wrappers/process_wrapper_pbtk.py +0 -16
  200. atomicshop/wrappers/psutilw/networks.py +0 -45
  201. atomicshop/wrappers/pycharmw.py +0 -81
  202. atomicshop/wrappers/socketw/base.py +0 -59
  203. atomicshop/wrappers/socketw/get_process.py +0 -107
  204. atomicshop/wrappers/wslw.py +0 -191
  205. atomicshop-2.15.11.dist-info/RECORD +0 -302
  206. /atomicshop/{addons/mains → a_mains}/FACT/factw_fact_extractor_docker_image_main_sudo.py +0 -0
  207. /atomicshop/{addons → a_mains/addons}/PlayWrightCodegen.cmd +0 -0
  208. /atomicshop/{addons → a_mains/addons}/ScriptExecution.cmd +0 -0
  209. /atomicshop/{addons → a_mains/addons}/inits/init_to_import_all_modules.py +0 -0
  210. /atomicshop/{addons → a_mains/addons}/process_list/ReadMe.txt +0 -0
  211. /atomicshop/{addons → a_mains/addons}/process_list/compile.cmd +0 -0
  212. /atomicshop/{addons → a_mains/addons}/process_list/compiled/Win10x64/process_list.dll +0 -0
  213. /atomicshop/{addons → a_mains/addons}/process_list/compiled/Win10x64/process_list.exp +0 -0
  214. /atomicshop/{addons → a_mains/addons}/process_list/compiled/Win10x64/process_list.lib +0 -0
  215. /atomicshop/{addons → a_mains/addons}/process_list/process_list.cpp +0 -0
  216. /atomicshop/{archiver → permissions}/__init__.py +0 -0
  217. /atomicshop/{wrappers/fibratusw → web_apis}/__init__.py +0 -0
  218. /atomicshop/wrappers/{nodejsw → pywin32w/wmis}/__init__.py +0 -0
  219. /atomicshop/wrappers/pywin32w/{wmi_win32process.py → wmis/win32process.py} +0 -0
  220. {atomicshop-2.15.11.dist-info → atomicshop-3.10.5.dist-info/licenses}/LICENSE.txt +0 -0
  221. {atomicshop-2.15.11.dist-info → atomicshop-3.10.5.dist-info}/top_level.txt +0 -0
@@ -1,112 +1,189 @@
1
1
  import os
2
- import sys
3
2
  from pathlib import Path
4
3
 
5
- from .. import filesystem
4
+ from .. import ip_addresses
6
5
  from ..file_io import tomls
7
6
  from ..basics.classes import import_first_class_name_from_file_path
8
- from ..wrappers.loggingw import loggingw
9
- from .engines.__reference_general import parser___reference_general, responder___reference_general, \
10
- recorder___reference_general
7
+ from .engines.__reference_general import parser___reference_general, requester___reference_general, \
8
+ responder___reference_general, recorder___reference_general
11
9
 
12
10
 
13
11
  class ModuleCategory:
14
12
  def __init__(self, script_directory: str):
15
- self.domain_list: list = list()
16
13
  self.engine_name: str = str()
17
14
  self.script_directory: str = script_directory
18
15
 
16
+ self.domain_list: list = list()
17
+ self.domain_target_dict: dict = dict()
18
+ self.port_target_dict: dict = dict()
19
+
20
+ self.is_localhost: bool = bool()
21
+ self.on_port_connect: dict = dict()
22
+ self.mtls: dict = dict()
23
+
19
24
  self.parser_file_path: str = str()
25
+ self.requester_file_path: str = str()
20
26
  self.responder_file_path: str = str()
21
27
  self.recorder_file_path: str = str()
22
28
 
23
29
  self.parser_class_object: str = str()
30
+ self.requester_class_object: str = str()
24
31
  self.responder_class_object: str = str()
25
32
  self.recorder_class_object: str = str()
26
33
 
27
- # The instance of the recorder class that will be initiated once in the script start
28
- self.responder_instance = None
29
-
30
34
  def fill_engine_fields_from_general_reference(self, engines_fullpath: str):
31
35
  # Reference module variables.
32
36
  self.engine_name = '__reference_general'
33
37
  reference_folder_path: str = engines_fullpath + os.sep + self.engine_name
34
38
  # Full path to file.
35
39
  self.parser_file_path = reference_folder_path + os.sep + "parser___reference_general.py"
40
+ self.requester_file_path = reference_folder_path + os.sep + "requester___reference_general.py"
36
41
  self.responder_file_path = reference_folder_path + os.sep + "responder___reference_general.py"
37
42
  self.recorder_file_path = reference_folder_path + os.sep + "recorder___reference_general.py"
38
43
 
39
- def fill_engine_fields_from_config(self, engine_config_file_path: str):
44
+ def fill_engine_fields_from_config(
45
+ self,
46
+ engine_config_file_path: str,
47
+ print_kwargs: dict = None
48
+ ) -> tuple[int, str]:
40
49
  # Read the configuration file of the engine.
41
- configuration_data = tomls.read_toml_file(engine_config_file_path)
50
+ configuration_data = tomls.read_toml_file(engine_config_file_path, **(print_kwargs or {}))
42
51
 
43
52
  engine_directory_path: str = str(Path(engine_config_file_path).parent)
44
53
  self.engine_name = Path(engine_directory_path).name
45
54
 
46
55
  # Getting the parameters from engine config file
47
- self.domain_list = configuration_data['domains']
56
+ self.domain_list = configuration_data['engine']['domains']
57
+
58
+ if 'on_port_connect' in configuration_data:
59
+ self.on_port_connect = configuration_data['on_port_connect']
60
+
61
+ if 'mtls' in configuration_data:
62
+ self.mtls = configuration_data['mtls']
48
63
 
49
64
  # If there's module configuration file, but no domains in it, there's no point to continue.
50
65
  # Since, each engine is based on domains.
51
66
  if not self.domain_list or self.domain_list[0] == '':
52
67
  raise ValueError(f"Engine Configuration file doesn't contain any domains: {engine_config_file_path}")
53
68
 
54
- # Full path to file
55
- self.parser_file_path = filesystem.get_file_paths_from_directory(
56
- engine_directory_path, file_name_check_pattern=configuration_data['parser_file'])[0]
57
- self.responder_file_path = filesystem.get_file_paths_from_directory(
58
- engine_directory_path, file_name_check_pattern=configuration_data['responder_file'])[0]
59
- self.recorder_file_path = filesystem.get_file_paths_from_directory(
60
- engine_directory_path, file_name_check_pattern=configuration_data['recorder_file'])[0]
61
-
62
- def initialize_engine(self, logs_path: str, logger=None, reference_general: bool = False, **kwargs):
63
- if not reference_general:
64
- self.parser_class_object = import_first_class_name_from_file_path(
65
- self.script_directory, self.parser_file_path, logger=logger, stdout=False)
66
- self.responder_class_object = import_first_class_name_from_file_path(
67
- self.script_directory, self.responder_file_path, logger=logger, stdout=False)
68
- self.recorder_class_object = import_first_class_name_from_file_path(
69
- self.script_directory, self.recorder_file_path, logger=logger, stdout=False)
69
+ # This is needed for backwards compatibility before glass 1.8.2, atomicshop 2.20.6
70
+ # When the name of each file was following the pattern: parser_<EngineName>.py, responder_<EngineName>.py, recorder_<EngineName>.py
71
+ if os.path.isfile(f"{engine_directory_path}{os.sep}parser.py"):
72
+ file_name_suffix: str = ''
70
73
  else:
71
- self.parser_class_object = parser___reference_general.ParserGeneral
72
- self.responder_class_object = responder___reference_general.ResponderGeneral
73
- self.recorder_class_object = recorder___reference_general.RecorderGeneral
74
+ file_name_suffix: str = f"_{self.engine_name}"
74
75
 
76
+ # Full path to file
77
+ self.parser_file_path = f"{engine_directory_path}{os.sep}parser{file_name_suffix}.py"
78
+ self.requester_file_path = f"{engine_directory_path}{os.sep}requester{file_name_suffix}.py"
79
+ self.responder_file_path = f"{engine_directory_path}{os.sep}responder{file_name_suffix}.py"
80
+ self.recorder_file_path = f"{engine_directory_path}{os.sep}recorder{file_name_suffix}.py"
81
+
82
+ for domain_index, domain_port_string in enumerate(self.domain_list):
83
+ # Splitting the domain and port
84
+ if ':' in domain_port_string:
85
+ domain, port = domain_port_string.split(':')
86
+ else:
87
+ error_string: str = f"No [domain:port] pair found in: {domain_port_string}"
88
+ return 1, error_string
89
+
90
+ self.domain_target_dict[domain] = {'ip': None, 'port': int(port)}
91
+
92
+ for port, value in self.on_port_connect.items():
93
+ self.port_target_dict[port] = {'ip': None, 'port': int(port)}
94
+
95
+ # If it is not an IP address (e.g. <IP:PORT>) it will be treated as file path.
96
+ if ':' not in value:
97
+ self.on_port_connect[port] = f'{engine_directory_path}{os.sep}{value}'
98
+
99
+ for subdomain, file_name in self.mtls.items():
100
+ self.mtls[subdomain] = f'{engine_directory_path}{os.sep}{file_name}'
101
+
102
+ return 0, ''
103
+
104
+ def initialize_engine(
105
+ self,
106
+ reference_general: bool = False,
107
+ print_kwargs: dict = None
108
+ ) -> tuple[int, str]:
75
109
  try:
76
- # Since we're using responder to aggregate requests to build responses based on several
77
- # requests, we need to initiate responder's class only once in the beginning and assign
78
- # this instance to a variable that will be called later per domain.
79
- self.responder_instance = self.responder_class_object()
80
- except Exception as exception_object:
81
- logger.error_exception(f"Exception while initializing responder: {exception_object}")
82
- sys.exit()
83
-
84
- # Initiating logger for each engine by its name
85
- # initiate_logger(current_module.engine_name, log_file_extension)
86
- loggingw.create_logger(
87
- logger_name=self.engine_name,
88
- directory_path=logs_path,
89
- add_stream=True,
90
- add_timedfile=True,
91
- formatter_streamhandler='DEFAULT',
92
- formatter_filehandler='DEFAULT'
93
- )
94
-
95
-
96
- # Assigning external class object by message domain received from client. If the domain is not in the list,
97
- # the reference general module will be assigned.
110
+ if not reference_general:
111
+ self.parser_class_object = import_first_class_name_from_file_path(
112
+ self.script_directory, self.parser_file_path, **(print_kwargs or {}))
113
+ self.requester_class_object = import_first_class_name_from_file_path(
114
+ self.script_directory, self.requester_file_path, **(print_kwargs or {}))
115
+ self.responder_class_object = import_first_class_name_from_file_path(
116
+ self.script_directory, self.responder_file_path, **(print_kwargs or {}))
117
+ self.recorder_class_object = import_first_class_name_from_file_path(
118
+ self.script_directory, self.recorder_file_path, **(print_kwargs or {}))
119
+ else:
120
+ self.parser_class_object = parser___reference_general.ParserGeneral
121
+ self.requester_class_object = requester___reference_general.RequesterGeneral
122
+ self.responder_class_object = responder___reference_general.ResponderGeneral
123
+ self.recorder_class_object = recorder___reference_general.RecorderGeneral
124
+ except ModuleNotFoundError as e:
125
+ return 1, str(e)
126
+
127
+ return 0, ''
128
+
129
+
130
+ def get_ipv4_from_engine_on_connect_port(
131
+ address_or_file_path: str
132
+ ) -> tuple[str, str] | None:
133
+ """
134
+ Function to get the IPv4 address from the engine on connect port.
135
+
136
+ :param address_or_file_path: string, "ip_address:port" or file path that was set in the engine on_port_connect.
137
+ :return: string, IPv4 address that was parsed from the 'ip_port_address'.
138
+
139
+ """
140
+
141
+ def get_ip_port_from_address(ip_port_address: str) -> tuple[str, str] | None:
142
+ """
143
+ Function to get the IP address and port from the address string.
144
+ If the address is a file path, it will return an empty string.
145
+ """
146
+ if ':' in ip_port_address:
147
+ ipv4_to_connect, port_to_connect = ip_port_address.split(':')
148
+ if ip_addresses.is_ip_address(ipv4_to_connect, ip_type='ipv4'):
149
+ return ipv4_to_connect, port_to_connect
150
+ else:
151
+ return None
152
+ else:
153
+ return None
154
+
155
+ # Try to get it as IP address.
156
+ ip_port_address_from_config = get_ip_port_from_address(address_or_file_path)
157
+
158
+ # If it is not an IP address, try to read it as a text file.
159
+ if not ip_port_address_from_config:
160
+ if os.path.isfile(address_or_file_path):
161
+ with open(address_or_file_path, 'r', encoding='utf-8') as file:
162
+ first_line = file.readline().strip()
163
+
164
+ ip_port_address_from_config = get_ip_port_from_address(first_line)
165
+ else:
166
+ return None
167
+
168
+ return ip_port_address_from_config
169
+
170
+
98
171
  def assign_class_by_domain(
99
- engines_list: list, message_domain_name: str, reference_module, config, logger=None):
100
- # Defining return variables:
101
- function_parser = None
102
- function_responder = None
103
- function_recorder = None
172
+ engines_list: list,
173
+ message_domain_name: str,
174
+ reference_module
175
+ ):
176
+ """
177
+ Assigning external class object by message domain received from client. If the domain is not in the list,
178
+ the reference general module will be assigned.
179
+ """
104
180
 
105
181
  # In case SNI came empty in the request from client, then there's no point in iterating through engine domains.
182
+ module = None
106
183
  if message_domain_name:
107
- # If the engines_usage is set to True in the config file, then we'll iterate through the list of engines
184
+ # If engine/s exit, the engines_list will not be empty, then we'll iterate through the list of engines
108
185
  # to find the domain in the list of domains of the engine.
109
- if config['tcp']['engines_usage']:
186
+ if engines_list:
110
187
  # Checking if current domain is in engines' domain list to activate domain specific engine
111
188
  for function_module in engines_list:
112
189
  # The list: matches_list = ["domain1.com", "domain2.com", "domain3.com"]
@@ -117,31 +194,34 @@ def assign_class_by_domain(
117
194
  # On the other hand if you want to find if partial string is
118
195
  # in the list of strings: if any(a_string in x for x in matches_list):
119
196
  # In this case list is the same and string: a_string = domain
120
- if any(x in message_domain_name for x in function_module.domain_list):
121
- # Assigning modules by current engine of the domain
122
- function_parser = function_module.parser_class_object
123
- function_recorder = function_module.recorder_class_object
124
- # Since the responder is being initiated only once, we're assigning only the instance
125
- function_responder = function_module.responder_instance
126
-
127
- logger.info(f"Assigned Modules for [{message_domain_name}]: "
128
- f"{function_module.parser_class_object.__name__}, "
129
- f"{function_module.responder_class_object.__name__}, "
130
- f"{function_module.recorder_class_object.__name__}")
197
+ if any(x in message_domain_name for x in function_module.domain_target_dict.keys()):
198
+ # Assigning module by current engine of the domain
199
+ module = function_module
131
200
 
132
201
  # If the domain was found in the current list of class domains, we can stop the loop
133
202
  break
134
203
 
204
+ # If the module wasn't found by the domain, check it by the port.
205
+ if not module:
206
+ # Get the list of all the ip addresses in the on_port_connect dict.
207
+ list_of_ip_addresses_per_port: list[str] = []
208
+ for port, value in function_module.on_port_connect.items():
209
+ ipv4_to_connect, _ = get_ipv4_from_engine_on_connect_port(value)
210
+ list_of_ip_addresses_per_port.append(ipv4_to_connect)
211
+
212
+ # Checking if the message domain name is in the list of ip addresses per port.
213
+ if any(x in message_domain_name for x in list_of_ip_addresses_per_port):
214
+ # Assigning module by current engine of the port
215
+ module = function_module
216
+
217
+ # If the port was found in the current list of class ports, we can stop the loop
218
+ break
219
+
135
220
  # If none of the domains were found in the engine domains list, then we'll assign reference module.
136
221
  # It's enough to check only parser, since responder and recorder also will be empty.
137
222
  # This section is also relevant if SNI came empty in the request from the client and no domain was passed by the
138
223
  # DNS Server.
139
- if not function_parser:
140
- # Assigning modules by current engine of the domain
141
- function_parser = reference_module.parser_class_object
142
- function_recorder = reference_module.recorder_class_object
143
- # Since the responder is being initiated only once, we're assigning only the instance
144
- function_responder = reference_module.responder_instance
145
-
146
- # Return all the initiated modules
147
- return function_parser, function_responder, function_recorder
224
+ if not module:
225
+ module = reference_module
226
+
227
+ return module
@@ -1,39 +1,80 @@
1
+ from datetime import datetime
2
+ from typing import Union, Any
3
+
4
+ from .. import http_parse
5
+ from ..basics import dicts
6
+
7
+
1
8
  class ClientMessage:
2
9
  """ A class that will store all the message details from the client """
3
10
  def __init__(self):
4
- self.request_raw_bytes: bytearray = bytearray()
5
- self.request_time_received = None
6
- self.request_raw_decoded = None
7
- self.request_body_parsed = None
11
+ # noinspection PyTypeChecker
12
+ self.timestamp: datetime = None
13
+ self.engine_name: str = str()
14
+ # noinspection PyTypeChecker
15
+ self.request_raw_bytes: bytes = None
16
+ self.request_auto_parsed: Union[http_parse.HTTPRequestParse, any] = None
17
+ self.request_custom_parsed: Any = None
8
18
  self.request_raw_hex: hex = None
9
- # self.response_raw_bytes: bytearray = bytearray()
10
- self.response_list_of_raw_bytes: list = list()
11
- self.response_list_of_raw_decoded: list = list()
12
- # self.response_raw_hex: hex = None
13
- self.response_list_of_raw_hex: list = list()
19
+ # noinspection PyTypeChecker
20
+ self.response_raw_bytes: bytes = None
21
+ self.response_auto_parsed: Any = None
22
+ self.response_custom_parsed: Any = None
23
+ self.response_raw_hex: hex = None
14
24
  self.server_name: str = str()
15
25
  self.server_ip: str = str()
26
+ self.client_name: str = str()
16
27
  self.client_ip: str = str()
17
28
  self.source_port: int = int()
18
29
  self.destination_port: int = int()
19
30
  self.process_name: str = str()
20
31
  self.thread_id = None
32
+ self.thread_process: str = str()
21
33
  self.info: str = str()
22
- self.error: str = str()
34
+ self.errors: list = list()
35
+ self.protocol: str = str()
36
+ self.protocol2: str = str()
37
+ self.protocol3: str = str()
38
+ self.recorded_file_path: str = str()
39
+ self.action: str = str()
23
40
 
24
- def reinitialize(self) -> None:
41
+ def reinitialize_dynamic_vars(self):
25
42
  """
26
- 'ClientMessage' is being reused, since connection is still established to the server and new requests
27
- are being processed on the same socket, so we need to reinitialize variables that are being updated, like
28
- lists and dictionaries. Added the rest pf the variables that are repopulated to be on the safe side.
29
- :return:
43
+ Reinitialize the dynamic variables of the class for the new cycle.
30
44
  """
31
-
32
- self.request_raw_bytes = bytearray()
33
- self.request_time_received = None
34
- self.request_raw_decoded = None
35
- self.request_body_parsed = None
36
- self.response_list_of_raw_bytes = list()
45
+ self.request_raw_bytes = None
46
+ self.timestamp = None
47
+ self.request_auto_parsed = None
48
+ self.request_custom_parsed = None
37
49
  self.request_raw_hex = None
38
- self.response_list_of_raw_hex = list()
39
- self.response_list_of_raw_decoded = list()
50
+ self.response_raw_bytes = None
51
+ self.response_auto_parsed = None
52
+ self.response_custom_parsed = None
53
+ self.response_raw_hex = None
54
+ self.action = None
55
+ self.info = str()
56
+ self.errors = list()
57
+ self.protocol = str()
58
+ self.protocol2 = str()
59
+ self.protocol3 = str()
60
+ self.recorded_file_path = str()
61
+
62
+ def __iter__(self):
63
+ # __dict__ returns a dictionary containing the instance's attributes
64
+ for key, value in self.__dict__.items():
65
+ if key == 'request_raw_bytes':
66
+ value = str(value)
67
+ elif key == 'timestamp':
68
+ value = value.strftime('%Y-%m-%d-%H:%M:%S.%f')
69
+ elif key == 'request_auto_parsed':
70
+ if isinstance(value, http_parse.HTTPRequestParse):
71
+ value = dicts.convert_complex_object_to_dict(value)
72
+ else:
73
+ value = str(value)
74
+ elif key == 'request_custom_parsed':
75
+ value = dicts.convert_complex_object_to_dict(value)
76
+ elif key == 'response_raw_bytes':
77
+ value = str(value)
78
+ elif key == 'response_auto_parsed':
79
+ value = dicts.convert_complex_object_to_dict(value)
80
+ yield key, value