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
@@ -24,22 +24,23 @@ def convert_der_x509_bytes_to_pem_string(certificate) -> str:
24
24
  return ssl.DER_cert_to_PEM_cert(certificate)
25
25
 
26
26
 
27
- def is_tls(client_socket) -> Optional[Tuple[str, str]]:
27
+ def is_tls(
28
+ client_socket,
29
+ timeout: float = None
30
+ ) -> Optional[Tuple[str, str]]:
28
31
  """
29
32
  Return protocol type of the incoming socket after 'accept()'.
30
33
  :param client_socket: incoming socket after 'accept()'.
34
+ :param timeout: optional timeout for receiving/peeking the first bytes.
31
35
  :return: tuple with content type, protocol type + version.
32
36
  If the length of the first bytes is less than 3, return None.
33
37
  """
34
38
 
35
- first_bytes = receiver.peek_first_bytes(client_socket, bytes_amount=3)
39
+ first_bytes = receiver.peek_first_bytes(client_socket, bytes_amount=3, timeout=timeout)
36
40
 
37
- # Ensure we got enough data.
38
- if len(first_bytes) < 3:
39
- return None
40
-
41
- # Extract the content type and version
42
- content_type, version_major, version_minor = first_bytes
41
+ # Sometimes only one byte is available, so we need to handle that case.
42
+ # convert to a tuple of ints, add three Nones, and keep only the first 3 items.
43
+ content_type, version_major, version_minor = (tuple(first_bytes) + (None, None, None))[:3]
43
44
 
44
45
  # Map TLS content types to their string representation.
45
46
  content_type_map = {
@@ -52,19 +53,19 @@ def is_tls(client_socket) -> Optional[Tuple[str, str]]:
52
53
 
53
54
  # Map TLS version bytes to their string representation.
54
55
  version_map = {
55
- (0x03, 0x00): "SSL 3.0",
56
- (0x03, 0x01): "TLS 1.0",
57
- (0x03, 0x02): "TLS 1.1",
58
- (0x03, 0x03): "TLS 1.2/1.3"
56
+ (0x03, 0x00): "SSLv3.0",
57
+ (0x03, 0x01): "TLSv1.0",
58
+ (0x03, 0x02): "TLSv1.1",
59
+ (0x03, 0x03): "TLSv1.2/1.3"
59
60
  # Remember, you can't definitively differentiate 1.2 and 1.3 just from these bytes
60
61
  }
61
62
 
62
63
  # Get the tuple of the type and version as strings.
63
- tls_content_and_version_tuple: tuple =\
64
+ tls_content_and_version_tuple: tuple[str, str] = \
64
65
  content_type_map.get(content_type), version_map.get((version_major, version_minor))
65
66
 
66
67
  # If both parts of the tuple are not None, return the protocol type.
67
- if tls_content_and_version_tuple[0] and tls_content_and_version_tuple[1]:
68
+ if tls_content_and_version_tuple[0]:
68
69
  return tls_content_and_version_tuple
69
70
  else:
70
71
  return None
@@ -1,23 +1,154 @@
1
1
  import datetime
2
+ import multiprocessing
2
3
 
3
- from ...print_api import print_api
4
+ from ..loggingw import loggingw
4
5
 
5
6
 
6
- def write_accept_error(error_message: str, host: str, process_name: str, statistics_logger, print_kwargs: dict = None):
7
- request_time_sent = datetime.datetime.now()
7
+ LOGGER_NAME: str = 'statistics'
8
+ STATISTICS_HEADER: str = (
9
+ 'request_time_sent,thread_id,engine,source_host,source_ip,tls,protocol,protocol2,protocol3,dest_port,host,path,command,status_code,request_size_bytes,'
10
+ 'response_size_bytes,file_path,process_cmd,action,error')
8
11
 
9
- # If 'message' is not defined, it means there was no execution and there is no need for statistics.
10
- try:
11
- statistics_logger.info(
12
- f"{request_time_sent},"
13
- f"{host},"
14
- f",,,,,,"
15
- f"\"{process_name}\","
16
- f"{error_message}"
12
+
13
+ class StatisticsCSVWriter(loggingw.CsvLogger):
14
+ """
15
+ Class to write statistics to CSV file.
16
+ This can be initiated at the main, and then passed to the thread worker function.
17
+ """
18
+ def __init__(
19
+ self,
20
+ logger_name: str = LOGGER_NAME,
21
+ directory_path: str = None,
22
+ log_queue: multiprocessing.Queue = None,
23
+ add_queue_handler_start_listener_multiprocessing: bool = False,
24
+ add_queue_handler_no_listener_multiprocessing: bool = False
25
+ ):
26
+ """
27
+ Initialize the StatisticsCSVWriter with the directory path for the statistics CSV file.
28
+ :param directory_path: str, the directory path where the statistics CSV file will be created.
29
+ :param log_queue: multiprocessing.Queue, the queue to use for logging in multiprocessing.
30
+ :param add_queue_handler_start_listener_multiprocessing: bool, whether to add a queue handler that will use
31
+ the 'logger_queue' and start the queue listener with the same 'logger_queue' for multiprocessing.
32
+ :param add_queue_handler_no_listener_multiprocessing: bool, whether to add a queue handler that will use
33
+ the 'logger_queue' but will not start the queue listener for multiprocessing. This is useful when you
34
+ already started the queue listener and want to add more handlers to the logger without
35
+ starting a new listener.
36
+
37
+ If you don't set any of 'add_queue_handler_start_listener_multiprocessing' or
38
+ 'add_queue_handler_no_listener_multiprocessing', the logger will be created without a queue handler.
39
+ """
40
+
41
+ super().__init__(
42
+ logger_name=logger_name,
43
+ directory_path=directory_path,
44
+ log_queue=log_queue,
45
+ add_queue_handler_start_listener_multiprocessing=add_queue_handler_start_listener_multiprocessing,
46
+ add_queue_handler_no_listener_multiprocessing=add_queue_handler_no_listener_multiprocessing,
47
+ custom_header=STATISTICS_HEADER
48
+ )
49
+
50
+ def write_row(
51
+ self,
52
+ thread_id: str,
53
+ engine: str,
54
+ source_host: str,
55
+ source_ip: str,
56
+ host: str,
57
+ tls_type: str,
58
+ tls_version: str,
59
+ protocol: str,
60
+ protocol2: str,
61
+ protocol3: str,
62
+ dest_port: str,
63
+ path: str,
64
+ status_code: str,
65
+ command: str,
66
+ request_size_bytes: str,
67
+ response_size_bytes: str,
68
+ recorded_file_path: str = None,
69
+ process_cmd: str = None,
70
+ error: str = None,
71
+ action: str = None,
72
+ timestamp=None,
73
+ ):
74
+ if not timestamp:
75
+ timestamp = datetime.datetime.now()
76
+
77
+ if not tls_type and not tls_version:
78
+ tls_info = ''
79
+ else:
80
+ tls_info = f'{tls_type}|{tls_version}'
81
+
82
+ row_of_cols: list = [
83
+ timestamp,
84
+ thread_id,
85
+ engine,
86
+ source_host,
87
+ source_ip,
88
+ tls_info,
89
+ protocol,
90
+ protocol2,
91
+ protocol3,
92
+ dest_port,
93
+ host,
94
+ path,
95
+ command,
96
+ status_code,
97
+ request_size_bytes,
98
+ response_size_bytes,
99
+ recorded_file_path,
100
+ process_cmd,
101
+ action,
102
+ error
103
+ ]
104
+
105
+ super().write(row_of_cols)
106
+
107
+ def write_accept_error(
108
+ self,
109
+ engine: str,
110
+ source_ip: str,
111
+ source_host: str,
112
+ error_message: str,
113
+ dest_port: str,
114
+ host: str,
115
+ process_name: str,
116
+ thread_id: str = str()
117
+ ):
118
+ """
119
+ Write the error message to the statistics CSV file.
120
+ This is used for easier execution, since most of the parameters will be empty on accept.
121
+
122
+ :param engine: string, engine name.
123
+ :param source_ip: string, source IP address.
124
+ :param source_host: string, source host name.
125
+ :param error_message: string, error message.
126
+ :param dest_port: string, destination port.
127
+ :param host: string, host, the domain or IP address.
128
+ :param process_name: process name, the command line of the process.
129
+ :param thread_id: integer, the id of the thread.
130
+ :return:
131
+ """
132
+
133
+ self.write_row(
134
+ thread_id=thread_id,
135
+ engine=engine,
136
+ source_host=source_host,
137
+ source_ip=source_ip,
138
+ tls_type='',
139
+ tls_version='',
140
+ protocol='',
141
+ protocol2='',
142
+ protocol3='',
143
+ dest_port=dest_port,
144
+ host=host,
145
+ path='',
146
+ status_code='',
147
+ command='',
148
+ request_size_bytes='',
149
+ response_size_bytes='',
150
+ recorded_file_path='',
151
+ process_cmd=process_name,
152
+ action='client_accept',
153
+ error=error_message
17
154
  )
18
- except UnboundLocalError:
19
- pass
20
- except Exception:
21
- message = "Undocumented exception after accept on building statistics."
22
- print_api(message, error_type=True, logger_method='error', traceback_string=True, oneline=True, **print_kwargs)
23
- pass
@@ -0,0 +1,157 @@
1
+ import os
2
+ import subprocess
3
+
4
+ from .. import filesystem, web, process
5
+
6
+
7
+ # Define paths and configuration
8
+ DEFAULT_INSTALLATION_PATH: str = 'C:\\Sysmon'
9
+ SYSMON_FILE_NAME: str = 'Sysmon.exe'
10
+ SYSINTERNALS_SYSMON_URL: str = 'https://download.sysinternals.com/files/Sysmon.zip'
11
+ SYSMON_CONFIG_FILE_NAME: str = 'sysmonconfig.xml'
12
+ SYSMON_CONFIG_FILE_PATH: str = os.path.join(DEFAULT_INSTALLATION_PATH, SYSMON_CONFIG_FILE_NAME)
13
+
14
+
15
+ class ConfigFileNotFoundError(Exception):
16
+ pass
17
+
18
+
19
+ class SymonExecutableNotFoundError(Exception):
20
+ pass
21
+
22
+
23
+ class SysmonAlreadyRunningError(Exception):
24
+ pass
25
+
26
+
27
+ def download_sysmon(installation_path: str = None):
28
+ """
29
+ Install Sysmon on the system.
30
+
31
+ :param installation_path: string, full path where to put the Sysmon executable.
32
+ """
33
+
34
+ if not installation_path:
35
+ installation_path = DEFAULT_INSTALLATION_PATH
36
+
37
+ # Check if the file exists
38
+ if not os.path.exists(installation_path):
39
+ filesystem.create_directory(installation_path)
40
+
41
+ web.download_and_extract_file(SYSINTERNALS_SYSMON_URL, installation_path)
42
+
43
+
44
+ def is_sysmon_running():
45
+ """
46
+ Check if Sysmon is running.
47
+
48
+ :return: boolean, True if Sysmon is running, False otherwise.
49
+ """
50
+
51
+ process_list: list = process.get_running_processes_by_cmdline_pattern(
52
+ pattern=SYSMON_FILE_NAME, first=True, cmdline_case_insensitive=True)
53
+
54
+ if process_list:
55
+ return True
56
+ else:
57
+ return False
58
+
59
+
60
+ def start_as_service(
61
+ installation_path: str = None,
62
+ config_file_path: str = None,
63
+ use_config_in_same_directory: bool = False,
64
+ download_sysmon_if_not_found: bool = False,
65
+ skip_if_running: bool = False
66
+ ):
67
+ """
68
+ Start Sysmon as a service. Besides starting, it installs itself as a service, meaning that on the next boot,
69
+ it will start automatically.
70
+
71
+ :param installation_path: string, full path where to put the Sysmon executable.
72
+ :param config_file_path: string, full path to the configuration file.
73
+ :param use_config_in_same_directory: boolean, if True, the function will use the configuration file in the same
74
+ directory as the Sysmon executable.
75
+ :param download_sysmon_if_not_found: boolean, if True, the function will download Sysmon if it is not
76
+ found in the 'installation_path'.
77
+ :param skip_if_running: boolean,
78
+ True, the function will not start Sysmon if it is already running.
79
+ False, the function will raise 'SysmonAlreadyRunningError' exception if it is already running.
80
+ """
81
+
82
+ # Check if sysmon already running.
83
+ if is_sysmon_running():
84
+ if skip_if_running:
85
+ return
86
+ else:
87
+ raise SysmonAlreadyRunningError("Sysmon is already running.")
88
+
89
+ if config_file_path and use_config_in_same_directory:
90
+ raise ValueError("You cannot use both 'config_file_path' and 'use_config_in_same_directory'.")
91
+
92
+ if use_config_in_same_directory:
93
+ config_file_path = SYSMON_CONFIG_FILE_PATH
94
+
95
+ if config_file_path:
96
+ # Check if the file exists
97
+ if not os.path.exists(config_file_path):
98
+ raise ConfigFileNotFoundError(f"Configuration file '{config_file_path}' not found.")
99
+
100
+ if not installation_path:
101
+ installation_path = DEFAULT_INSTALLATION_PATH
102
+
103
+ sysmon_file_path: str = os.path.join(installation_path, SYSMON_FILE_NAME)
104
+
105
+ # Check if the file exists
106
+ if not os.path.exists(sysmon_file_path):
107
+ if download_sysmon_if_not_found:
108
+ download_sysmon(installation_path)
109
+ else:
110
+ raise SymonExecutableNotFoundError(f"Sysmon executable '{sysmon_file_path}' not found.")
111
+
112
+ # Start Sysmon as a service.
113
+ if config_file_path:
114
+ subprocess.run([sysmon_file_path, '-accepteula', '-i', config_file_path])
115
+ else:
116
+ subprocess.run([sysmon_file_path, '-accepteula', '-i'])
117
+
118
+
119
+ def stop_service(installation_path: str = None):
120
+ """
121
+ Stop Sysmon service.
122
+
123
+ :param installation_path: string, full path where to put the Sysmon executable.
124
+ """
125
+
126
+ if not installation_path:
127
+ installation_path = DEFAULT_INSTALLATION_PATH
128
+
129
+ sysmon_file_path: str = os.path.join(installation_path, SYSMON_FILE_NAME)
130
+
131
+ # Check if the file exists
132
+ if not os.path.exists(sysmon_file_path):
133
+ raise SymonExecutableNotFoundError(f"Sysmon executable '{sysmon_file_path}' not found.")
134
+
135
+ # Stop Sysmon service.
136
+ subprocess.run([sysmon_file_path, '-u'])
137
+
138
+
139
+ def change_config_on_the_fly(config_file_path: str, installation_path: str = None):
140
+ """
141
+ Change the Sysmon configuration on the fly.
142
+
143
+ :param config_file_path: string, full path to the configuration file.
144
+ :param installation_path: string, full path where to put the Sysmon executable.
145
+ """
146
+
147
+ if not installation_path:
148
+ installation_path = DEFAULT_INSTALLATION_PATH
149
+
150
+ sysmon_file_path: str = os.path.join(installation_path, SYSMON_FILE_NAME)
151
+
152
+ # Check if the file exists
153
+ if not os.path.exists(sysmon_file_path):
154
+ raise SymonExecutableNotFoundError(f"Sysmon executable '{sysmon_file_path}' not found.")
155
+
156
+ # Change the configuration on the fly.
157
+ subprocess.run([sysmon_file_path, '-c', config_file_path])
@@ -4,23 +4,64 @@ import subprocess
4
4
  import shutil
5
5
  import time
6
6
 
7
+ from rich.console import Console
8
+
7
9
  from ..print_api import print_api
8
- from .. import permissions
10
+ from ..permissions import ubuntu_permissions
11
+
12
+
13
+ console = Console()
9
14
 
10
15
 
11
- def install_packages(package_list: list[str]):
16
+ def install_packages(
17
+ package_list: list[str],
18
+ timeout_seconds: int = 0,
19
+ ):
12
20
  """
13
21
  Function installs a package using apt-get.
14
22
  :param package_list: list of strings, package names to install.
23
+ :param timeout_seconds: int, if the 'apt-get' command is busy at the moment, the function will wait for
24
+ 'timeout_seconds' seconds before raising an error.
25
+ '-1' means wait indefinitely.
15
26
  :return:
16
27
  """
17
28
 
18
29
  # Construct the command with the package list
19
- command = ["sudo", "apt-get", "install", "-y"] + package_list
30
+ command = ["sudo", "apt", "install", "-y"] + package_list
31
+
32
+ if timeout_seconds != 0:
33
+ command.extend(["-o", f"DPkg::Lock::Timeout={str(timeout_seconds)}"])
20
34
 
21
35
  subprocess.check_call(command)
22
36
 
23
37
 
38
+ def remove_packages(
39
+ package_list: list[str],
40
+ remove_config_files: bool = False,
41
+ remove_dependencies: bool = False,
42
+ ):
43
+ """
44
+ Function removes a list of packages.
45
+ :param package_list: list of strings, package names to remove. Regular removal is through 'apt remove'.
46
+ :param remove_config_files: bool, if True, the config files will be removed also through 'apt purge'.
47
+ :param remove_dependencies: bool, if True, the dependencies will be removed also through 'apt autoremove'.
48
+ :return:
49
+ """
50
+
51
+ # Construct the command with the package list
52
+ command = ["sudo", "apt", "remove", "-y"] + package_list
53
+
54
+ # If remove_config_files is True, add 'purge' to the command
55
+ if remove_config_files:
56
+ command.insert(2, "purge")
57
+
58
+ subprocess.check_call(command)
59
+
60
+ # If remove_dependencies is True, remove the dependencies
61
+ if remove_dependencies:
62
+ subprocess.check_call(["sudo", "apt", "autoremove", "-y"])
63
+
64
+
24
65
  def is_package_installed(package: str) -> bool:
25
66
  """
26
67
  Function checks if a package is installed.
@@ -74,7 +115,7 @@ def update_system_packages():
74
115
  Function updates the system packages.
75
116
  :return:
76
117
  """
77
- subprocess.check_call(['sudo', 'apt-get', 'update'])
118
+ subprocess.check_call(['sudo', 'apt', 'update'])
78
119
 
79
120
 
80
121
  def upgrade_system_packages(apt_update: bool = True):
@@ -88,7 +129,7 @@ def upgrade_system_packages(apt_update: bool = True):
88
129
  if apt_update:
89
130
  update_system_packages()
90
131
 
91
- subprocess.check_call(['sudo', 'apt-get', 'upgrade', '-y'])
132
+ subprocess.check_call(['sudo', 'apt', 'upgrade', '-y'])
92
133
 
93
134
 
94
135
  def is_service_running(service_name: str, user_mode: bool = False, return_false_on_error: bool = False) -> bool:
@@ -175,28 +216,25 @@ def start_service(service_name: str, sudo: bool = False, user_mode: bool = False
175
216
  def start_enable_service_check_availability(
176
217
  service_name: str,
177
218
  wait_time_seconds: float = 30,
178
- exit_on_error: bool = True,
179
219
  start_service_bool: bool = True,
180
220
  enable_service_bool: bool = True,
181
221
  check_service_running: bool = True,
182
222
  user_mode: bool = False,
183
- sudo: bool = True,
184
- print_kwargs: dict = None
185
- ):
223
+ sudo: bool = True
224
+ ) -> int:
186
225
  """
187
226
  Function starts and enables a service and checks its availability.
188
227
 
189
228
  :param service_name: str, the service name.
190
229
  :param wait_time_seconds: float, the time to wait after starting the service before checking the service
191
230
  availability.
192
- :param exit_on_error: bool, if True, the function will exit the program if the service is not available.
193
231
  :param start_service_bool: bool, if True, the service will be started.
194
232
  :param enable_service_bool: bool, if True, the service will be enabled.
195
233
  :param check_service_running: bool, if True, the function will check if the service is running.
196
234
  :param user_mode: bool, if True, the service will be started and enabled in user mode.
197
235
  :param sudo: bool, if True, the command will be executed with sudo.
198
- :param print_kwargs: dict, the print arguments.
199
- :return:
236
+
237
+ :return: int, 0 if the service is running, 1 if the service is not running.
200
238
  """
201
239
 
202
240
  if not start_service_bool and not enable_service_bool:
@@ -209,18 +247,19 @@ def start_enable_service_check_availability(
209
247
  enable_service(service_name, user_mode=user_mode,sudo=sudo)
210
248
 
211
249
  if check_service_running:
212
- print_api(
213
- f"Waiting {str(wait_time_seconds)} seconds for the program to start before availability check...",
214
- **(print_kwargs or {}))
215
- time.sleep(wait_time_seconds)
250
+ print(f"Waiting up to {str(wait_time_seconds)} seconds for the program to start.")
251
+ count: int = 0
252
+ while not is_service_running(service_name, user_mode=user_mode) and count < wait_time_seconds:
253
+ count += 1
254
+ time.sleep(1)
216
255
 
217
256
  if not is_service_running(service_name, user_mode=user_mode):
218
- print_api(
219
- f"[{service_name}] service failed to start.", color='red', error_type=True, **(print_kwargs or {}))
220
- if exit_on_error:
221
- sys.exit(1)
257
+ console.print(f"[{service_name}] service failed to start.", style='red', markup=False)
258
+ return 1
222
259
  else:
223
- print_api(f"[{service_name}] service is running.", color='green', **(print_kwargs or {}))
260
+ console.print(f"[{service_name}] service is running.", style='green', markup=False)
261
+
262
+ return 0
224
263
 
225
264
 
226
265
  def add_path_to_bashrc(as_regular_user: bool = False):
@@ -231,11 +270,11 @@ def add_path_to_bashrc(as_regular_user: bool = False):
231
270
 
232
271
  if as_regular_user:
233
272
  # Get the current non-sudo user
234
- with permissions.temporary_regular_permissions():
273
+ with ubuntu_permissions.temporary_regular_permissions():
235
274
  current_non_sudo_user = os.getlogin()
236
275
 
237
276
  # Get the home path of the current non-sudo user
238
- user_bashrc_path = permissions.expand_user_path(current_non_sudo_user, home_path_bashrc)
277
+ user_bashrc_path = ubuntu_permissions.expand_user_path(current_non_sudo_user, home_path_bashrc)
239
278
  else:
240
279
  user_bashrc_path = os.path.expanduser(home_path_bashrc)
241
280
 
@@ -258,11 +297,11 @@ def add_line_to_bashrc(line: str, as_regular_user: bool = False):
258
297
 
259
298
  if as_regular_user:
260
299
  # Get the current non-sudo user
261
- with permissions.temporary_regular_permissions():
300
+ with ubuntu_permissions.temporary_regular_permissions():
262
301
  current_non_sudo_user = os.getlogin()
263
302
 
264
303
  # Get the home path of the current non-sudo user
265
- user_bashrc_path = permissions.expand_user_path(current_non_sudo_user, home_path_bashrc)
304
+ user_bashrc_path = ubuntu_permissions.expand_user_path(current_non_sudo_user, home_path_bashrc)
266
305
  else:
267
306
  user_bashrc_path = os.path.expanduser(home_path_bashrc)
268
307
 
@@ -293,7 +332,7 @@ def get_command_execution_as_sudo_executer(command: str, add_bash_exec: bool = F
293
332
 
294
333
  command = command.replace('sudo ', '').strip()
295
334
 
296
- sudo_executer_username: str = permissions.get_ubuntu_sudo_executer_username()
335
+ sudo_executer_username: str = ubuntu_permissions.get_sudo_executer_username()
297
336
 
298
337
  if sudo_executer_username:
299
338
  if add_bash_exec: