atomicshop 2.16.14__py3-none-any.whl → 2.16.16__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.

Potentially problematic release.


This version of atomicshop might be problematic. Click here for more details.

Files changed (29) hide show
  1. atomicshop/__init__.py +1 -1
  2. atomicshop/certificates.py +146 -52
  3. atomicshop/mitm/config_static.py +12 -3
  4. atomicshop/mitm/import_config.py +8 -0
  5. atomicshop/mitm/mitm_main.py +7 -4
  6. atomicshop/mitm/recs_files.py +0 -1
  7. atomicshop/process_poller/process_pool.py +0 -1
  8. atomicshop/process_poller/simple_process_pool.py +0 -1
  9. atomicshop/wrappers/cryptographyw.py +3 -1
  10. atomicshop/wrappers/ctyping/msi_windows_installer/extract_msi_main.py +0 -1
  11. atomicshop/wrappers/elasticsearchw/elasticsearchw.py +2 -20
  12. atomicshop/wrappers/elasticsearchw/install_elastic.py +7 -7
  13. atomicshop/wrappers/factw/get_file_data.py +12 -5
  14. atomicshop/wrappers/githubw.py +0 -1
  15. atomicshop/wrappers/loggingw/handlers.py +31 -16
  16. atomicshop/wrappers/loggingw/loggingw.py +3 -0
  17. atomicshop/wrappers/mongodbw/install_mongodb.py +6 -6
  18. atomicshop/wrappers/mongodbw/{infrastructure.py → mongo_infra.py} +14 -6
  19. atomicshop/wrappers/mongodbw/mongodbw.py +174 -24
  20. atomicshop/wrappers/pywin32w/cert_store.py +89 -0
  21. atomicshop/wrappers/socketw/socket_server_tester.py +5 -1
  22. atomicshop/wrappers/socketw/socket_wrapper.py +71 -2
  23. atomicshop/wrappers/socketw/ssl_base.py +1 -1
  24. {atomicshop-2.16.14.dist-info → atomicshop-2.16.16.dist-info}/METADATA +1 -2
  25. {atomicshop-2.16.14.dist-info → atomicshop-2.16.16.dist-info}/RECORD +29 -28
  26. /atomicshop/wrappers/elasticsearchw/{infrastructure.py → elastic_infra.py} +0 -0
  27. {atomicshop-2.16.14.dist-info → atomicshop-2.16.16.dist-info}/LICENSE.txt +0 -0
  28. {atomicshop-2.16.14.dist-info → atomicshop-2.16.16.dist-info}/WHEEL +0 -0
  29. {atomicshop-2.16.14.dist-info → atomicshop-2.16.16.dist-info}/top_level.txt +0 -0
atomicshop/__init__.py CHANGED
@@ -1,4 +1,4 @@
1
1
  """Atomic Basic functions and classes to make developer life easier"""
2
2
 
3
3
  __author__ = "Den Kras"
4
- __version__ = '2.16.14'
4
+ __version__ = '2.16.16'
@@ -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
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,165 @@ 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()
59
+
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
+ ) -> tuple[bool, list]:
73
+ """
74
+ The function will check if the CA certificate is installed in the Windows certificate Trusted Root store.
75
+ NO ADMIN RIGHTS NEEDED.
76
+
77
+ :param certificate: x509 object, certificate to check. You can search by certificate or by issuer name.
78
+ Supported types:
79
+ string that is path to file will be imported as bytes object abd converted to x509.Certificate
80
+ After check if it's PEM or DER format.
81
+ string that is PEM certificate will be converted to bytes, then x509.Certificate
82
+ bytes of PEM or DER will be converted to x509.Certificate.
83
+ x509.Certificate will be returned as is.
84
+ :param by_cert_issuer: bool, if True, will check only by the certificate issuer common name is installed in the store.
85
+ The problem if the search will be by issuer alone, that the issuer common name is not unique,
86
+ so it can be installed multiple times.
87
+ :param by_cert_thumbprint: bool, if True, will check only by the certificate thumbprint is installed in the store.
88
+ The problem that searching by the thumbprint alone will not tell you if there are multiple
89
+ certificates with the same issuer name.
90
+ :param issuer_name: string, issuer name to search for. You can search by certificate or by issuer name.
91
+ :param store_location: string, store location to search in. Default is "ROOT".
92
+ :return: tuple(bool - True if certificate is installed and False if not, list of certificates found)
93
+ """
67
94
 
68
- certificates_list = []
95
+ if not by_cert_issuer and not by_cert_thumbprint:
96
+ raise ValueError('At least one of the parameters "by_issuer" or "by_thumbprint" must be True.')
97
+
98
+ if not certificate and not issuer_name:
99
+ raise ValueError('At least one of the parameters "certificate" or "issuer_name" must be provided.')
100
+ elif certificate and issuer_name:
101
+ raise ValueError('Only one of the parameters "certificate" or "issuer_name" must be provided.')
102
+
103
+ if certificate:
104
+ # Make sure the certificate is x509.Certificate object.
105
+ certificate_x509 = cryptographyw.convert_object_to_x509(certificate)
106
+ # Get the certificate thumbprint.
107
+ provided_thumbprint = cryptographyw.get_sha1_thumbprint_from_x509(certificate_x509)
108
+ provided_issuer_common_name: str = cryptographyw.get_issuer_common_name_from_x509(certificate_x509)
109
+ elif issuer_name:
110
+ provided_thumbprint = None
111
+ provided_issuer_common_name = issuer_name
112
+ else:
113
+ raise ValueError('At least one of the parameters "certificate" or "issuer_name" must be provided.')
69
114
 
70
- for cert, encoding, trust in ssl.enum_certificates("ROOT"):
115
+ # Iterate over all certificates in the store specifically in the ROOT.
116
+ # for store in ["CA", "ROOT", "MY"]:
117
+ result_found_list: list = []
118
+ found: bool = False
119
+ for cert, encoding, trust in ssl.enum_certificates(store_location):
71
120
  store_certificate = cryptographyw.convert_object_to_x509(cert)
72
121
  store_issuer_common_name: str = cryptographyw.get_issuer_common_name_from_x509(store_certificate)
122
+ store_thumbprint = cryptographyw.get_sha1_thumbprint_from_x509(store_certificate)
73
123
 
74
- if store_issuer_common_name == issuer_name:
75
- certificates_list.append(store_certificate)
124
+ if certificate:
125
+ if by_cert_issuer and not by_cert_thumbprint:
126
+ if store_issuer_common_name == provided_issuer_common_name:
127
+ result_found_list.append(store_certificate)
128
+ found = True
129
+ elif by_cert_thumbprint and not by_cert_issuer:
130
+ if store_thumbprint == provided_thumbprint:
131
+ result_found_list.append(store_certificate)
132
+ found = True
133
+ elif by_cert_issuer and by_cert_thumbprint:
134
+ if store_thumbprint == provided_thumbprint and store_issuer_common_name == provided_issuer_common_name:
135
+ result_found_list.append(store_certificate)
136
+ found = True
137
+ elif issuer_name:
138
+ if store_issuer_common_name == provided_issuer_common_name:
139
+ result_found_list.append(store_certificate)
140
+ found = True
141
+
142
+ return found, result_found_list
143
+
144
+
145
+ def delete_certificate_by_issuer_name(
146
+ issuer_name: str,
147
+ store_location: Literal[
148
+ "ROOT",
149
+ "CA",
150
+ "MY"] = "ROOT",
151
+ print_kwargs: dict = None
152
+ ):
153
+ """
154
+ NEED ADMIN RIGHTS.
155
+ The function will remove all certificates with the specified issuer name.
156
+ There can be several certificates with this name.
76
157
 
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)
158
+ :param issuer_name: string, issuer name to search for.
159
+ :param store_location: string, store location to search in. Default is "ROOT".
160
+ :param print_kwargs: dict, print_api kwargs.
161
+ """
162
+
163
+ cert_store.delete_certificate_by_issuer_name(issuer_name, store_location, print_kwargs)
164
+
165
+
166
+ def install_certificate_file(
167
+ file_path: str,
168
+ store_location: Literal[
169
+ "ROOT", "CA", "MY"] = "ROOT",
170
+ print_kwargs: dict = None
171
+ ):
172
+ """
173
+ The function will install the certificate from the file to the specified store location.
174
+ NEED ADMIN RIGHTS.
175
+
176
+ :param file_path: string, full file path to the certificate file.
177
+ :param store_location: string, store location to install the certificate. Default is "ROOT".
178
+ :param print_kwargs: dict, print_api kwargs.
179
+ """
86
180
 
87
- return certificates_list
181
+ cert_store.install_certificate_file(file_path, store_location, print_kwargs)
@@ -4,9 +4,9 @@ from dataclasses import dataclass
4
4
  from . import import_config
5
5
 
6
6
 
7
- SCRIPT_VERSION: str = '1.7.5'
7
+ SCRIPT_VERSION: str = '1.7.6'
8
8
  """
9
- Added logs backup days
9
+ added ca cert check and installation
10
10
  """
11
11
 
12
12
 
@@ -23,6 +23,8 @@ LIST_OF_BOOLEANS: list = [
23
23
  ('tcp', 'engines_usage'),
24
24
  ('tcp', 'server_response_mode'),
25
25
  ('logrec', 'enable_request_response_recordings_in_logs'),
26
+ ('certificates', 'install_ca_certificate_to_root_store'),
27
+ ('certificates', 'uninstall_unused_ca_certificates_with_mitm_ca_name'),
26
28
  ('certificates', 'default_server_certificate_usage'),
27
29
  ('certificates', 'sni_add_new_domains_to_default_server_certificate'),
28
30
  ('certificates', 'custom_server_certificate_usage'),
@@ -55,8 +57,11 @@ class MainConfig:
55
57
  # Certificates.
56
58
  default_server_certificate_name: str = 'default'
57
59
  ca_certificate_name: str = 'ElaborateCA'
60
+ ca_certificate_pem_filename: str = f'{ca_certificate_name}.pem'
61
+ ca_certificate_crt_filename: str = f'{ca_certificate_name}_for_manual_installation_not_used_by_script.crt'
58
62
  # CA Certificate name and file name without extension.
59
63
  ca_certificate_filepath: str = None
64
+ ca_certificate_crt_filepath: str = None
60
65
  # Default server certificate file name and path.
61
66
  default_server_certificate_filename = f'{default_server_certificate_name}.pem'
62
67
  default_server_certificate_filepath: str = None
@@ -65,7 +70,8 @@ class MainConfig:
65
70
  def update(cls):
66
71
  # This runs after the dataclass is initialized
67
72
  cls.ENGINES_DIRECTORY_PATH = cls.SCRIPT_DIRECTORY + os.sep + cls.ENGINES_DIRECTORY_NAME
68
- cls.ca_certificate_filepath = f'{cls.SCRIPT_DIRECTORY}{os.sep}{cls.ca_certificate_name}.pem'
73
+ cls.ca_certificate_filepath = f'{cls.SCRIPT_DIRECTORY}{os.sep}{cls.ca_certificate_pem_filename}'
74
+ cls.ca_certificate_crt_filepath = f'{cls.SCRIPT_DIRECTORY}{os.sep}{cls.ca_certificate_crt_filename}'
69
75
  cls.default_server_certificate_filepath = \
70
76
  f'{cls.SCRIPT_DIRECTORY}{os.sep}{cls.default_server_certificate_filename}'
71
77
 
@@ -115,6 +121,9 @@ class LogRec:
115
121
 
116
122
  @dataclass
117
123
  class Certificates:
124
+ install_ca_certificate_to_root_store: bool
125
+ uninstall_unused_ca_certificates_with_mitm_ca_name: bool
126
+
118
127
  default_server_certificate_usage: bool
119
128
  sni_add_new_domains_to_default_server_certificate: bool
120
129
 
@@ -117,6 +117,14 @@ def check_configurations() -> int:
117
117
  print_api(message, color='red')
118
118
  return 1
119
119
 
120
+ # This is checked directly in the SocketWrapper.
121
+ # if (config_static.Certificates.install_ca_certificate_to_root_store and not is_admin) or \
122
+ # (config_static.Certificates.uninstall_unused_ca_certificates_with_mitm_ca_name and not is_admin):
123
+ # message: str = \
124
+ # "Need to run the script with administrative rights to install or uninstall CA certificate.\nExiting..."
125
+ # print_api(message, color='red')
126
+ # return 1
127
+
120
128
  return 0
121
129
 
122
130
 
@@ -263,6 +263,10 @@ def mitm_server_main(config_file_path: str):
263
263
  listening_port_list=config_static.TCPServer.listening_port_list,
264
264
  ca_certificate_name=config_static.MainConfig.ca_certificate_name,
265
265
  ca_certificate_filepath=config_static.MainConfig.ca_certificate_filepath,
266
+ ca_certificate_crt_filepath=config_static.MainConfig.ca_certificate_crt_filepath,
267
+ install_ca_certificate_to_root_store=config_static.Certificates.install_ca_certificate_to_root_store,
268
+ uninstall_unused_ca_certificates_with_ca_certificate_name=(
269
+ config_static.Certificates.uninstall_unused_ca_certificates_with_mitm_ca_name),
266
270
  default_server_certificate_usage=config_static.Certificates.default_server_certificate_usage,
267
271
  default_server_certificate_name=config_static.MainConfig.default_server_certificate_name,
268
272
  default_certificate_domain_list=config_static.Certificates.domains_all_times,
@@ -316,11 +320,10 @@ def mitm_server_main(config_file_path: str):
316
320
  dns_gateway_server_list = [base.DEFAULT_IPV4]
317
321
  set_dns_gateway = True
318
322
 
323
+ # Get current network interface state.
324
+ global NETWORK_INTERFACE_IS_DYNAMIC, NETWORK_INTERFACE_IPV4_ADDRESS_LIST
325
+ NETWORK_INTERFACE_IS_DYNAMIC, NETWORK_INTERFACE_IPV4_ADDRESS_LIST = dns.get_default_dns_gateway()
319
326
  if set_dns_gateway:
320
- # Get current network interface state.
321
- global NETWORK_INTERFACE_IS_DYNAMIC, NETWORK_INTERFACE_IPV4_ADDRESS_LIST
322
- NETWORK_INTERFACE_IS_DYNAMIC, NETWORK_INTERFACE_IPV4_ADDRESS_LIST = dns.get_default_dns_gateway()
323
-
324
327
  # Set the DNS gateway to the specified one only if the DNS gateway is dynamic or it is static but different
325
328
  # from the one specified in the configuration file.
326
329
  if (NETWORK_INTERFACE_IS_DYNAMIC or (not NETWORK_INTERFACE_IS_DYNAMIC and
@@ -2,7 +2,6 @@ import datetime
2
2
  import os
3
3
  import multiprocessing
4
4
 
5
- from ..wrappers.loggingw import reading
6
5
  from ..archiver import zips
7
6
  from .. import filesystem
8
7
 
@@ -3,7 +3,6 @@ import multiprocessing
3
3
  import time
4
4
  from typing import Literal, Union
5
5
 
6
- from ..print_api import print_api
7
6
  from .tracers import sysmon_etw, event_log
8
7
  from .pollers import psutil_pywin32wmi_dll
9
8
  from ..wrappers.pywin32w.win_event_log.subscribes import process_terminate
@@ -4,7 +4,6 @@ import time
4
4
 
5
5
  from ..wrappers.pywin32w.win_event_log.subscribes import process_create, process_terminate
6
6
  from .. import get_process_list
7
- from ..print_api import print_api
8
7
 
9
8
 
10
9
  WAIT_BEFORE_PROCESS_TERMINATION_CHECK_SECONDS: float = 3
@@ -36,7 +36,9 @@ def convert_object_to_x509(certificate):
36
36
  """
37
37
 
38
38
  # Check if 'certificate' is a string and a path.
39
- if isinstance(certificate, str) and os.path.isfile(certificate):
39
+ if isinstance(certificate, str):
40
+ if not os.path.isfile(certificate):
41
+ raise FileNotFoundError(f'File not found: {certificate}')
40
42
  # Import the certificate from the path.
41
43
  certificate = file_io.read_file(certificate, file_mode='rb')
42
44
 
@@ -1,5 +1,4 @@
1
1
  import os
2
- import sys
3
2
  import argparse
4
3
 
5
4
  from .base import msi
@@ -6,10 +6,8 @@ from typing import Union
6
6
  from . import config_basic
7
7
  from ...basics import dicts
8
8
 
9
- ELASTIC_WRAPPER = None
10
9
 
11
-
12
- def get_elastic_wrapper(url: str = None, overwrite: bool = False):
10
+ def get_elastic_wrapper(url: str = config_basic.DEFAULT_ELASTIC_URL, overwrite: bool = False):
13
11
  """
14
12
  The function initializes the Elasticsearch wrapper.
15
13
 
@@ -19,25 +17,9 @@ def get_elastic_wrapper(url: str = None, overwrite: bool = False):
19
17
 
20
18
  Usage:
21
19
  elastic_wrapper = get_elastic_wrapper()
22
- or after you initialize it once, you can use it like:
23
- atomicshop.wrappers.elasticsearchw.elasticsearchw.ELASTIC_WRAPPER
24
20
  """
25
21
 
26
- # If no url is provided, use the default url.
27
- if url is None:
28
- url = config_basic.DEFAULT_ELASTIC_URL
29
-
30
- # Get the global variable.
31
- global ELASTIC_WRAPPER
32
- # If the wrapper is not initialized, initialize it.
33
- if ELASTIC_WRAPPER is None:
34
- ELASTIC_WRAPPER = Elasticsearch([url])
35
- # If the wrapper is already initialized, check if it should be overwritten.
36
- else:
37
- if overwrite:
38
- ELASTIC_WRAPPER = Elasticsearch([url])
39
-
40
- return ELASTIC_WRAPPER
22
+ return Elasticsearch([url])
41
23
 
42
24
 
43
25
  def test_connection(elastic_wrapper: Elasticsearch = None):
@@ -4,7 +4,7 @@ from ...print_api import print_api
4
4
  from ... import process
5
5
  from ...permissions import permissions
6
6
  from .. import ubuntu_terminal
7
- from . import config_basic, infrastructure
7
+ from . import config_basic, elastic_infra
8
8
 
9
9
 
10
10
  def install_elastic_kibana_ubuntu(install_elastic: bool = True, install_kibana: bool = True):
@@ -202,29 +202,29 @@ def install_elastic_kibana_ubuntu(install_elastic: bool = True, install_kibana:
202
202
  sys.exit(1)
203
203
 
204
204
  # Check if the configuration file exists.
205
- infrastructure.is_elastic_config_file_exists(exit_on_error=True, output_message=True)
205
+ elastic_infra.is_elastic_config_file_exists(exit_on_error=True, output_message=True)
206
206
 
207
207
  # Check if the specific setting exists or not and set it to false.
208
- infrastructure.modify_xpack_security_setting(setting=False, output_message=True)
208
+ elastic_infra.modify_xpack_security_setting(setting=False, output_message=True)
209
209
 
210
210
  # Check if the setting was really set to false.
211
- if infrastructure.check_xpack_security_setting() is False:
211
+ if elastic_infra.check_xpack_security_setting() is False:
212
212
  print_api(f"The setting is confirmed to be [{config_basic.XPACK_SECURITY_SETTING_NAME}: false].")
213
213
  else:
214
214
  print_api(f"Failed to set [{config_basic.XPACK_SECURITY_SETTING_NAME}: false].")
215
215
  sys.exit(1)
216
216
 
217
- infrastructure.start_elastic_and_check_service_availability()
217
+ elastic_infra.start_elastic_and_check_service_availability()
218
218
 
219
219
  print_api("Creating custom JVM options file with 4GB memory usage.")
220
- infrastructure.create_jvm_options_custom_4gb_memory_heap_file()
220
+ elastic_infra.create_jvm_options_custom_4gb_memory_heap_file()
221
221
 
222
222
  if install_kibana:
223
223
  # Install Kibana.
224
224
  ubuntu_terminal.install_packages([config_basic.UBUNTU_KIBANA_PACKAGE_NAME])
225
225
 
226
226
  # Start and enable Kibana service.
227
- infrastructure.start_kibana_and_check_service_availability()
227
+ elastic_infra.start_kibana_and_check_service_availability()
228
228
 
229
229
  print_api("Installation completed.", color='green')
230
230
  if install_elastic:
@@ -33,11 +33,18 @@ def get_file_data(directory_path: str, firmwares: list = None):
33
33
  """
34
34
 
35
35
  if not firmwares:
36
- firmwares: list = filesystem.get_file_hashes_from_directory(directory_path, recursive=False, add_binary=True)
36
+ firmwares: list = filesystem.get_paths_from_directory(
37
+ directory_path, get_file=True, recursive=False, add_file_binary=True, add_file_hash=True)
37
38
 
38
39
  # Add UIDs to the list.
40
+ final_firmwares: list = []
39
41
  for firmware in firmwares:
40
- if 'uid' not in firmware:
41
- firmware['uid'] = get_uid_from_file(file_binary=firmware['binary'], sha256_hash=firmware['hash'])
42
-
43
- return firmwares
42
+ uid = get_uid_from_file(file_binary=firmware.binary, sha256_hash=firmware.hash)
43
+ final_firmwares.append({
44
+ 'path': firmware.path,
45
+ 'hash': firmware.hash,
46
+ 'binary': firmware.binary,
47
+ 'uid': uid
48
+ })
49
+
50
+ return final_firmwares
@@ -3,7 +3,6 @@ import fnmatch
3
3
 
4
4
  from .. import web, urls
5
5
  from ..print_api import print_api
6
- from ..basics import strings
7
6
 
8
7
 
9
8
  class GitHubWrapper:
@@ -84,27 +84,42 @@ def add_stream_handler(
84
84
 
85
85
  # Function to start the interval-based rotation check
86
86
  def _start_interval_rotation(handler):
87
+ # def check_rotation():
88
+ # while True:
89
+ # next_rollover = _calculate_next_rollover()
90
+ # while datetime.now() < next_rollover:
91
+ # time.sleep(0.1)
92
+ #
93
+ # # Check if the next_rollover has changed (indicating a rollover by an event)
94
+ # if _calculate_next_rollover() != next_rollover:
95
+ # next_rollover = _calculate_next_rollover()
96
+ # break
97
+ #
98
+ # # Perform manual rollover if needed
99
+ # if datetime.now() >= next_rollover:
100
+ # handler.doRollover()
101
+ #
102
+ # # handler.doRollover()
103
+ #
104
+ # def _calculate_next_rollover():
105
+ # return datetime.fromtimestamp(handler.rolloverAt)
87
106
  def check_rotation():
88
- while True:
89
- next_rollover = _calculate_next_rollover()
90
- while datetime.now() < next_rollover:
91
- time.sleep(0.1)
107
+ last_rollover_at = handler.rolloverAt # Initial rollover time
92
108
 
93
- # Check if the next_rollover has changed (indicating a rollover by an event)
94
- if _calculate_next_rollover() != next_rollover:
95
- next_rollover = _calculate_next_rollover()
96
- break
109
+ while True:
110
+ current_time = datetime.now()
111
+ next_rollover = datetime.fromtimestamp(handler.rolloverAt)
97
112
 
98
- # Perform manual rollover if needed
99
- if datetime.now() >= next_rollover:
100
- _rotate_log()
113
+ # Check if the rollover time has passed and it hasn't been handled yet
114
+ if current_time >= next_rollover and handler.rolloverAt == last_rollover_at:
115
+ # Perform manual rollover
116
+ handler.doRollover()
101
117
 
102
- def _calculate_next_rollover():
103
- return datetime.fromtimestamp(handler.rolloverAt)
118
+ # Update last_rollover_at to the new rolloverAt
119
+ last_rollover_at = handler.rolloverAt
104
120
 
105
- # Function to rotate logs
106
- def _rotate_log():
107
- handler.doRollover()
121
+ # Sleep for a short interval before checking again
122
+ time.sleep(0.1)
108
123
 
109
124
  rotation_thread = threading.Thread(target=check_rotation)
110
125
  rotation_thread.daemon = True
@@ -5,6 +5,7 @@ from typing import Literal, Union
5
5
  from . import loggers, handlers
6
6
 
7
7
 
8
+ # noinspection PyPep8Naming
8
9
  def create_logger(
9
10
  logger_name: str,
10
11
  file_path: str = None,
@@ -74,7 +75,9 @@ def create_logger(
74
75
  in the formatter in case you provide 'asctime' element.
75
76
  :param filehandler_rotate_at_rollover_time: bool,
76
77
  If set to True, the log file will be rotated at the rollover time, even if there's nothing to write.
78
+ This behavior overrides the TimedRotatingFileHandler default behavior on doRollover.
77
79
  If set to False, the log file will be rotated after 'when' time, but only when event occurs.
80
+ This is the default doRollover behavior of the TimedRotatingFileHandler.
78
81
  :param filehandler_rotation_date_format: string, Date format to use for the log file rotation.
79
82
  Example for 'when="midnight"': the default date format is '%Y-%m-%d', resulting in filename on rotation like:
80
83
  "test.log.2021-11-25"
@@ -8,7 +8,7 @@ from ... import urls, web
8
8
  from ...permissions import permissions
9
9
  from ...print_api import print_api
10
10
  from .. import msiw
11
- from . import infrastructure
11
+ from . import mongo_infra
12
12
 
13
13
 
14
14
  MONGODB_DOWNLOAD_PAGE_URL: str = 'https://www.mongodb.com/try/download/community'
@@ -111,7 +111,7 @@ def download_install_latest_main(
111
111
  print_api("This function requires administrator privileges.", color='red')
112
112
  return 1
113
113
 
114
- if infrastructure.is_service_running():
114
+ if mongo_infra.is_service_running():
115
115
  print_api("MongoDB service is running - already installed.", color='blue')
116
116
 
117
117
  if not force:
@@ -119,8 +119,8 @@ def download_install_latest_main(
119
119
  else:
120
120
  print_api("MongoDB is service is not running.")
121
121
 
122
- mongo_is_installed: Union[str, None] = infrastructure.is_installed()
123
- if infrastructure.is_installed():
122
+ mongo_is_installed: Union[str, None] = mongo_infra.is_installed()
123
+ if mongo_infra.is_installed():
124
124
  message = f"MongoDB is installed in: {mongo_is_installed}\n" \
125
125
  f"The service is not running. Fix the service or use the 'force' parameter to reinstall."
126
126
  print_api(message, color='yellow')
@@ -151,11 +151,11 @@ def download_install_latest_main(
151
151
 
152
152
  # Check if MongoDB is installed.
153
153
  message: str = ''
154
- mongo_is_installed = infrastructure.is_installed()
154
+ mongo_is_installed = mongo_infra.is_installed()
155
155
  if not mongo_is_installed:
156
156
  message += "MongoDB Executable not found.\n"
157
157
 
158
- if not infrastructure.is_service_running():
158
+ if not mongo_infra.is_service_running():
159
159
  message += "MongoDB service is not running.\n"
160
160
 
161
161
  if message:
@@ -1,9 +1,13 @@
1
+ import os
1
2
  from typing import Union
2
3
 
3
4
  from pymongo import MongoClient
4
5
  import pymongo.errors
5
6
 
6
- from ... import get_process_list, filesystem
7
+ from ... import filesystem
8
+
9
+ if os.name == 'nt':
10
+ from ... import get_process_list
7
11
 
8
12
 
9
13
  WHERE_TO_SEARCH_FOR_MONGODB_EXE: str = 'C:\\Program Files\\MongoDB\\Server\\'
@@ -34,12 +38,16 @@ def is_service_running() -> bool:
34
38
  Check if the MongoDB service is running.
35
39
  :return: bool, True if the MongoDB service is running, False otherwise.
36
40
  """
37
- current_processes: dict = (
38
- get_process_list.GetProcessList(get_method='pywin32', connect_on_init=True).get_processes())
39
41
 
40
- for pid, process_info in current_processes.items():
41
- if MONGODB_EXE_NAME in process_info['name']:
42
- return True
42
+ if os.name == 'nt':
43
+ current_processes: dict = (
44
+ get_process_list.GetProcessList(get_method='pywin32', connect_on_init=True).get_processes())
45
+
46
+ for pid, process_info in current_processes.items():
47
+ if MONGODB_EXE_NAME in process_info['name']:
48
+ return True
49
+ else:
50
+ raise NotImplementedError("This function is not implemented for this OS.")
43
51
 
44
52
  return False
45
53