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.
- atomicshop/__init__.py +1 -1
- atomicshop/certificates.py +146 -52
- atomicshop/mitm/config_static.py +12 -3
- atomicshop/mitm/import_config.py +8 -0
- atomicshop/mitm/mitm_main.py +7 -4
- atomicshop/mitm/recs_files.py +0 -1
- atomicshop/process_poller/process_pool.py +0 -1
- atomicshop/process_poller/simple_process_pool.py +0 -1
- atomicshop/wrappers/cryptographyw.py +3 -1
- atomicshop/wrappers/ctyping/msi_windows_installer/extract_msi_main.py +0 -1
- atomicshop/wrappers/elasticsearchw/elasticsearchw.py +2 -20
- atomicshop/wrappers/elasticsearchw/install_elastic.py +7 -7
- atomicshop/wrappers/factw/get_file_data.py +12 -5
- atomicshop/wrappers/githubw.py +0 -1
- atomicshop/wrappers/loggingw/handlers.py +31 -16
- atomicshop/wrappers/loggingw/loggingw.py +3 -0
- atomicshop/wrappers/mongodbw/install_mongodb.py +6 -6
- atomicshop/wrappers/mongodbw/{infrastructure.py → mongo_infra.py} +14 -6
- atomicshop/wrappers/mongodbw/mongodbw.py +174 -24
- atomicshop/wrappers/pywin32w/cert_store.py +89 -0
- atomicshop/wrappers/socketw/socket_server_tester.py +5 -1
- atomicshop/wrappers/socketw/socket_wrapper.py +71 -2
- atomicshop/wrappers/socketw/ssl_base.py +1 -1
- {atomicshop-2.16.14.dist-info → atomicshop-2.16.16.dist-info}/METADATA +1 -2
- {atomicshop-2.16.14.dist-info → atomicshop-2.16.16.dist-info}/RECORD +29 -28
- /atomicshop/wrappers/elasticsearchw/{infrastructure.py → elastic_infra.py} +0 -0
- {atomicshop-2.16.14.dist-info → atomicshop-2.16.16.dist-info}/LICENSE.txt +0 -0
- {atomicshop-2.16.14.dist-info → atomicshop-2.16.16.dist-info}/WHEEL +0 -0
- {atomicshop-2.16.14.dist-info → atomicshop-2.16.16.dist-info}/top_level.txt +0 -0
|
@@ -1,6 +1,11 @@
|
|
|
1
|
+
from typing import Union
|
|
2
|
+
import datetime
|
|
3
|
+
|
|
1
4
|
import pymongo
|
|
2
5
|
|
|
3
|
-
from
|
|
6
|
+
from ...basics import dicts
|
|
7
|
+
|
|
8
|
+
from . import mongo_infra
|
|
4
9
|
|
|
5
10
|
|
|
6
11
|
"""
|
|
@@ -9,7 +14,7 @@ These are good examples to get you started, but can't really cover all the use c
|
|
|
9
14
|
"""
|
|
10
15
|
|
|
11
16
|
|
|
12
|
-
def connect(uri: str =
|
|
17
|
+
def connect(uri: str = mongo_infra.MONGODB_DEFAULT_URI):
|
|
13
18
|
"""
|
|
14
19
|
Connect to a MongoDB database.
|
|
15
20
|
:param uri: str, the URI of the MongoDB database.
|
|
@@ -18,18 +23,23 @@ def connect(uri: str = infrastructure.MONGODB_DEFAULT_URI):
|
|
|
18
23
|
return pymongo.MongoClient(uri)
|
|
19
24
|
|
|
20
25
|
|
|
21
|
-
def
|
|
22
|
-
|
|
26
|
+
def index(
|
|
27
|
+
object_instance: Union[list[dict], dict],
|
|
23
28
|
database_name: str,
|
|
24
29
|
collection_name: str,
|
|
30
|
+
add_timestamp: bool = False,
|
|
31
|
+
convert_mixed_lists_to_strings: bool = False,
|
|
25
32
|
mongo_client: pymongo.MongoClient = None,
|
|
26
33
|
close_client: bool = False
|
|
27
34
|
):
|
|
28
35
|
"""
|
|
29
|
-
Add a list
|
|
30
|
-
:param
|
|
36
|
+
Add a dictionary or list dictionaries to a MongoDB collection.
|
|
37
|
+
:param object_instance: list of dictionaries or dictionary to add to the collection.
|
|
31
38
|
:param database_name: str, the name of the database.
|
|
32
39
|
:param collection_name: str, the name of the collection.
|
|
40
|
+
:param add_timestamp: bool, if True, a current time timestamp will be added to the object.
|
|
41
|
+
:param convert_mixed_lists_to_strings: bool, if True, mixed lists or tuples when entries are strings and integers,
|
|
42
|
+
the integers will be converted to strings.
|
|
33
43
|
:param mongo_client: pymongo.MongoClient, the connection object.
|
|
34
44
|
If None, a new connection will be created to default URI.
|
|
35
45
|
:param close_client: bool, if True, the connection will be closed after the operation.
|
|
@@ -37,28 +47,46 @@ def add_list_of_dicts_to_mongo(
|
|
|
37
47
|
:return: None
|
|
38
48
|
"""
|
|
39
49
|
|
|
50
|
+
_is_object_list_of_dicts_or_dict(object_instance)
|
|
51
|
+
|
|
40
52
|
if not mongo_client:
|
|
41
53
|
mongo_client = connect()
|
|
54
|
+
close_client = True
|
|
42
55
|
|
|
43
56
|
db = mongo_client[database_name]
|
|
44
57
|
collection = db[collection_name]
|
|
45
58
|
|
|
46
|
-
|
|
59
|
+
if convert_mixed_lists_to_strings:
|
|
60
|
+
object_instance = dicts.convert_int_to_str_in_mixed_lists(object_instance)
|
|
61
|
+
|
|
62
|
+
if add_timestamp:
|
|
63
|
+
timestamp = datetime.datetime.now()
|
|
64
|
+
if isinstance(object_instance, dict):
|
|
65
|
+
object_instance['timestamp'] = timestamp
|
|
66
|
+
elif isinstance(object_instance, list):
|
|
67
|
+
for doc in object_instance:
|
|
68
|
+
doc['timestamp'] = timestamp
|
|
69
|
+
|
|
70
|
+
if isinstance(object_instance, dict):
|
|
71
|
+
collection.insert_one(object_instance)
|
|
72
|
+
elif isinstance(object_instance, list):
|
|
73
|
+
collection.insert_many(object_instance)
|
|
47
74
|
|
|
48
75
|
if close_client:
|
|
49
76
|
mongo_client.close()
|
|
50
77
|
|
|
51
78
|
|
|
52
|
-
def
|
|
53
|
-
|
|
79
|
+
def delete(
|
|
80
|
+
object_instance: Union[list[dict], dict],
|
|
54
81
|
database_name: str,
|
|
55
82
|
collection_name: str,
|
|
56
83
|
mongo_client: pymongo.MongoClient = None,
|
|
57
84
|
close_client: bool = False
|
|
58
85
|
):
|
|
59
86
|
"""
|
|
60
|
-
Remove a list of dictionaries from a MongoDB collection.
|
|
61
|
-
|
|
87
|
+
Remove a list of dictionaries or a dictionary from a MongoDB collection.
|
|
88
|
+
|
|
89
|
+
:param object_instance: list of dictionaries, the list of dictionaries to remove from the collection.
|
|
62
90
|
:param database_name: str, the name of the database.
|
|
63
91
|
:param collection_name: str, the name of the collection.
|
|
64
92
|
:param mongo_client: pymongo.MongoClient, the connection object.
|
|
@@ -68,29 +96,74 @@ def remove_list_of_dicts(
|
|
|
68
96
|
:return: None
|
|
69
97
|
"""
|
|
70
98
|
|
|
99
|
+
_is_object_list_of_dicts_or_dict(object_instance)
|
|
100
|
+
|
|
71
101
|
if not mongo_client:
|
|
72
102
|
mongo_client = connect()
|
|
103
|
+
close_client = True
|
|
73
104
|
|
|
74
105
|
db = mongo_client[database_name]
|
|
75
106
|
collection = db[collection_name]
|
|
76
107
|
|
|
77
|
-
|
|
78
|
-
collection.delete_one(
|
|
108
|
+
if isinstance(object_instance, dict):
|
|
109
|
+
collection.delete_one(object_instance)
|
|
110
|
+
elif isinstance(object_instance, list):
|
|
111
|
+
for doc in object_instance:
|
|
112
|
+
collection.delete_one(doc)
|
|
79
113
|
|
|
80
114
|
if close_client:
|
|
81
115
|
mongo_client.close()
|
|
82
116
|
|
|
83
117
|
|
|
84
|
-
def
|
|
85
|
-
list_of_dicts: list,
|
|
118
|
+
def find(
|
|
86
119
|
database_name: str,
|
|
87
120
|
collection_name: str,
|
|
121
|
+
query: dict = None,
|
|
88
122
|
mongo_client: pymongo.MongoClient = None,
|
|
89
123
|
close_client: bool = False
|
|
90
124
|
):
|
|
91
125
|
"""
|
|
92
|
-
|
|
93
|
-
:param
|
|
126
|
+
Find entries in a MongoDB collection by query.
|
|
127
|
+
:param database_name: str, the name of the database.
|
|
128
|
+
:param collection_name: str, the name of the collection.
|
|
129
|
+
:param query: dict, the query to search for.
|
|
130
|
+
Example, search for all entries with column name 'name' equal to 'John':
|
|
131
|
+
query = {'name': 'John'}
|
|
132
|
+
Example, return all entries from collection:
|
|
133
|
+
query = None
|
|
134
|
+
:param mongo_client: pymongo.MongoClient, the connection object.
|
|
135
|
+
If None, a new connection will be created to default URI.
|
|
136
|
+
:param close_client: bool, if True, the connection will be closed after the operation.
|
|
137
|
+
|
|
138
|
+
:return: list of dictionaries, the list of entries that match the query.
|
|
139
|
+
"""
|
|
140
|
+
|
|
141
|
+
if not mongo_client:
|
|
142
|
+
mongo_client = connect()
|
|
143
|
+
close_client = True
|
|
144
|
+
|
|
145
|
+
db = mongo_client[database_name]
|
|
146
|
+
collection = db[collection_name]
|
|
147
|
+
|
|
148
|
+
if query is None:
|
|
149
|
+
entries: list = list(collection.find())
|
|
150
|
+
else:
|
|
151
|
+
entries: list = list(collection.find(query))
|
|
152
|
+
|
|
153
|
+
if close_client:
|
|
154
|
+
mongo_client.close()
|
|
155
|
+
|
|
156
|
+
return entries
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def delete_all_entries_from_collection(
|
|
160
|
+
database_name: str,
|
|
161
|
+
collection_name: str,
|
|
162
|
+
mongo_client: pymongo.MongoClient = None,
|
|
163
|
+
close_client: bool = False
|
|
164
|
+
):
|
|
165
|
+
"""
|
|
166
|
+
Remove all entries from a MongoDB collection.
|
|
94
167
|
:param database_name: str, the name of the database.
|
|
95
168
|
:param collection_name: str, the name of the collection.
|
|
96
169
|
:param mongo_client: pymongo.MongoClient, the connection object.
|
|
@@ -102,43 +175,120 @@ def overwrite_list_of_dicts(
|
|
|
102
175
|
|
|
103
176
|
if not mongo_client:
|
|
104
177
|
mongo_client = connect()
|
|
178
|
+
close_client = True
|
|
105
179
|
|
|
106
180
|
db = mongo_client[database_name]
|
|
107
181
|
collection = db[collection_name]
|
|
108
182
|
|
|
109
183
|
collection.delete_many({})
|
|
110
|
-
collection.insert_many(list_of_dicts)
|
|
111
184
|
|
|
112
185
|
if close_client:
|
|
113
186
|
mongo_client.close()
|
|
114
187
|
|
|
115
188
|
|
|
116
|
-
def
|
|
189
|
+
def overwrite_collection(
|
|
190
|
+
object_instance: list,
|
|
117
191
|
database_name: str,
|
|
118
192
|
collection_name: str,
|
|
193
|
+
add_timestamp: bool = False,
|
|
194
|
+
convert_mixed_lists_to_strings: bool = False,
|
|
119
195
|
mongo_client: pymongo.MongoClient = None,
|
|
120
196
|
close_client: bool = False
|
|
121
197
|
):
|
|
122
198
|
"""
|
|
123
|
-
|
|
199
|
+
Overwrite a MongoDB collection with list of dicts or a dict.
|
|
200
|
+
:param object_instance: list of dictionaries, the list of dictionaries to overwrite in the collection.
|
|
124
201
|
:param database_name: str, the name of the database.
|
|
125
202
|
:param collection_name: str, the name of the collection.
|
|
203
|
+
:param add_timestamp: bool, if True, a current time timestamp will be added to the object.
|
|
204
|
+
:param convert_mixed_lists_to_strings: bool, if True, mixed lists or tuples when entries are strings and integers,
|
|
205
|
+
the integers will be converted to strings.
|
|
206
|
+
:param mongo_client: pymongo.MongoClient, the connection object.
|
|
207
|
+
If None, a new connection will be created to default URI.
|
|
208
|
+
:param close_client: bool, if True, the connection will be closed after the operation.
|
|
209
|
+
|
|
210
|
+
:return: None
|
|
211
|
+
"""
|
|
212
|
+
|
|
213
|
+
_is_object_list_of_dicts_or_dict(object_instance)
|
|
214
|
+
|
|
215
|
+
if not mongo_client:
|
|
216
|
+
mongo_client = connect()
|
|
217
|
+
close_client = True
|
|
218
|
+
|
|
219
|
+
delete_all_entries_from_collection(
|
|
220
|
+
database_name=database_name, collection_name=collection_name,
|
|
221
|
+
mongo_client=mongo_client
|
|
222
|
+
)
|
|
223
|
+
|
|
224
|
+
index(
|
|
225
|
+
object_instance=object_instance,
|
|
226
|
+
database_name=database_name, collection_name=collection_name,
|
|
227
|
+
add_timestamp=add_timestamp, convert_mixed_lists_to_strings=convert_mixed_lists_to_strings,
|
|
228
|
+
mongo_client=mongo_client, close_client=close_client)
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
def _is_object_list_of_dicts_or_dict(
|
|
232
|
+
object_instance: Union[list[dict], dict]
|
|
233
|
+
):
|
|
234
|
+
if isinstance(object_instance, dict):
|
|
235
|
+
return True
|
|
236
|
+
elif isinstance(object_instance, list):
|
|
237
|
+
if object_instance and isinstance(object_instance[0], dict):
|
|
238
|
+
return True
|
|
239
|
+
else:
|
|
240
|
+
raise ValueError("List must contain dictionaries.")
|
|
241
|
+
else:
|
|
242
|
+
raise ValueError("Object must be a dictionary or a list of dictionaries.")
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
def get_stats_db(
|
|
246
|
+
database_name: str,
|
|
247
|
+
mongo_client: pymongo.MongoClient = None,
|
|
248
|
+
close_client: bool = False
|
|
249
|
+
):
|
|
250
|
+
"""
|
|
251
|
+
Get the stats of a MongoDB database.
|
|
252
|
+
|
|
253
|
+
:param database_name: str, the name of the database.
|
|
126
254
|
:param mongo_client: pymongo.MongoClient, the connection object.
|
|
127
255
|
If None, a new connection will be created to default URI.
|
|
128
256
|
:param close_client: bool, if True, the connection will be closed after the operation.
|
|
129
257
|
|
|
130
|
-
:return:
|
|
258
|
+
:return: dict, the stats of the collection.
|
|
131
259
|
"""
|
|
132
260
|
|
|
133
261
|
if not mongo_client:
|
|
134
262
|
mongo_client = connect()
|
|
263
|
+
close_client = True
|
|
135
264
|
|
|
136
265
|
db = mongo_client[database_name]
|
|
137
|
-
collection = db[collection_name]
|
|
138
266
|
|
|
139
|
-
|
|
267
|
+
stats = db.command("dbStats")
|
|
140
268
|
|
|
141
269
|
if close_client:
|
|
142
270
|
mongo_client.close()
|
|
143
271
|
|
|
144
|
-
return
|
|
272
|
+
return stats
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
def get_stats_db_size(
|
|
276
|
+
database_name: str,
|
|
277
|
+
mongo_client: pymongo.MongoClient = None,
|
|
278
|
+
close_client: bool = False
|
|
279
|
+
):
|
|
280
|
+
"""
|
|
281
|
+
Get the size of a MongoDB database in bytes.
|
|
282
|
+
|
|
283
|
+
:param database_name: str, the name of the database.
|
|
284
|
+
:param mongo_client: pymongo.MongoClient, the connection object.
|
|
285
|
+
If None, a new connection will be created to default URI.
|
|
286
|
+
:param close_client: bool, if True, the connection will be closed after the operation.
|
|
287
|
+
|
|
288
|
+
:return: int, the size of the database in bytes.
|
|
289
|
+
"""
|
|
290
|
+
|
|
291
|
+
stats = get_stats_db(
|
|
292
|
+
database_name=database_name, mongo_client=mongo_client, close_client=close_client)
|
|
293
|
+
|
|
294
|
+
return stats['dataSize']
|
|
@@ -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 {}))
|
|
@@ -54,7 +54,11 @@ def execute_test(config_static):
|
|
|
54
54
|
config = config_importer.config['config']
|
|
55
55
|
|
|
56
56
|
# SocketClient is working with 'network' logger by default, so we will initialize it.
|
|
57
|
-
loggingw.
|
|
57
|
+
loggingw.create_logger(
|
|
58
|
+
logger_name="network",
|
|
59
|
+
add_stream=True,
|
|
60
|
+
formatter_streamhandler='DEFAULT'
|
|
61
|
+
)
|
|
58
62
|
|
|
59
63
|
# Get all the files in requests folder recursively.
|
|
60
64
|
request_file_list = filesystem.get_paths_from_directory(config['requests_directory'], get_file=True)
|
|
@@ -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
|
|
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.
|
|
3
|
+
Version: 2.16.16
|
|
4
4
|
Summary: Atomic functions and classes to make developer life easier
|
|
5
5
|
Author: Denis Kras
|
|
6
6
|
License: MIT License
|
|
@@ -38,7 +38,6 @@ Requires-Dist: cryptography
|
|
|
38
38
|
Requires-Dist: dnslib
|
|
39
39
|
Requires-Dist: dnspython
|
|
40
40
|
Requires-Dist: docker
|
|
41
|
-
Requires-Dist: elasticsearch
|
|
42
41
|
Requires-Dist: numpy
|
|
43
42
|
Requires-Dist: olefile
|
|
44
43
|
Requires-Dist: openpyxl
|