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

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.15'
@@ -5,8 +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
11
+ from .wrappers.pywin32w import cert_store
10
12
  from .print_api import print_api
11
13
 
12
14
 
@@ -16,72 +18,165 @@ from .print_api import print_api
16
18
  SECONDS_NOT_AFTER_3_YEARS = 3 * 365 * 24 * 60 * 60
17
19
 
18
20
 
19
- def is_certificate_in_store(certificate, issuer_only: bool = False, thumbprint_only: bool = False):
21
+ def get_pem_certificate_from_string(certificate: str) -> str:
20
22
  """
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.
23
+ Some PEM certificates can contain a private key. This function will return only the certificate part.
24
+
25
+ :param certificate: string, PEM certificate.
26
+ :return: string, certificate part.
30
27
  """
31
28
 
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)
29
+ certificate_lines = certificate.split('\n')
30
+ certificate_part = ''
31
+ start = False
32
+ for line in certificate_lines:
33
+ if 'BEGIN CERTIFICATE' in line:
34
+ start = True
35
+ if start:
36
+ certificate_part += line + '\n'
37
+ if 'END CERTIFICATE' in line:
38
+ break
37
39
 
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
40
+ return certificate_part
53
41
 
54
42
 
55
- def get_certificates_by_issuer_name(issuer_name: str, print_kwargs: dict = None):
43
+ def write_crt_certificate_file_in_pem_format_from_pem_file(
44
+ pem_file_path: str,
45
+ crt_file_path: str
46
+ ):
56
47
  """
57
- The function will return all certificates with the specified issuer name.
48
+ The function will read the PEM certificate file and write it to the CRT file in PEM format.
49
+ The function is used to convert the PEM certificate file to the CRT file.
58
50
 
59
- :param issuer_name: string, issuer name to search for.
60
- :param print_kwargs: dict, that contains all the arguments for 'print_api' function.
51
+ Basically the point here is that the CRT file is the same as the PEM file, but the extension is different,
52
+ and it doesn't support integrated private key.
61
53
 
62
- :return: list, of certificates with the specified issuer name.
54
+ :param pem_file_path: string, path to the PEM certificate file.
55
+ :param crt_file_path: string, path to the CRT certificate file.
63
56
  """
64
57
 
65
- if not print_kwargs:
66
- print_kwargs = {}
58
+ with open(pem_file_path, 'r') as f:
59
+ certificate_string = f.read()
60
+
61
+ certificate_pem = get_pem_certificate_from_string(certificate_string)
62
+
63
+ with open(crt_file_path, 'w') as f:
64
+ f.write(certificate_pem)
65
+
66
+
67
+ def is_certificate_in_store(
68
+ certificate: any = None,
69
+ by_cert_issuer: bool = True,
70
+ by_cert_thumbprint: bool = True,
71
+ issuer_name: str = None,
72
+ store_location: str = "ROOT"
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
+ :return: tuple(bool - True if certificate is installed and False if not, list of certificates found)
94
+ """
67
95
 
68
- certificates_list = []
96
+ if not by_cert_issuer and not by_cert_thumbprint:
97
+ raise ValueError('At least one of the parameters "by_issuer" or "by_thumbprint" must be True.')
98
+
99
+ if not certificate and not issuer_name:
100
+ raise ValueError('At least one of the parameters "certificate" or "issuer_name" must be provided.')
101
+ elif certificate and issuer_name:
102
+ raise ValueError('Only one of the parameters "certificate" or "issuer_name" must be provided.')
103
+
104
+ if certificate:
105
+ # Make sure the certificate is x509.Certificate object.
106
+ certificate_x509 = cryptographyw.convert_object_to_x509(certificate)
107
+ # Get the certificate thumbprint.
108
+ provided_thumbprint = cryptographyw.get_sha1_thumbprint_from_x509(certificate_x509)
109
+ provided_issuer_common_name: str = cryptographyw.get_issuer_common_name_from_x509(certificate_x509)
110
+ elif issuer_name:
111
+ provided_thumbprint = None
112
+ provided_issuer_common_name = issuer_name
113
+ else:
114
+ raise ValueError('At least one of the parameters "certificate" or "issuer_name" must be provided.')
69
115
 
70
- for cert, encoding, trust in ssl.enum_certificates("ROOT"):
116
+ # Iterate over all certificates in the store specifically in the ROOT.
117
+ # for store in ["CA", "ROOT", "MY"]:
118
+ result_found_list: list = []
119
+ found: bool = False
120
+ for cert, encoding, trust in ssl.enum_certificates(store_location):
71
121
  store_certificate = cryptographyw.convert_object_to_x509(cert)
72
122
  store_issuer_common_name: str = cryptographyw.get_issuer_common_name_from_x509(store_certificate)
123
+ store_thumbprint = cryptographyw.get_sha1_thumbprint_from_x509(store_certificate)
73
124
 
74
- if store_issuer_common_name == issuer_name:
75
- certificates_list.append(store_certificate)
125
+ if certificate:
126
+ if by_cert_issuer and not by_cert_thumbprint:
127
+ if store_issuer_common_name == provided_issuer_common_name:
128
+ result_found_list.append(store_certificate)
129
+ found = True
130
+ elif by_cert_thumbprint and not by_cert_issuer:
131
+ if store_thumbprint == provided_thumbprint:
132
+ result_found_list.append(store_certificate)
133
+ found = True
134
+ elif by_cert_issuer and by_cert_thumbprint:
135
+ if store_thumbprint == provided_thumbprint and store_issuer_common_name == provided_issuer_common_name:
136
+ result_found_list.append(store_certificate)
137
+ found = True
138
+ elif issuer_name:
139
+ if store_issuer_common_name == provided_issuer_common_name:
140
+ result_found_list.append(store_certificate)
141
+ found = True
142
+
143
+ return found, result_found_list
144
+
145
+
146
+ def delete_certificate_by_issuer_name(
147
+ issuer_name: str,
148
+ store_location: Literal[
149
+ "ROOT",
150
+ "CA",
151
+ "MY"] = "ROOT",
152
+ print_kwargs: dict = None
153
+ ):
154
+ """
155
+ NEED ADMIN RIGHTS.
156
+ The function will remove all certificates with the specified issuer name.
157
+ There can be several certificates with this name.
76
158
 
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)
159
+ :param issuer_name: string, issuer name to search for.
160
+ :param store_location: string, store location to search in. Default is "ROOT".
161
+ :param print_kwargs: dict, print_api kwargs.
162
+ """
163
+
164
+ cert_store.delete_certificate_by_issuer_name(issuer_name, store_location, print_kwargs)
165
+
166
+
167
+ def install_certificate_file(
168
+ file_path: str,
169
+ store_location: Literal[
170
+ "ROOT", "CA", "MY"] = "ROOT",
171
+ print_kwargs: dict = None
172
+ ):
173
+ """
174
+ The function will install the certificate from the file to the specified store location.
175
+ NEED ADMIN RIGHTS.
176
+
177
+ :param file_path: string, full file path to the certificate file.
178
+ :param store_location: string, store location to install the certificate. Default is "ROOT".
179
+ :param print_kwargs: dict, print_api kwargs.
180
+ """
86
181
 
87
- return certificates_list
182
+ 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
@@ -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
 
@@ -0,0 +1,89 @@
1
+ from typing import Literal
2
+ import win32crypt as wcrypt
3
+
4
+ from ...print_api import print_api
5
+ from ... import certificates
6
+
7
+
8
+ # lpszStoreProvider
9
+ CERT_STORE_PROV_SYSTEM = 0x0000000A
10
+ # dwFlags
11
+ CERT_SYSTEM_STORE_LOCAL_MACHINE = 0x00020000
12
+ CERT_SYSTEM_STORE_CURRENT_USER = 0x00010000
13
+ CERT_CLOSE_STORE_FORCE_FLAG = 0x00000001
14
+ CRYPT_STRING_BASE64HEADER = 0x00000000
15
+ X509_ASN_ENCODING = 0x00000001
16
+ CERT_STORE_ADD_REPLACE_EXISTING = 3
17
+
18
+
19
+ STORE_LOCATION_TO_CERT_SYSTEM_STORE: dict = {
20
+ "ROOT": CERT_SYSTEM_STORE_LOCAL_MACHINE,
21
+ "CA": CERT_SYSTEM_STORE_LOCAL_MACHINE,
22
+ "MY": CERT_SYSTEM_STORE_CURRENT_USER
23
+ }
24
+
25
+
26
+ def delete_certificate_by_issuer_name(
27
+ issuer_name: str,
28
+ store_location: Literal[
29
+ "ROOT",
30
+ "CA",
31
+ "MY"] = "ROOT",
32
+ print_kwargs: dict = None
33
+ ):
34
+ """
35
+ NEED ADMIN RIGHTS.
36
+ The function will remove all certificates with the specified issuer name.
37
+ There can be several certificates with this name.
38
+
39
+ :param issuer_name: string, issuer name to search for.
40
+ :param store_location: string, store location to search in. Default is "ROOT".
41
+ :param print_kwargs: dict, print_api kwargs.
42
+ """
43
+
44
+ store = wcrypt.CertOpenStore(
45
+ CERT_STORE_PROV_SYSTEM, 0, None, STORE_LOCATION_TO_CERT_SYSTEM_STORE[store_location], store_location)
46
+
47
+ for cert in store.CertEnumCertificatesInStore():
48
+ # Certificate properties.
49
+ # cert.CertEnumCertificateContextProperties()
50
+ subject_string: str = wcrypt.CertNameToStr(cert.Subject)
51
+ if subject_string == issuer_name:
52
+ # Remove the certificate.
53
+ cert.CertDeleteCertificateFromStore()
54
+ print_api(f"Removed the Certificate with issuer: {issuer_name}", **(print_kwargs or {}))
55
+
56
+ # There is an exception about store close.
57
+ # store.CertCloseStore()
58
+
59
+
60
+ def install_certificate_file(
61
+ file_path: str,
62
+ store_location: Literal[
63
+ "ROOT", "CA", "MY"] = "ROOT",
64
+ print_kwargs: dict = None
65
+ ):
66
+ """
67
+ NEED ADMIN RIGHTS.
68
+ The function will install the certificate from the file to the specified store location.
69
+
70
+ :param file_path: string, full file path to the certificate file.
71
+ :param store_location: string, store location to install the certificate. Default is "ROOT".
72
+ :param print_kwargs: dict, print_api kwargs.
73
+ """
74
+
75
+ with open(file_path, 'r') as f:
76
+ certificate_string = f.read()
77
+
78
+ certificate_pem = certificates.get_pem_certificate_from_string(certificate_string)
79
+
80
+ certificate_bytes = wcrypt.CryptStringToBinary(certificate_pem, CRYPT_STRING_BASE64HEADER)[0]
81
+
82
+ store = wcrypt.CertOpenStore(
83
+ CERT_STORE_PROV_SYSTEM, 0, None, STORE_LOCATION_TO_CERT_SYSTEM_STORE[store_location], store_location)
84
+
85
+ store.CertAddEncodedCertificateToStore(X509_ASN_ENCODING, certificate_bytes, CERT_STORE_ADD_REPLACE_EXISTING)
86
+ store.CertCloseStore(CERT_CLOSE_STORE_FORCE_FLAG)
87
+
88
+ message = f"Certificate installed to the store: [{store_location}] from file: [{file_path}]"
89
+ print_api(message, **(print_kwargs or {}))
@@ -1,10 +1,13 @@
1
1
  import threading
2
2
  import select
3
3
  from typing import Literal, Union
4
+ from pathlib import Path
4
5
 
5
6
  from ..psutilw import networks
7
+ from ..certauthw import certauthw
6
8
  from ...script_as_string_processor import ScriptAsStringProcessor
7
- from ... import queues, filesystem
9
+ from ...permissions import permissions
10
+ from ... import queues, filesystem, certificates
8
11
  from ...basics import booleans
9
12
  from ...print_api import print_api
10
13
 
@@ -30,6 +33,9 @@ class SocketWrapper:
30
33
  forwarding_dns_service_ipv4_list___only_for_localhost: list = None,
31
34
  ca_certificate_name: str = None,
32
35
  ca_certificate_filepath: str = None,
36
+ ca_certificate_crt_filepath: str = None,
37
+ install_ca_certificate_to_root_store: bool = False,
38
+ uninstall_unused_ca_certificates_with_ca_certificate_name: bool = False,
33
39
  default_server_certificate_usage: bool = False,
34
40
  default_server_certificate_name: str = None,
35
41
  default_certificate_domain_list: list = None,
@@ -68,7 +74,13 @@ class SocketWrapper:
68
74
  Example: '0.0.0.0'. For all interfaces.
69
75
  :param listening_port_list: list, of ports that will be listened on.
70
76
  :param ca_certificate_name: CA certificate name.
71
- :param ca_certificate_filepath: CA certificate file path.
77
+ :param ca_certificate_filepath: CA certificate file path with '.pem' extension.
78
+ :param ca_certificate_crt_filepath: CA certificate file path with '.crt' extension.
79
+ This file will be created from the PEM file 'ca_certificate_filepath' for manual installation.
80
+ :param install_ca_certificate_to_root_store: boolean, if True, CA certificate will be installed
81
+ to the root store.
82
+ :param uninstall_unused_ca_certificates_with_ca_certificate_name: boolean, if True, unused CA certificates
83
+ with provided 'ca_certificate_name' will be uninstalled.
72
84
  :param default_server_certificate_usage: boolean, if True, default server certificate will be used
73
85
  for each incoming socket.
74
86
  :param sni_custom_callback_function: callable, custom callback function that will be executed when
@@ -150,6 +162,10 @@ class SocketWrapper:
150
162
  self.listening_port_list: list[int] = listening_port_list
151
163
  self.ca_certificate_name: str = ca_certificate_name
152
164
  self.ca_certificate_filepath: str = ca_certificate_filepath
165
+ self.ca_certificate_crt_filepath: str = ca_certificate_crt_filepath
166
+ self.install_ca_certificate_to_root_store: bool = install_ca_certificate_to_root_store
167
+ self.uninstall_unused_ca_certificates_with_ca_certificate_name: bool = \
168
+ uninstall_unused_ca_certificates_with_ca_certificate_name
153
169
  self.default_server_certificate_usage: bool = default_server_certificate_usage
154
170
  self.default_server_certificate_name: str = default_server_certificate_name
155
171
  self.default_certificate_domain_list: list = default_certificate_domain_list
@@ -270,6 +286,59 @@ class SocketWrapper:
270
286
  error_messages.append(f"Port [{port}] is already in use by process: {process_info}")
271
287
  raise SocketWrapperPortInUseError("\n".join(error_messages))
272
288
 
289
+ if not filesystem.is_file_exists(file_path=self.ca_certificate_filepath):
290
+ # Initialize CertAuthWrapper.
291
+ ca_certificate_directory: str = str(Path(self.ca_certificate_filepath).parent)
292
+ certauth_wrapper = certauthw.CertAuthWrapper(
293
+ ca_certificate_name=self.ca_certificate_name,
294
+ ca_certificate_filepath=self.ca_certificate_filepath,
295
+ server_certificate_directory=ca_certificate_directory
296
+ )
297
+
298
+ # Create CA certificate if it doesn't exist.
299
+ certauth_wrapper.create_use_ca_certificate()
300
+
301
+ certificates.write_crt_certificate_file_in_pem_format_from_pem_file(
302
+ pem_file_path=self.ca_certificate_filepath,
303
+ crt_file_path=self.ca_certificate_crt_filepath)
304
+
305
+ if self.install_ca_certificate_to_root_store:
306
+ if not self.ca_certificate_filepath:
307
+ message = "You set [install_ca_certificate_to_root_store = True],\n" \
308
+ "But you didn't set [ca_certificate_filepath]."
309
+ raise SocketWrapperConfigurationValuesError(message)
310
+
311
+ # Before installation check if there are any unused certificates with the same name.
312
+ if self.uninstall_unused_ca_certificates_with_ca_certificate_name:
313
+ # Check how many certificates with our ca certificate name are installed.
314
+ is_installed_by_name, certificate_list_by_name = certificates.is_certificate_in_store(
315
+ issuer_name=self.ca_certificate_name)
316
+ # If there is more than one certificate with the same name, delete them all.
317
+ if is_installed_by_name and len(certificate_list_by_name) > 1:
318
+ certificates.delete_certificate_by_issuer_name(self.ca_certificate_name)
319
+ # If there is only one certificate with the same name, check if it is the same certificate.
320
+ elif is_installed_by_name and len(certificate_list_by_name) == 1:
321
+ is_installed_by_file, certificate_list_by_file = certificates.is_certificate_in_store(
322
+ certificate=self.ca_certificate_filepath, by_cert_thumbprint=True, by_cert_issuer=True)
323
+ # If the certificate is not the same, delete it.
324
+ if not is_installed_by_file:
325
+ if not permissions.is_admin():
326
+ raise SocketWrapperConfigurationValuesError(
327
+ "You need to run the script with admin rights to uninstall the unused certificates.")
328
+ certificates.delete_certificate_by_issuer_name(
329
+ self.ca_certificate_name, store_location="ROOT", print_kwargs={'logger': self.logger})
330
+
331
+ if self.install_ca_certificate_to_root_store:
332
+ # Install CA certificate to the root store if it is not installed.
333
+ is_installed_by_file, certificate_list_by_file = certificates.is_certificate_in_store(
334
+ certificate=self.ca_certificate_filepath, by_cert_thumbprint=True, by_cert_issuer=True)
335
+ if not is_installed_by_file:
336
+ if not permissions.is_admin():
337
+ raise SocketWrapperConfigurationValuesError(
338
+ "You need to run the script with admin rights to install the CA certificate.")
339
+ certificates.install_certificate_file(
340
+ self.ca_certificate_filepath, store_location="ROOT", print_kwargs={'logger': self.logger})
341
+
273
342
  # Creating listening sockets.
274
343
  def create_socket_ipv4_tcp(self, ip_address: str, port: int):
275
344
  self.sni_execute_extended = True
@@ -60,7 +60,7 @@ def is_tls(client_socket) -> Optional[Tuple[str, str]]:
60
60
  }
61
61
 
62
62
  # Get the tuple of the type and version as strings.
63
- tls_content_and_version_tuple: tuple =\
63
+ tls_content_and_version_tuple: tuple = \
64
64
  content_type_map.get(content_type), version_map.get((version_major, version_minor))
65
65
 
66
66
  # If both parts of the tuple are not None, return the protocol type.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: atomicshop
3
- Version: 2.16.14
3
+ Version: 2.16.15
4
4
  Summary: Atomic functions and classes to make developer life easier
5
5
  Author: Denis Kras
6
6
  License: MIT License
@@ -1,9 +1,9 @@
1
- atomicshop/__init__.py,sha256=waCY7DPxgBrQX24BI-0hmphU84XoLtMKDMT9OE3ps6g,124
1
+ atomicshop/__init__.py,sha256=UzNeZyRkmLnYywv5edPjB0_p7zEgYfoGzcusp1FpodI,124
2
2
  atomicshop/_basics_temp.py,sha256=6cu2dd6r2dLrd1BRNcVDKTHlsHs_26Gpw8QS6v32lQ0,3699
3
3
  atomicshop/_create_pdf_demo.py,sha256=Yi-PGZuMg0RKvQmLqVeLIZYadqEZwUm-4A9JxBl_vYA,3713
4
4
  atomicshop/_patch_import.py,sha256=ENp55sKVJ0e6-4lBvZnpz9PQCt3Otbur7F6aXDlyje4,6334
5
5
  atomicshop/appointment_management.py,sha256=BsYH_PClTGLVazcuNjt30--hpXKYjSmHp1R1iQbM4Hc,7330
6
- atomicshop/certificates.py,sha256=J-cmd6Rpq3zZyzsOH-GcdqIXdg2UwM8_E9mg7XtUph8,3787
6
+ atomicshop/certificates.py,sha256=ssOTD1uN4OaB9TU7mI0Dg_sSGFb6Xxw28A7TtyKmMMY,7637
7
7
  atomicshop/command_line_processing.py,sha256=u5yT9Ger_cu7ni5ID0VFlRbVD46ARHeNC9tRM-_YXrQ,1038
8
8
  atomicshop/config_init.py,sha256=BSxc2FhytQPv06g5z9wbAXuA6oYCAsAJLxu_mTExhwI,2491
9
9
  atomicshop/console_output.py,sha256=AOSJjrRryE97PAGtgDL03IBtWSi02aNol8noDnW3k6M,4667
@@ -122,13 +122,13 @@ atomicshop/file_io/tomls.py,sha256=ol8EvQPf9sryTmZUf1v55BYSUQ6ml7HVVBHpNKbsIlA,9
122
122
  atomicshop/file_io/xlsxs.py,sha256=v_dyg9GD4LqgWi6wA1QuWRZ8zG4ZwB6Dz52ytdcmmmI,2184
123
123
  atomicshop/file_io/xmls.py,sha256=zh3SuK-dNaFq2NDNhx6ivcf4GYCfGM8M10PcEwDSpxk,2104
124
124
  atomicshop/mitm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
125
- atomicshop/mitm/config_static.py,sha256=ds31SXyOnOEvd7RAVWvw1o8MrQTVWWZCZeQX0wUptbM,7171
125
+ atomicshop/mitm/config_static.py,sha256=UNvRTb3ZuFVGZpF33fvaIf0xw_VGyml2ExIwqW_uYcg,7777
126
126
  atomicshop/mitm/config_toml_editor.py,sha256=2p1CMcktWRR_NW-SmyDwylu63ad5e0-w1QPMa8ZLDBw,1635
127
127
  atomicshop/mitm/connection_thread_worker.py,sha256=1MBpRoLpzWJMvxqQKizo6IVQ4XYsbKGsjxianNQLUlE,20051
128
- atomicshop/mitm/import_config.py,sha256=5peDr6cT0ZWK3J53yG-VEew77CKrvB88CphM10SQd3I,7868
128
+ atomicshop/mitm/import_config.py,sha256=_nu8mgA-M4s6dZ8_QWx3x0aVb75upvsCuX_PIUg4X2w,8345
129
129
  atomicshop/mitm/initialize_engines.py,sha256=kBG8TBnyFuwlJ1uKaWDzc5AiZNpwdvouq2pr-PYrdEA,8349
130
130
  atomicshop/mitm/message.py,sha256=d_sm3O_aoZf87dDQP44xOMNEG-uZBN1ZecQgMCacbZs,1814
131
- atomicshop/mitm/mitm_main.py,sha256=N7ckWZhGkkIO2dJ7m7mnh_h7lQTihUeSAfzTTsHEKts,20903
131
+ atomicshop/mitm/mitm_main.py,sha256=CdCv4nYt_jwd23AI14v6lC2H8SZeIZqsXjFhwq61UtM,21285
132
132
  atomicshop/mitm/recs_files.py,sha256=btOuYQca4DuBOAKp9OY21HGjeEVOx9r_k-AnZOqs3Dk,3007
133
133
  atomicshop/mitm/shared_functions.py,sha256=hplm98tz8pgJ4WHUVI9sf_oVqUM2KJ1Y2pD6EFSb8P0,1879
134
134
  atomicshop/mitm/statistic_analyzer.py,sha256=AzL9rQhg0tLJj33gZfxdwWghmbXGLh_HyMBDpzuBmsQ,24709
@@ -178,7 +178,7 @@ atomicshop/wrappers/_process_wrapper_curl.py,sha256=XkZZXYl7D0Q6UfdWqy-18AvpU0yV
178
178
  atomicshop/wrappers/_process_wrapper_tar.py,sha256=WUMZFKNrlG4nJP9tWZ51W7BR1j_pIjsjgyAStmWjRGs,655
179
179
  atomicshop/wrappers/astw.py,sha256=VkYfkfyc_PJLIOxByT6L7B8uUmKY6-I8XGZl4t_z828,4239
180
180
  atomicshop/wrappers/configparserw.py,sha256=JwDTPjZoSrv44YKwIRcjyUnpN-FjgXVfMqMK_tJuSgU,22800
181
- atomicshop/wrappers/cryptographyw.py,sha256=_5jgzQjgCDQrFN1f6_0y-IdIR6bGaYIjIy92bjJRuHI,13168
181
+ atomicshop/wrappers/cryptographyw.py,sha256=LfzTnwvJE03G6WZryOOf43VKhhnyMakzHpn8DPPCoy4,13252
182
182
  atomicshop/wrappers/ffmpegw.py,sha256=wcq0ZnAe0yajBOuTKZCCaKI7CDBjkq7FAgdW5IsKcVE,6031
183
183
  atomicshop/wrappers/githubw.py,sha256=AQcFuT5mvDUNT_cI31MwkJ7srdhMtttF8FyXS8vs5cU,12270
184
184
  atomicshop/wrappers/msiw.py,sha256=GQLqud72nfex3kvO1bJSruNriCYTYX1_G1gSf1MPkIA,6118
@@ -278,6 +278,7 @@ atomicshop/wrappers/pycharmw/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NM
278
278
  atomicshop/wrappers/pycharmw/ubuntu.py,sha256=l2_9SXrw7ApSvFOROGZdPZa5ylZBKofk4sYqf4IugQs,1223
279
279
  atomicshop/wrappers/pycharmw/win.py,sha256=jdnTkUqZX_BrMW8AmW-xGtxdV-wmmNr_NMA2jB6JHsQ,2725
280
280
  atomicshop/wrappers/pywin32w/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
281
+ atomicshop/wrappers/pywin32w/cert_store.py,sha256=bpFm5nH9j6I9eJdLjPnSvo-g4OyJO7Sb5VddzVE9-UM,3156
281
282
  atomicshop/wrappers/pywin32w/console.py,sha256=LstHajPLgXp9qQxFNR44QfH10nOnNp3bCJquxaTquns,1175
282
283
  atomicshop/wrappers/pywin32w/winshell.py,sha256=i2bKiMldPU7_azsD5xGQDdMwjaM7suKJd3k0Szmcs6c,723
283
284
  atomicshop/wrappers/pywin32w/win_event_log/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -303,13 +304,13 @@ atomicshop/wrappers/socketw/sender.py,sha256=d7YQFlCBMFTYtkGxbS-8cm5rh5WWFeBVvrE
303
304
  atomicshop/wrappers/socketw/sni.py,sha256=fVwyh3h9IqfLMnf4__bMIzcF4c-Kk9mlbDWMRXKN-ow,17155
304
305
  atomicshop/wrappers/socketw/socket_client.py,sha256=FNmTt94YvjZP0X4RPb7icO3xD_nBHQ_XynnObdWFiAU,19682
305
306
  atomicshop/wrappers/socketw/socket_server_tester.py,sha256=wAwyst8YdVyVfZfERav1A9_OnMJAiVBy-4uY0RpNqkU,6339
306
- atomicshop/wrappers/socketw/socket_wrapper.py,sha256=g7f_8RkW80EZeQWNTqGYnfrQkgAI56T3SwWybq7ZsXg,28521
307
- atomicshop/wrappers/socketw/ssl_base.py,sha256=k4V3gwkbq10MvOH4btU4onLX2GNOsSfUAdcHmL1rpVE,2274
307
+ atomicshop/wrappers/socketw/socket_wrapper.py,sha256=DiDzg9OlgahxpqAsnOkCKHNcE-H-YAY3ndVMeU-oCjw,33363
308
+ atomicshop/wrappers/socketw/ssl_base.py,sha256=kmiif84kMhBr5yjQW17p935sfjR5JKG0LxIwBA4iVvU,2275
308
309
  atomicshop/wrappers/socketw/statistics_csv.py,sha256=V_m1D0KpizQox3IEWp2AUcncwWy5kG25hbFrc-mBSJE,3029
309
310
  atomicshop/wrappers/winregw/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
310
311
  atomicshop/wrappers/winregw/winreg_network.py,sha256=bQ8Jql8bVGBJ0dt3VQ56lga_1LBOMLI3Km_otvvbU6c,7138
311
- atomicshop-2.16.14.dist-info/LICENSE.txt,sha256=lLU7EYycfYcK2NR_1gfnhnRC8b8ccOTElACYplgZN88,1094
312
- atomicshop-2.16.14.dist-info/METADATA,sha256=V_qBUztY_EbQm-h-yHG_P1-KbkF1PpntRW34Q1zW07U,10503
313
- atomicshop-2.16.14.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
314
- atomicshop-2.16.14.dist-info/top_level.txt,sha256=EgKJB-7xcrAPeqTRF2laD_Np2gNGYkJkd4OyXqpJphA,11
315
- atomicshop-2.16.14.dist-info/RECORD,,
312
+ atomicshop-2.16.15.dist-info/LICENSE.txt,sha256=lLU7EYycfYcK2NR_1gfnhnRC8b8ccOTElACYplgZN88,1094
313
+ atomicshop-2.16.15.dist-info/METADATA,sha256=i5Xgtqpn2TfPbeSQ_L3nAryipoFyy2Z6whmJsDFQyD4,10503
314
+ atomicshop-2.16.15.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
315
+ atomicshop-2.16.15.dist-info/top_level.txt,sha256=EgKJB-7xcrAPeqTRF2laD_Np2gNGYkJkd4OyXqpJphA,11
316
+ atomicshop-2.16.15.dist-info/RECORD,,