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
@@ -4,7 +4,7 @@ from pathlib import Path
4
4
  import argparse
5
5
 
6
6
  from . import lists
7
- from ..print_api import print_api
7
+ from .. import print_api
8
8
 
9
9
 
10
10
  def get_nth_character_from_start(input_string: str, nth: int):
@@ -108,7 +108,12 @@ def is_any_string_from_list_in_string(string_list: list, check_string: str) -> b
108
108
  return any(test_string in check_string for test_string in string_list)
109
109
 
110
110
 
111
- def match_pattern_against_string(pattern: str, check_string: str, prefix_suffix: bool = False) -> bool:
111
+ def _match_pattern_against_string(
112
+ pattern: str,
113
+ check_string: str,
114
+ case_insensitive: bool = False,
115
+ prefix_suffix: bool = False
116
+ ) -> bool:
112
117
  """
113
118
  Function checks the 'pattern' against 'check_string' and returns 'True' if pattern matches and 'False' if not.
114
119
 
@@ -121,6 +126,7 @@ def match_pattern_against_string(pattern: str, check_string: str, prefix_suffix:
121
126
 
122
127
  :param pattern: string, can include wildcards as '*'.
123
128
  :param check_string: string, to check the pattern against.
129
+ :param case_insensitive: boolean, if 'True' will treat the 'pattern' and 'check_string' as case-insensitive.
124
130
  :param prefix_suffix: boolean, that sets if the function should return 'True' also for all the cases that wildcard
125
131
  in the beginning of the pattern and in the end of the pattern, since the default behavior of regex to return
126
132
  'False' on these cases.
@@ -152,12 +158,16 @@ def match_pattern_against_string(pattern: str, check_string: str, prefix_suffix:
152
158
  # on complex strings.
153
159
  # return fnmatch.fnmatch(check_string, pattern)
154
160
 
161
+ # Determine the regex flags based on case_insensitive.
162
+ flags = re.IGNORECASE if case_insensitive else 0
163
+
155
164
  def search_pattern(function_pattern):
156
165
  # Use regex to match the pattern.
157
- return re.search(fr'{function_pattern}', check_string)
166
+ return re.search(fr'{function_pattern}', check_string, flags)
158
167
 
159
168
  wildcard_str: str = '*'
160
169
  wildcard_re: str = '.+'
170
+ # wildcard_re: str = '.*' # Adjusted to '.*' to match zero or more characters
161
171
 
162
172
  # Replace the wildcard string '*' with regex wildcard string '.+'.
163
173
  # In regex '.' is a wildcard, but only for 1 character, if you need more than 1 character you should add '+'.
@@ -204,13 +214,86 @@ def match_pattern_against_string(pattern: str, check_string: str, prefix_suffix:
204
214
  return False
205
215
 
206
216
 
207
- def match_list_of_patterns_against_string(patterns: list, check_string: str, prefix_suffix: bool = False) -> bool:
217
+ def match_pattern_against_string(
218
+ pattern: str,
219
+ check_string: str,
220
+ case_insensitive: bool = False,
221
+ prefix_suffix: bool = False
222
+ ) -> bool:
223
+ """
224
+ Function checks the 'pattern' against 'check_string' and returns 'True' if pattern matches and 'False' if not.
225
+
226
+ Example:
227
+ pattern_string = "*ffmpeg*full_build.zip"
228
+ check_string = "https://github.com/GyanD/codexffmpeg/releases/download/5.1.2/ffmpeg-5.1.2-full_build.zip"
229
+ match_pattern_against_string(pattern_string, check_string)
230
+ Result:
231
+ True
232
+
233
+ :param pattern: string, can include wildcards as '*'.
234
+ :param check_string: string, to check the pattern against.
235
+ :param case_insensitive: boolean, if 'True' will treat the 'pattern' and 'check_string' as case-insensitive.
236
+ :param prefix_suffix: boolean, that sets if the function should return 'True' also for all the cases that wildcard
237
+ in the beginning of the pattern and in the end of the pattern, since the default behavior of regex to return
238
+ 'False' on these cases.
239
+
240
+ Example:
241
+ pattern: *test
242
+ check_string: testblabla
243
+ Default regex behavior will return 'False' with 'prefix_suffix' switch set to 'True',
244
+ this case will return 'True'. Same will go for:
245
+ pattern: test*
246
+ check_string: blablatest
247
+
248
+ Why this is good?
249
+ Let's say you have a python script 'example.py' and you want to find all the executed command lines,
250
+ and you want to make sure that this was executed by 'python'. Your python is installed
251
+ in 'c:\\Python310\\python.exe', and you want to match all the possible patterns of 'python' and 'example.py'.
252
+ Pattern:
253
+ *python*example.py
254
+ You want to match 'True' for the next cases:
255
+ python example.py
256
+ c:\\Python310\\python.exe example.py
257
+
258
+ Default regex behavior is to return 'False' on 'python example.py'.
259
+
260
+ :return: boolean.
261
+ """
262
+ # Determine the regex flags based on case_insensitive.
263
+ flags = re.IGNORECASE if case_insensitive else 0
264
+
265
+ # Escape the pattern for regex, then replace '*' with '.*' to match any characters.
266
+ escaped_pattern = re.escape(pattern).replace(r'\*', '.*')
267
+
268
+ # Adjust the pattern to match from the start and/or end based on prefix_suffix.
269
+ if prefix_suffix:
270
+ if not pattern.startswith('*'):
271
+ escaped_pattern = '.*' + escaped_pattern
272
+ if not pattern.endswith('*'):
273
+ escaped_pattern = escaped_pattern + '.*'
274
+ else:
275
+ escaped_pattern = '^' + escaped_pattern + '$'
276
+
277
+ # Compile the regex pattern with the appropriate flags.
278
+ regex_pattern = re.compile(escaped_pattern, flags)
279
+
280
+ # Perform the search and return the result.
281
+ return bool(regex_pattern.search(check_string))
282
+
283
+
284
+ def match_list_of_patterns_against_string(
285
+ patterns: list,
286
+ check_string: str,
287
+ case_insensitive: bool = False,
288
+ prefix_suffix: bool = False
289
+ ) -> bool:
208
290
  """
209
291
  Function checks each pattern in 'patterns' list against 'check_string' and returns 'True' if any pattern matches
210
292
  and 'False' if not.
211
293
 
212
294
  :param patterns: list, of string patterns to check against. May include wildcards.
213
295
  :param check_string: string, to check the pattern against.
296
+ :param case_insensitive: boolean, if 'True' will treat the 'pattern' and 'check_string' as case-insensitive.
214
297
  :param prefix_suffix: boolean, that sets if the function should return 'True' also for all the cases that wildcard
215
298
  in the beginning of the pattern and in the end of the pattern, since the default behavior of regex to return
216
299
  'False' on these cases.
@@ -221,7 +304,8 @@ def match_list_of_patterns_against_string(patterns: list, check_string: str, pre
221
304
  """
222
305
 
223
306
  for pattern in patterns:
224
- if match_pattern_against_string(pattern, check_string, prefix_suffix=prefix_suffix):
307
+ if match_pattern_against_string(
308
+ pattern, check_string, case_insensitive=case_insensitive, prefix_suffix=prefix_suffix):
225
309
  return True
226
310
 
227
311
  return False
@@ -339,7 +423,7 @@ def replace_words_with_values_from_dict(
339
423
 
340
424
 
341
425
  def replace_strings_with_values_from_dict(string_to_replace: str, dictionary: dict) -> str:
342
- """
426
+ r"""
343
427
  Function replaces strings, which are keys with values from dictionary.
344
428
 
345
429
  :param string_to_replace: string, to replace words in.
@@ -453,7 +537,7 @@ def replace_string_in_file(
453
537
  file.writelines(lines)
454
538
 
455
539
  # Output the relevant line numbers
456
- print_api(f"Target string found on the following lines: {changed_lines}", **(print_kwargs or {}))
540
+ print_api.print_api(f"Target string found on the following lines: {changed_lines}", **(print_kwargs or {}))
457
541
  return changed_lines
458
542
 
459
543
 
@@ -487,3 +571,72 @@ def replace_string_in_file_main_argparse():
487
571
  new_string=args.new_string,
488
572
  find_only=args.find_only
489
573
  )
574
+
575
+
576
+ def _replace_string_in_variable():
577
+ """
578
+ Replace string in a string variable, but do it by a meta variable inside the string.
579
+ This is just an example, using the 'Template' class from the 'string' module is a better way to do it.
580
+ """
581
+
582
+ from string import Template
583
+ import os
584
+ import tempfile
585
+ import subprocess
586
+
587
+ get_docker_url: str = "https://get.docker.com"
588
+ docker_proxy_image_name: str = "rpardini/docker-registry-proxy:0.6.5"
589
+ preparation_output_dir: str = str(Path(__file__).parent / "offline-bundle")
590
+
591
+ class BashTemplate(Template):
592
+ # Anything that is not '$', which is a default delimiter in Template class, but also used in bash scripts.
593
+ # The below symbol can be printed from keyboard by holding 'Alt' and typing '0167' on the numeric keypad.
594
+ delimiter = '§'
595
+
596
+ bash_tmpl = BashTemplate(r"""#!/usr/bin/env bash
597
+ #
598
+ set -Eeuo pipefail
599
+
600
+ die() { echo "ERROR: $*" >&2; exit 1; }
601
+ need_root() { [[ $EUID -eq 0 ]] || die "Run as root (use sudo)"; }
602
+ need_cmd() {
603
+ local cmd=$1
604
+ local pkg=${2:-$1} # default package == command
605
+ if ! command -v "$cmd" &>/dev/null; then
606
+ echo "[*] $cmd not found – installing $pkg ..."
607
+ apt-get update -qq
608
+ DEBIAN_FRONTEND=noninteractive \
609
+ apt-get install -y --no-install-recommends "$pkg" || \
610
+ die "Unable to install required package: $pkg"
611
+ fi
612
+ }
613
+
614
+ need_root
615
+ need_cmd curl # binary and pkg are both “curl”
616
+ need_cmd gpg # → apt-get install gpg
617
+
618
+ DRY_LOG=$(curl -fsSL "§url" | bash -s -- --dry-run)
619
+ IMAGE="§proxyimage"
620
+ ARCHIVE="$OUTDIR/registry-proxy-image.tar.gz"
621
+ zip -r "§output_zip" "$OUTDIR"
622
+ """)
623
+
624
+ # Substitute the variables in the bash script template.
625
+ bash_script = bash_tmpl.substitute(
626
+ url=get_docker_url, proxyimage=docker_proxy_image_name, output_zip=preparation_output_dir)
627
+
628
+ # Write it to a secure temporary file.
629
+ with tempfile.NamedTemporaryFile('w', delete=False, suffix='.sh') as f:
630
+ f.write(bash_script)
631
+ temp_path = f.name
632
+ os.chmod(temp_path, 0o755) # make it executable
633
+
634
+ # Decide where the bundle should land (optional argument to the script).
635
+ cmd = ["sudo", temp_path, preparation_output_dir] # use sudo because the script demands root
636
+
637
+ # Run it and stream output live.
638
+ try:
639
+ subprocess.run(cmd, check=True)
640
+ finally:
641
+ # 5. Clean up the temp file unless you want to inspect it.
642
+ os.remove(temp_path)
@@ -18,6 +18,20 @@ def current_thread_id():
18
18
  return thread_id
19
19
 
20
20
 
21
+ def get_current_thread_name():
22
+ return threading.current_thread().name
23
+
24
+
25
+ def set_current_thread_name(name: str):
26
+ threading.current_thread().name = name
27
+
28
+
29
+ def set_current_thread_name_by_process_name():
30
+ import multiprocessing
31
+ current_process_name = multiprocessing.current_process().name
32
+ threading.current_thread().name = current_process_name
33
+
34
+
21
35
  def get_number_of_active_threads():
22
36
  return threading.active_count()
23
37
 
@@ -1,17 +1,26 @@
1
- # v1.0.0 - 02.04.2023 16:20
2
1
  import traceback
3
2
 
4
3
 
5
- def get_as_string(one_line: bool = False, replace_end: str = str()) -> str:
4
+ def get_as_string(
5
+ exc: BaseException = None,
6
+ one_line: bool = False,
7
+ replace_end: str = str()
8
+ ) -> str:
6
9
  """
7
10
  Returns traceback as string.
8
11
 
12
+ :param exc: Exception to get traceback from. If 'None', current exception will be used.
9
13
  :param one_line: If 'True', traceback will be returned as one line.
10
14
  :param replace_end: If 'one_line' is 'True', this string will be used to replace '\n' in traceback.
11
15
  :return: Traceback as string.
12
16
  """
13
17
 
18
+ if exc is None:
19
+ stringed_exception: str = traceback.format_exc()
20
+ else:
21
+ stringed_exception: str = ''.join(traceback.TracebackException.from_exception(exc).format())
22
+
14
23
  if not one_line:
15
- return traceback.format_exc()
24
+ return stringed_exception
16
25
  else:
17
- return traceback.format_exc().replace('\n', replace_end)
26
+ return stringed_exception.replace('\n', replace_end)
@@ -5,9 +5,10 @@ https://oidref.com/1.3.6.1.5.5.7.3.1
5
5
 
6
6
 
7
7
  import ssl
8
+ from typing import Literal, Any
8
9
 
9
10
  from .wrappers import cryptographyw
10
- from .print_api import print_api
11
+ from .wrappers.pywin32w import cert_store
11
12
 
12
13
 
13
14
  # Valid for 3 years from now
@@ -16,72 +17,172 @@ from .print_api import print_api
16
17
  SECONDS_NOT_AFTER_3_YEARS = 3 * 365 * 24 * 60 * 60
17
18
 
18
19
 
19
- def is_certificate_in_store(certificate, issuer_only: bool = False, thumbprint_only: bool = False):
20
+ def get_pem_certificate_from_string(certificate: str) -> str:
20
21
  """
21
- The function will check if the certificate is installed in the Windows certificate store.
22
-
23
- :param certificate: x509 object, certificate to check.
24
- :param issuer_only: bool, if True, will check only by the certificate issuer common name is installed in the store.
25
- The problem that the issuer common name is not unique, so it can be installed multiple times.
26
- :param thumbprint_only: bool, if True, will check only by the certificate thumbprint is installed in the store.
27
- The problem that searching by the thumbprint will not tell you if there are multiple certificates with the same
28
- issuer name.
29
- :return: bool, True if certificate is installed, False if not.
22
+ Some PEM certificates can contain a private key. This function will return only the certificate part.
23
+
24
+ :param certificate: string, PEM certificate.
25
+ :return: string, certificate part.
30
26
  """
31
27
 
32
- # Make sure the certificate is x509.Certificate object.
33
- certificate = cryptographyw.convert_object_to_x509(certificate)
34
- # Get the certificate thumbprint.
35
- thumbprint = cryptographyw.get_sha1_thumbprint_from_x509(certificate)
36
- issuer_common_name: str = cryptographyw.get_issuer_common_name_from_x509(certificate)
28
+ certificate_lines = certificate.split('\n')
29
+ certificate_part = ''
30
+ start = False
31
+ for line in certificate_lines:
32
+ if 'BEGIN CERTIFICATE' in line:
33
+ start = True
34
+ if start:
35
+ certificate_part += line + '\n'
36
+ if 'END CERTIFICATE' in line:
37
+ break
37
38
 
38
- # for store in ["CA", "ROOT", "MY"]:
39
- for cert, encoding, trust in ssl.enum_certificates("ROOT"):
40
- store_certificate = cryptographyw.convert_object_to_x509(cert)
41
- store_issuer_common_name: str = cryptographyw.get_issuer_common_name_from_x509(store_certificate)
42
- store_thumbprint = cryptographyw.get_sha1_thumbprint_from_x509(store_certificate)
43
-
44
- if issuer_only:
45
- if store_issuer_common_name == issuer_common_name:
46
- return True, certificate
47
- elif thumbprint_only:
48
- if store_thumbprint == thumbprint:
49
- return True, certificate
50
- elif not issuer_only and not thumbprint_only:
51
- if store_thumbprint == thumbprint and store_issuer_common_name == issuer_common_name:
52
- return True, certificate
39
+ return certificate_part
53
40
 
54
41
 
55
- def get_certificates_by_issuer_name(issuer_name: str, print_kwargs: dict = None):
42
+ def write_crt_certificate_file_in_pem_format_from_pem_file(
43
+ pem_file_path: str,
44
+ crt_file_path: str
45
+ ):
56
46
  """
57
- The function will return all certificates with the specified issuer name.
47
+ The function will read the PEM certificate file and write it to the CRT file in PEM format.
48
+ The function is used to convert the PEM certificate file to the CRT file.
58
49
 
59
- :param issuer_name: string, issuer name to search for.
60
- :param print_kwargs: dict, that contains all the arguments for 'print_api' function.
50
+ Basically the point here is that the CRT file is the same as the PEM file, but the extension is different,
51
+ and it doesn't support integrated private key.
61
52
 
62
- :return: list, of certificates with the specified issuer name.
53
+ :param pem_file_path: string, path to the PEM certificate file.
54
+ :param crt_file_path: string, path to the CRT certificate file.
63
55
  """
64
56
 
65
- if not print_kwargs:
66
- print_kwargs = {}
57
+ with open(pem_file_path, 'r') as f:
58
+ certificate_string = f.read()
67
59
 
68
- certificates_list = []
60
+ certificate_pem = get_pem_certificate_from_string(certificate_string)
61
+
62
+ with open(crt_file_path, 'w') as f:
63
+ f.write(certificate_pem)
64
+
65
+
66
+ def is_certificate_in_store(
67
+ certificate: Any = None,
68
+ by_cert_issuer: bool = True,
69
+ by_cert_thumbprint: bool = True,
70
+ issuer_name: str = None,
71
+ store_location: str = "ROOT",
72
+ print_kwargs: dict = None
73
+ ) -> tuple[bool, list]:
74
+ """
75
+ The function will check if the CA certificate is installed in the Windows certificate Trusted Root store.
76
+ NO ADMIN RIGHTS NEEDED.
77
+
78
+ :param certificate: x509 object, certificate to check. You can search by certificate or by issuer name.
79
+ Supported types:
80
+ string that is path to file will be imported as bytes object abd converted to x509.Certificate
81
+ After check if it's PEM or DER format.
82
+ string that is PEM certificate will be converted to bytes, then x509.Certificate
83
+ bytes of PEM or DER will be converted to x509.Certificate.
84
+ x509.Certificate will be returned as is.
85
+ :param by_cert_issuer: bool, if True, will check only by the certificate issuer common name is installed in the store.
86
+ The problem if the search will be by issuer alone, that the issuer common name is not unique,
87
+ so it can be installed multiple times.
88
+ :param by_cert_thumbprint: bool, if True, will check only by the certificate thumbprint is installed in the store.
89
+ The problem that searching by the thumbprint alone will not tell you if there are multiple
90
+ certificates with the same issuer name.
91
+ :param issuer_name: string, issuer name to search for. You can search by certificate or by issuer name.
92
+ :param store_location: string, store location to search in. Default is "ROOT".
93
+ :param print_kwargs: dict, print_api kwargs.
94
+ :return: tuple(bool - True if certificate is installed and False if not, list of certificates found)
95
+ """
96
+
97
+ if not by_cert_issuer and not by_cert_thumbprint:
98
+ raise ValueError('At least one of the parameters "by_issuer" or "by_thumbprint" must be True.')
99
+
100
+ if not certificate and not issuer_name:
101
+ raise ValueError('At least one of the parameters "certificate" or "issuer_name" must be provided.')
102
+ elif certificate and issuer_name:
103
+ raise ValueError('Only one of the parameters "certificate" or "issuer_name" must be provided.')
104
+
105
+ if certificate:
106
+ # Make sure the certificate is x509.Certificate object.
107
+ certificate_x509 = cryptographyw.convert_object_to_x509(certificate, print_kwargs=print_kwargs)
108
+ # Get the certificate thumbprint.
109
+ provided_thumbprint = cryptographyw.get_sha1_thumbprint_from_x509(certificate_x509)
110
+ provided_issuer_common_name: str = cryptographyw.get_issuer_common_name_from_x509(certificate_x509)
111
+ elif issuer_name:
112
+ provided_thumbprint = None
113
+ provided_issuer_common_name = issuer_name
114
+ else:
115
+ raise ValueError('At least one of the parameters "certificate" or "issuer_name" must be provided.')
69
116
 
70
- for cert, encoding, trust in ssl.enum_certificates("ROOT"):
117
+ # Iterate over all certificates in the store specifically in the ROOT.
118
+ # for store in ["CA", "ROOT", "MY"]:
119
+ result_found_list: list = []
120
+ found: bool = False
121
+ for cert, encoding, trust in ssl.enum_certificates(store_location):
122
+ # Some certificates in the store can have zero or negative serial number.
123
+ # We will skip them, since they're deprecated by the cryptography library.
71
124
  store_certificate = cryptographyw.convert_object_to_x509(cert)
125
+ if not store_certificate:
126
+ continue
127
+
72
128
  store_issuer_common_name: str = cryptographyw.get_issuer_common_name_from_x509(store_certificate)
129
+ store_thumbprint = cryptographyw.get_sha1_thumbprint_from_x509(store_certificate)
73
130
 
74
- if store_issuer_common_name == issuer_name:
75
- certificates_list.append(store_certificate)
131
+ if certificate:
132
+ if by_cert_issuer and not by_cert_thumbprint:
133
+ if store_issuer_common_name == provided_issuer_common_name:
134
+ result_found_list.append(store_certificate)
135
+ found = True
136
+ elif by_cert_thumbprint and not by_cert_issuer:
137
+ if store_thumbprint == provided_thumbprint:
138
+ result_found_list.append(store_certificate)
139
+ found = True
140
+ elif by_cert_issuer and by_cert_thumbprint:
141
+ if store_thumbprint == provided_thumbprint and store_issuer_common_name == provided_issuer_common_name:
142
+ result_found_list.append(store_certificate)
143
+ found = True
144
+ elif issuer_name:
145
+ if store_issuer_common_name == provided_issuer_common_name:
146
+ result_found_list.append(store_certificate)
147
+ found = True
148
+
149
+ return found, result_found_list
150
+
151
+
152
+ def delete_certificate_by_issuer_name(
153
+ issuer_name: str,
154
+ store_location: Literal[
155
+ "ROOT",
156
+ "CA",
157
+ "MY"] = "ROOT",
158
+ print_kwargs: dict = None
159
+ ):
160
+ """
161
+ NEED ADMIN RIGHTS.
162
+ The function will remove all certificates with the specified issuer name.
163
+ There can be several certificates with this name.
76
164
 
77
- if certificates_list:
78
- for certificate_single in certificates_list:
79
- issuer_name = cryptographyw.get_issuer_common_name_from_x509(certificate_single)
80
- thumbprint = cryptographyw.get_sha1_thumbprint_from_x509(certificate_single)
81
- message = f'Issuer name: {issuer_name} | Thumbprint: {thumbprint}'
82
- print_api(message, **print_kwargs)
83
- else:
84
- message = f'No certificates with issuer name: {issuer_name}'
85
- print_api(message, **print_kwargs)
165
+ :param issuer_name: string, issuer name to search for.
166
+ :param store_location: string, store location to search in. Default is "ROOT".
167
+ :param print_kwargs: dict, print_api kwargs.
168
+ """
169
+
170
+ cert_store.delete_certificate_by_issuer_name(issuer_name, store_location, print_kwargs)
171
+
172
+
173
+ def install_certificate_file(
174
+ file_path: str,
175
+ store_location: Literal[
176
+ "ROOT", "CA", "MY"] = "ROOT",
177
+ print_kwargs: dict = None
178
+ ):
179
+ """
180
+ The function will install the certificate from the file to the specified store location.
181
+ NEED ADMIN RIGHTS.
182
+
183
+ :param file_path: string, full file path to the certificate file.
184
+ :param store_location: string, store location to install the certificate. Default is "ROOT".
185
+ :param print_kwargs: dict, print_api kwargs.
186
+ """
86
187
 
87
- return certificates_list
188
+ cert_store.install_certificate_file(file_path, store_location, print_kwargs)
atomicshop/config_init.py CHANGED
@@ -2,13 +2,17 @@ import os
2
2
 
3
3
  from .file_io import tomls
4
4
  from . import filesystem
5
- from .print_api import print_api
5
+ from . import print_api
6
6
 
7
7
  CONFIG_FILE_NAME = 'config.toml'
8
8
  CONFIG: dict = dict()
9
9
 
10
10
 
11
- def get_config(script_directory: str = None, config_file_name: str = CONFIG_FILE_NAME) -> dict:
11
+ def get_config(
12
+ script_directory: str = None,
13
+ config_file_name: str = CONFIG_FILE_NAME,
14
+ print_kwargs: dict = None
15
+ ) -> dict:
12
16
  """
13
17
  Get the config file content.
14
18
 
@@ -16,6 +20,7 @@ def get_config(script_directory: str = None, config_file_name: str = CONFIG_FILE
16
20
  get the working directory instead.
17
21
  :param config_file_name: string, name of the config file. Default is 'config.toml' as specified in the constant:
18
22
  'CONFIG_FILE_NAME'.
23
+ :param print_kwargs: dict, additional arguments to pass to the print function. Default is None.
19
24
  :return: dict.
20
25
  """
21
26
 
@@ -25,7 +30,7 @@ def get_config(script_directory: str = None, config_file_name: str = CONFIG_FILE
25
30
  if not script_directory:
26
31
  script_directory = filesystem.get_working_directory()
27
32
 
28
- CONFIG = tomls.read_toml_file(f'{script_directory}{os.sep}{config_file_name}')
33
+ CONFIG = tomls.read_toml_file(f'{script_directory}{os.sep}{config_file_name}', **(print_kwargs or {}))
29
34
  return CONFIG
30
35
 
31
36
 
@@ -45,7 +50,7 @@ def write_config(
45
50
  'CONFIG_FILE_NAME'.
46
51
  :param print_message: boolean, if True, the function will print the message about the created config file.
47
52
  Also, it will wait for the user to press Enter to exit the script.
48
- If False, the function will not print anything and will not exit..
53
+ If False, the function will not print anything and will not exit.
49
54
  :return:
50
55
  """
51
56
 
@@ -58,11 +63,11 @@ def write_config(
58
63
 
59
64
  config_file_path = f'{script_directory}{os.sep}{config_file_name}'
60
65
 
61
- if not filesystem.check_file_existence(config_file_path):
66
+ if not filesystem.is_file_exists(config_file_path):
62
67
  tomls.write_toml_file(config, f'{script_directory}{os.sep}{config_file_name}')
63
68
 
64
69
  if print_message:
65
- print_api(f"Created config file: {config_file_path}", color="yellow")
66
- print_api(f"You need to fill it with details.", color="yellow")
70
+ print_api.print_api(f"Created config file: {config_file_path}", color="yellow")
71
+ print_api.print_api(f"You need to fill it with details.", color="yellow")
67
72
  input("Press Enter to exit.")
68
73
  exit()
@@ -1,11 +1,12 @@
1
- # v1.0.2 - 26.03.2023 20:40
2
1
  import sys
3
2
 
4
3
 
5
- def query_positive_negative(question_string: str,
6
- add_first_values_to_question: bool = True,
7
- positive_answers: list = None,
8
- negative_answers: list = None) -> bool:
4
+ def query_positive_negative(
5
+ question_string: str,
6
+ add_first_values_to_question: bool = True,
7
+ positive_answers: list = None,
8
+ negative_answers: list = None
9
+ ) -> bool:
9
10
  """
10
11
  Ask for "yes" / "no" input to a question that is passed as a "question_string".
11
12
  Returns 'True' for 'positive' answers and 'False' for 'negative' answers.
@@ -31,10 +32,8 @@ def query_positive_negative(question_string: str,
31
32
  if add_first_values_to_question:
32
33
  question_string = f'{question_string} [{positive_answers[0]}/{negative_answers[0]}]'
33
34
 
34
- # Defining variable as False for While loop to run
35
- right_answer = False
36
35
  # As long as "right_answer" is False the loop will execute again
37
- while not right_answer:
36
+ while True:
38
37
  # Print the passed question
39
38
  print(question_string)
40
39
  # Get the input from the console in lowercase
@@ -42,22 +41,16 @@ def query_positive_negative(question_string: str,
42
41
 
43
42
  # If the gathered value is in "Yes" answers array
44
43
  if choice in positive_answers:
45
- # "right_answer" variable is True, so the loop will not execute again
46
- right_answer = True
47
44
  # Function will return True
48
45
  return True
49
46
  # Else If the gathered value is in "No" answers array
50
47
  elif choice in negative_answers:
51
- # "right_answer" variable is True, so the loop will not execute again
52
- right_answer = True
53
48
  # Function will return False
54
49
  return False
55
50
  # If the gathered input is not in the arrays
56
51
  else:
57
52
  # Then output to console the message
58
53
  print("Please respond with either:", positive_answers, negative_answers)
59
- # "right_answer" variable stays False, so the loop will execute again
60
- right_answer = False
61
54
 
62
55
 
63
56
  def do_you_want_to_continue_yn(message: str) -> None:
atomicshop/consoles.py ADDED
@@ -0,0 +1,9 @@
1
+ import msvcrt
2
+
3
+
4
+ # === WINDOWS ONLY FUNCTIONS ===========================================================================================
5
+ def wait_any_key(prompt="Press any key to continue..."):
6
+ print(prompt, end="", flush=True)
7
+ msvcrt.getch() # waits for one key press (no Enter needed)
8
+ print() # move to next line
9
+ # === EOF WINDOWS ONLY FUNCTIONS =======================================================================================