atomicshop 2.18.6__py3-none-any.whl → 2.18.8__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/archiver/search_in_archive.py +14 -5
- atomicshop/archiver/sevenzs.py +43 -14
- atomicshop/filesystem.py +18 -61
- atomicshop/ip_addresses.py +6 -1
- atomicshop/mitm/connection_thread_worker.py +23 -17
- atomicshop/mitm/engines/__parent/responder___parent.py +14 -69
- atomicshop/mitm/engines/__reference_general/responder___reference_general.py +70 -10
- atomicshop/process.py +13 -2
- atomicshop/wrappers/mongodbw/mongodbw.py +4 -0
- atomicshop/wrappers/playwrightw/scenarios.py +16 -2
- atomicshop/wrappers/pywin32w/wmis/win32networkadapter.py +2 -0
- atomicshop/wrappers/winregw/winreg_network.py +4 -0
- {atomicshop-2.18.6.dist-info → atomicshop-2.18.8.dist-info}/METADATA +1 -1
- {atomicshop-2.18.6.dist-info → atomicshop-2.18.8.dist-info}/RECORD +18 -18
- {atomicshop-2.18.6.dist-info → atomicshop-2.18.8.dist-info}/LICENSE.txt +0 -0
- {atomicshop-2.18.6.dist-info → atomicshop-2.18.8.dist-info}/WHEEL +0 -0
- {atomicshop-2.18.6.dist-info → atomicshop-2.18.8.dist-info}/top_level.txt +0 -0
atomicshop/__init__.py
CHANGED
|
@@ -107,18 +107,27 @@ def _search_in_archive(
|
|
|
107
107
|
|
|
108
108
|
# Iterate over each file in the archive.
|
|
109
109
|
for item_index, item in enumerate(file_info_list):
|
|
110
|
-
if item.filename.endswith('/'): # Skip directories
|
|
111
|
-
continue
|
|
112
|
-
|
|
113
110
|
# At this stage we will get the bytes of the archived file, which is an 'item' in the archive.
|
|
114
111
|
archived_file_bytes = None
|
|
115
112
|
# If the main archive is zip we will use the 'open' method, if it's 7z we will use the 'read' method.
|
|
116
113
|
if archive_type == 'zip':
|
|
114
|
+
# Skip directories.
|
|
115
|
+
if item.filename.endswith('/'):
|
|
116
|
+
continue
|
|
117
|
+
|
|
117
118
|
with arch_obj.open(item) as file_data:
|
|
118
119
|
archived_file_bytes = file_data.read()
|
|
119
120
|
elif archive_type == '7z':
|
|
121
|
+
# Skip directories.
|
|
122
|
+
if item.is_directory:
|
|
123
|
+
continue
|
|
124
|
+
|
|
125
|
+
# If 'SevenZipFile.red()' is used once, the second time you need to read it you will need to reset the
|
|
126
|
+
# SevenZipFile object in order to read again:
|
|
127
|
+
# https://py7zr.readthedocs.io/en/latest/api.html#py7zr.SevenZipFile.read
|
|
120
128
|
file_dict = arch_obj.read([item.filename])
|
|
121
129
|
archived_file_bytes = file_dict[item.filename].read()
|
|
130
|
+
arch_obj.reset()
|
|
122
131
|
|
|
123
132
|
# After we get the file bytes we will check if the file matches the callback functions.
|
|
124
133
|
callback_matched = False
|
|
@@ -129,7 +138,7 @@ def _search_in_archive(
|
|
|
129
138
|
if callback_matched:
|
|
130
139
|
_handle_file_extraction(item, extract_file_to_path, archived_file_bytes)
|
|
131
140
|
else:
|
|
132
|
-
if recursive and (zips.is_zip_zipfile(archived_file_bytes) or sevenzs.
|
|
141
|
+
if recursive and (zips.is_zip_zipfile(archived_file_bytes) or sevenzs.is_7z_magic_number(archived_file_bytes)):
|
|
133
142
|
_search_archive_content(
|
|
134
143
|
archived_file_bytes, file_names, results, found_set, case_sensitive, return_first_only,
|
|
135
144
|
recursive, callback_functions, extract_file_to_path)
|
|
@@ -187,7 +196,7 @@ def _get_archive_type(file_object) -> Union[str, None]:
|
|
|
187
196
|
|
|
188
197
|
if zips.is_zip_zipfile(file_object):
|
|
189
198
|
return 'zip'
|
|
190
|
-
elif sevenzs.
|
|
199
|
+
elif sevenzs.is_7z_magic_number(file_object):
|
|
191
200
|
return '7z'
|
|
192
201
|
else:
|
|
193
202
|
raise UnknownArchiveType(f"{file_object[:10]} is not a known archive type.")
|
atomicshop/archiver/sevenzs.py
CHANGED
|
@@ -4,8 +4,50 @@ from typing import Union
|
|
|
4
4
|
import py7zr
|
|
5
5
|
|
|
6
6
|
|
|
7
|
-
def
|
|
7
|
+
def is_7z_magic_number(
|
|
8
|
+
file_object: Union[str, bytes]
|
|
9
|
+
) -> bool:
|
|
8
10
|
"""
|
|
11
|
+
Function checks if the file is a 7z file, by checking the magic number.
|
|
12
|
+
|
|
13
|
+
:param file_object: can be two types:
|
|
14
|
+
string, full path to the file.
|
|
15
|
+
bytes or BytesIO, the bytes of the file.
|
|
16
|
+
:return: boolean.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
if isinstance(file_object, str):
|
|
20
|
+
with open(file_object, 'rb') as file:
|
|
21
|
+
data = file.read(6)
|
|
22
|
+
elif isinstance(file_object, bytes):
|
|
23
|
+
data = file_object
|
|
24
|
+
else:
|
|
25
|
+
raise TypeError(f'The file_object must be a string or bytes, not {type(file_object)}')
|
|
26
|
+
|
|
27
|
+
# Check if the data is at least 6 bytes long
|
|
28
|
+
if len(data) < 6:
|
|
29
|
+
return False
|
|
30
|
+
|
|
31
|
+
# 7z file signature (magic number)
|
|
32
|
+
# The signature is '7z' followed by 'BCAF271C'
|
|
33
|
+
seven_z_signature = b'7z\xBC\xAF\x27\x1C'
|
|
34
|
+
|
|
35
|
+
# Compare the first 6 bytes of the data with the 7z signature
|
|
36
|
+
result = data.startswith(seven_z_signature)
|
|
37
|
+
|
|
38
|
+
return result
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _is_7z(file_object: Union[str, bytes]) -> bool:
|
|
42
|
+
"""
|
|
43
|
+
THIS IS ONLY FOR THE REFERENCE.
|
|
44
|
+
|
|
45
|
+
Used to use this function since it raised 'py7zr.Bad7zFile' if the file was not a 7z file.
|
|
46
|
+
The problem that 'SevenZipFile.testzip()' checks archived files CRCs and returns the first bad file:
|
|
47
|
+
https://py7zr.readthedocs.io/en/latest/api.html#py7zr.SevenZipFile.testzip
|
|
48
|
+
The problem is when the file IS 7z file, but there can be other problems with the file, it can raise a RuntimeError.
|
|
49
|
+
So, better use the 'is_7z_magic_number' function.
|
|
50
|
+
|
|
9
51
|
Function checks if the file is a 7z file.
|
|
10
52
|
:param file_object: can be two types:
|
|
11
53
|
string, full path to the file.
|
|
@@ -29,16 +71,3 @@ def is_7z(file_object: Union[str, bytes]) -> bool:
|
|
|
29
71
|
except OSError as e:
|
|
30
72
|
if e.args[0] == 22:
|
|
31
73
|
return False
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
def _is_7z_magic_number(data):
|
|
35
|
-
# Check if the data is at least 6 bytes long
|
|
36
|
-
if len(data) < 6:
|
|
37
|
-
return False
|
|
38
|
-
|
|
39
|
-
# 7z file signature (magic number)
|
|
40
|
-
# The signature is '7z' followed by 'BCAF271C'
|
|
41
|
-
seven_z_signature = b'7z\xBC\xAF\x27\x1C'
|
|
42
|
-
|
|
43
|
-
# Compare the first 6 bytes of the data with the 7z signature
|
|
44
|
-
return data.startswith(seven_z_signature)
|
atomicshop/filesystem.py
CHANGED
|
@@ -1280,70 +1280,20 @@ def create_dict_of_paths_list(list_of_paths: list) -> list:
|
|
|
1280
1280
|
|
|
1281
1281
|
def create_dict_of_path(
|
|
1282
1282
|
path: str,
|
|
1283
|
-
# structure_dict: dict,
|
|
1284
1283
|
structure_list: list,
|
|
1285
|
-
add_data_to_entry: any = None
|
|
1286
|
-
add_data_key: str = 'addon',
|
|
1287
|
-
parent_entry: str = None
|
|
1284
|
+
add_data_to_entry: list[dict[str, any]] = None
|
|
1288
1285
|
):
|
|
1289
1286
|
"""
|
|
1290
1287
|
The function receives a path and a list, and adds the path to the list.
|
|
1291
|
-
|
|
1292
1288
|
Check the working example from 'create_dict_of_paths_list' function.
|
|
1293
1289
|
|
|
1294
1290
|
:param path: string, path.
|
|
1295
1291
|
:param structure_list: list to add the path to.
|
|
1296
|
-
:param add_data_to_entry:
|
|
1297
|
-
|
|
1298
|
-
:param parent_entry: string, for internal use to pass the current parent entry.
|
|
1292
|
+
:param add_data_to_entry: a list of dicts with data to add to the entry.
|
|
1293
|
+
dict format: {key: data}
|
|
1299
1294
|
:return:
|
|
1300
1295
|
"""
|
|
1301
1296
|
|
|
1302
|
-
# # Normalize path for cross-platform compatibility
|
|
1303
|
-
# normalized_path = path.replace("\\", "/")
|
|
1304
|
-
# parts = normalized_path.strip("/").split("/")
|
|
1305
|
-
# current_level = structure_dict
|
|
1306
|
-
#
|
|
1307
|
-
# for part in parts[:-1]: # Iterate through the directories
|
|
1308
|
-
# # If the part is not already a key in the current level of the structure, add it
|
|
1309
|
-
# if part not in current_level:
|
|
1310
|
-
# current_level[part] = {}
|
|
1311
|
-
# current_level = current_level[part]
|
|
1312
|
-
#
|
|
1313
|
-
# # Create the entry for the file with additional data
|
|
1314
|
-
# file_entry = {"entry": parts[-1], add_data_key: add_data_to_entry}
|
|
1315
|
-
#
|
|
1316
|
-
# # We're adding file entries under numeric keys.
|
|
1317
|
-
# if isinstance(current_level, dict) and all(isinstance(key, int) for key in current_level.keys()):
|
|
1318
|
-
# current_level[len(current_level)] = file_entry
|
|
1319
|
-
# else:
|
|
1320
|
-
# # Handle cases where there's a mix of numeric keys and directory names
|
|
1321
|
-
# # Find the next available numeric key
|
|
1322
|
-
# next_key = max([key if isinstance(key, int) else -1 for key in current_level.keys()], default=-1) + 1
|
|
1323
|
-
# current_level[next_key] = file_entry
|
|
1324
|
-
|
|
1325
|
-
# entries_key_name = "__entries__"
|
|
1326
|
-
#
|
|
1327
|
-
# # Normalize path for cross-platform compatibility
|
|
1328
|
-
# normalized_path = path.replace("\\", "/")
|
|
1329
|
-
# parts = normalized_path.strip("/").split("/")
|
|
1330
|
-
# current_level = structure_dict
|
|
1331
|
-
#
|
|
1332
|
-
# for part in parts[:-1]: # Navigate through or create directory structure
|
|
1333
|
-
# if part not in current_level:
|
|
1334
|
-
# current_level[part] = {}
|
|
1335
|
-
# current_level = current_level[part]
|
|
1336
|
-
#
|
|
1337
|
-
# # Create the entry for the file with additional data
|
|
1338
|
-
# file_entry = {"entry": parts[-1], add_data_key: add_data_to_entry}
|
|
1339
|
-
#
|
|
1340
|
-
# # If the current level (final directory) does not have an "entries" key for files, create it
|
|
1341
|
-
# if entries_key_name not in current_level:
|
|
1342
|
-
# current_level[entries_key_name] = []
|
|
1343
|
-
#
|
|
1344
|
-
# # Append the file entry to the list associated with the "entries" key
|
|
1345
|
-
# current_level[entries_key_name].append(file_entry)
|
|
1346
|
-
|
|
1347
1297
|
# Normalize path for cross-platform compatibility
|
|
1348
1298
|
normalized_path = path.replace("\\", "/")
|
|
1349
1299
|
parts = normalized_path.strip("/").split("/")
|
|
@@ -1351,29 +1301,36 @@ def create_dict_of_path(
|
|
|
1351
1301
|
current_level = structure_list
|
|
1352
1302
|
|
|
1353
1303
|
for i, part in enumerate(parts):
|
|
1354
|
-
# Determine if this is the last part (a file)
|
|
1304
|
+
# Determine if this is the last part (a file or final component of the path)
|
|
1355
1305
|
is_last_part = (i == len(parts) - 1)
|
|
1356
1306
|
|
|
1357
1307
|
# Try to find an existing entry for this part
|
|
1358
|
-
# noinspection PyTypeChecker
|
|
1359
1308
|
existing_entry = next((item for item in current_level if item["entry"] == part), None)
|
|
1360
1309
|
|
|
1361
1310
|
if existing_entry is None:
|
|
1362
|
-
#
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1311
|
+
# Create a new entry
|
|
1312
|
+
new_entry = {"entry": part, "included": []}
|
|
1313
|
+
|
|
1314
|
+
# Add additional data if it's the last part
|
|
1315
|
+
if is_last_part and add_data_to_entry:
|
|
1316
|
+
for data_dict in add_data_to_entry:
|
|
1317
|
+
new_entry.update(data_dict)
|
|
1367
1318
|
|
|
1368
1319
|
current_level.append(new_entry)
|
|
1320
|
+
|
|
1369
1321
|
# Only update current_level if it's not the last part
|
|
1370
1322
|
if not is_last_part:
|
|
1371
1323
|
current_level = new_entry["included"]
|
|
1372
1324
|
else:
|
|
1373
|
-
# If it's not the last part
|
|
1325
|
+
# If the entry exists and it's not the last part, navigate deeper
|
|
1374
1326
|
if not is_last_part:
|
|
1375
1327
|
current_level = existing_entry["included"]
|
|
1376
1328
|
|
|
1329
|
+
# If the entry exists and it's the last part, update with additional data
|
|
1330
|
+
if is_last_part and add_data_to_entry:
|
|
1331
|
+
for data_dict in add_data_to_entry:
|
|
1332
|
+
existing_entry.update(data_dict)
|
|
1333
|
+
|
|
1377
1334
|
|
|
1378
1335
|
def list_open_files_in_directory(directory):
|
|
1379
1336
|
"""
|
atomicshop/ip_addresses.py
CHANGED
|
@@ -2,7 +2,12 @@ import ipaddress
|
|
|
2
2
|
from typing import Union, Literal
|
|
3
3
|
|
|
4
4
|
|
|
5
|
-
def is_ip_address(
|
|
5
|
+
def is_ip_address(
|
|
6
|
+
string_value: str,
|
|
7
|
+
ip_type: Union[
|
|
8
|
+
Literal['ipv4', 'ipv6'],
|
|
9
|
+
None] = None
|
|
10
|
+
) -> bool:
|
|
6
11
|
"""
|
|
7
12
|
The function checks if the string is an IPv4 or IPv6 address.
|
|
8
13
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from datetime import datetime
|
|
2
2
|
import threading
|
|
3
3
|
import queue
|
|
4
|
+
import copy
|
|
4
5
|
|
|
5
6
|
from ..wrappers.socketw import receiver, sender, socket_client, base
|
|
6
7
|
from .. import websocket_parse
|
|
@@ -297,7 +298,10 @@ def thread_worker_main(
|
|
|
297
298
|
if not isinstance(client_message, ClientMessage):
|
|
298
299
|
return
|
|
299
300
|
|
|
300
|
-
|
|
301
|
+
if client_message.action == 'service_connect':
|
|
302
|
+
raw_responses: list[bytes] = responder.create_connect_response(client_message)
|
|
303
|
+
else:
|
|
304
|
+
raw_responses: list[bytes] = create_responder_response(client_message)
|
|
301
305
|
|
|
302
306
|
is_socket_closed: bool = False
|
|
303
307
|
for response_raw_bytes in raw_responses:
|
|
@@ -383,14 +387,14 @@ def thread_worker_main(
|
|
|
383
387
|
# the close on the opposite socket.
|
|
384
388
|
record_and_statistics_write(client_message)
|
|
385
389
|
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
+
if is_socket_closed:
|
|
391
|
+
exception_or_close_in_receiving_thread = True
|
|
392
|
+
finish_thread()
|
|
393
|
+
return
|
|
390
394
|
|
|
391
395
|
# If we're in response mode, execute responder.
|
|
392
396
|
if config_static.TCPServer.server_response_mode:
|
|
393
|
-
responder_queue.put(client_message)
|
|
397
|
+
responder_queue.put(copy.deepcopy(client_message))
|
|
394
398
|
else:
|
|
395
399
|
# if side == 'Client':
|
|
396
400
|
# raise NotImplementedError
|
|
@@ -543,7 +547,7 @@ def thread_worker_main(
|
|
|
543
547
|
client_message_connection.timestamp = datetime.now()
|
|
544
548
|
client_message_connection.action = 'service_connect'
|
|
545
549
|
client_message_connection.info = 'Server Response Mode'
|
|
546
|
-
responder_queue.put(client_message_connection)
|
|
550
|
+
responder_queue.put(copy.deepcopy(client_message_connection))
|
|
547
551
|
|
|
548
552
|
if connection_error:
|
|
549
553
|
client_message_connection.timestamp = datetime.now()
|
|
@@ -552,30 +556,32 @@ def thread_worker_main(
|
|
|
552
556
|
record_and_statistics_write(client_message_connection)
|
|
553
557
|
else:
|
|
554
558
|
client_exception_queue: queue.Queue = queue.Queue()
|
|
555
|
-
service_exception_queue: queue.Queue = queue.Queue()
|
|
556
|
-
|
|
557
559
|
client_thread = threading.Thread(
|
|
558
560
|
target=receive_send_start, args=(client_socket, service_socket_instance, client_exception_queue),
|
|
559
561
|
name=f"Thread-{thread_id}-Client")
|
|
560
562
|
client_thread.daemon = True
|
|
561
563
|
client_thread.start()
|
|
562
564
|
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
565
|
+
if not config_static.TCPServer.server_response_mode:
|
|
566
|
+
service_exception_queue: queue.Queue = queue.Queue()
|
|
567
|
+
service_thread = threading.Thread(
|
|
568
|
+
target=receive_send_start, args=(service_socket_instance, client_socket, service_exception_queue),
|
|
569
|
+
name=f"Thread-{thread_id}-Service")
|
|
570
|
+
service_thread.daemon = True
|
|
571
|
+
service_thread.start()
|
|
568
572
|
|
|
569
573
|
client_thread.join()
|
|
570
|
-
service_thread.join()
|
|
571
574
|
if config_static.TCPServer.server_response_mode:
|
|
572
575
|
responder_thread.join()
|
|
576
|
+
else:
|
|
577
|
+
service_thread.join()
|
|
573
578
|
|
|
574
579
|
# If there was an exception in any of the threads, then we'll raise it here.
|
|
575
580
|
if not client_exception_queue.empty():
|
|
576
581
|
raise client_exception_queue.get()
|
|
577
|
-
if not
|
|
578
|
-
|
|
582
|
+
if not config_static.TCPServer.server_response_mode:
|
|
583
|
+
if not service_exception_queue.empty():
|
|
584
|
+
raise service_exception_queue.get()
|
|
579
585
|
|
|
580
586
|
finish_thread()
|
|
581
587
|
except Exception as e:
|
|
@@ -103,8 +103,13 @@ class ResponderParent:
|
|
|
103
103
|
|
|
104
104
|
return parameter_value
|
|
105
105
|
|
|
106
|
-
def
|
|
107
|
-
self,
|
|
106
|
+
def build_byte_response(
|
|
107
|
+
self,
|
|
108
|
+
http_version: str,
|
|
109
|
+
status_code: int,
|
|
110
|
+
headers: dict,
|
|
111
|
+
body: bytes
|
|
112
|
+
) -> bytes:
|
|
108
113
|
"""
|
|
109
114
|
Create genuine response from input parameters.
|
|
110
115
|
---------------
|
|
@@ -145,8 +150,7 @@ class ResponderParent:
|
|
|
145
150
|
:param status_code: HTTP Status Code of Response in HTTP Status line.
|
|
146
151
|
:param headers: HTTP Headers of Response.
|
|
147
152
|
:param body: HTTP body data of Response, bytes.
|
|
148
|
-
:
|
|
149
|
-
:return:
|
|
153
|
+
:return: bytes of the response.
|
|
150
154
|
"""
|
|
151
155
|
|
|
152
156
|
try:
|
|
@@ -174,7 +178,6 @@ class ResponderParent:
|
|
|
174
178
|
print_api(message, error_type=True, logger=self.logger, logger_method='error', color='red')
|
|
175
179
|
|
|
176
180
|
response_raw_bytes = b''
|
|
177
|
-
pass
|
|
178
181
|
|
|
179
182
|
# Parsing the response we created.
|
|
180
183
|
response_parse_test = HTTPResponseParse(response_raw_bytes)
|
|
@@ -182,73 +185,15 @@ class ResponderParent:
|
|
|
182
185
|
if response_parse_test.error:
|
|
183
186
|
self.logger.error(response_parse_test.error)
|
|
184
187
|
response_raw_bytes = b''
|
|
185
|
-
response_decoded = None
|
|
186
188
|
else:
|
|
187
189
|
self.logger.info("Created Valid Byte Response.")
|
|
188
|
-
response_decoded = response_parse_test.response_raw_decoded
|
|
189
|
-
|
|
190
|
-
# Add 'response_raw_bytes' and 'response_decoded' to appropriate response lists in 'class_message'.
|
|
191
|
-
self.add_response_elements_to_lists(client_message, response_raw_bytes, response_decoded)
|
|
192
190
|
|
|
193
|
-
|
|
194
|
-
def add_response_elements_to_lists(class_client_message: ClientMessage, byte_response, decoded_response):
|
|
195
|
-
"""
|
|
196
|
-
Function just adds the byte response to the 'response_list_of_raw_bytes'.
|
|
197
|
-
:param class_client_message:
|
|
198
|
-
:param byte_response:
|
|
199
|
-
:param decoded_response:
|
|
200
|
-
:return:
|
|
201
|
-
"""
|
|
191
|
+
return response_raw_bytes
|
|
202
192
|
|
|
203
|
-
|
|
204
|
-
|
|
193
|
+
def create_connect_response(self, class_client_message: ClientMessage):
|
|
194
|
+
""" This function should be overridden in the child class. """
|
|
195
|
+
pass
|
|
205
196
|
|
|
206
197
|
def create_response(self, class_client_message: ClientMessage):
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
Function to create Response based on ClientMessage and its Request.
|
|
210
|
-
|
|
211
|
-
:param class_client_message: contains request and other parameters to help creating response.
|
|
212
|
-
:return: "class_client_message.response_list_of_raw_bytes" is populated with list of responses in bytes.
|
|
213
|
-
-----------------------------------
|
|
214
|
-
# Remember that 'response_list_of_raw_bytes' is a list object that will contain byte response/s.
|
|
215
|
-
|
|
216
|
-
# Example of creating 'response_list_of_raw_bytes' using 'build_byte_response' function:
|
|
217
|
-
class_client_message.response_list_of_raw_bytes.append(
|
|
218
|
-
self.build_byte_response(
|
|
219
|
-
http_version=class_client_message.request_raw_decoded.request_version,
|
|
220
|
-
status_code=200,
|
|
221
|
-
headers=response_headers,
|
|
222
|
-
body=b''
|
|
223
|
-
)
|
|
224
|
-
)
|
|
225
|
-
|
|
226
|
-
# Or you can use the 'add_byte_response_to_response_list' function that will do it for you:
|
|
227
|
-
byte_response = self.build_byte_response(
|
|
228
|
-
http_version=class_client_message.request_raw_decoded.request_version,
|
|
229
|
-
status_code=200,
|
|
230
|
-
headers=response_headers,
|
|
231
|
-
body=b''
|
|
232
|
-
)
|
|
233
|
-
self.add_byte_response_to_response_list(class_client_message, byte_response)
|
|
234
|
-
-----------------------------------
|
|
235
|
-
# Example of extracting variables from URL PATH based on custom PATH TEMPLATE:
|
|
236
|
-
# (more examples in 'self.extract_variables_from_path_template' function description)
|
|
237
|
-
template_path: str = "/hithere/<variable1>/else/<variable2>/tested/"
|
|
238
|
-
path_variables: dict = extract_variables_from_path_template(
|
|
239
|
-
path=class_client_message.request_raw_decoded.path,
|
|
240
|
-
template_path=template_path
|
|
241
|
-
)
|
|
242
|
-
-----------------------------------
|
|
243
|
-
# Example of extracting value from URL PATH parameters after question mark:
|
|
244
|
-
parameter_value = extract_value_from_path_parameter(
|
|
245
|
-
path=class_client_message.request_raw_decoded.path,
|
|
246
|
-
parameter='test_id'
|
|
247
|
-
)
|
|
248
|
-
"""
|
|
249
|
-
|
|
250
|
-
byte_response = None
|
|
251
|
-
decoded_response = None
|
|
252
|
-
# class_client_message.response_list_of_raw_bytes.append(byte_response)
|
|
253
|
-
self.add_response_elements_to_lists(class_client_message, byte_response, decoded_response)
|
|
254
|
-
self.logger.info(f"Response: {class_client_message.response_list_of_raw_bytes}")
|
|
198
|
+
""" This function should be overridden in the child class. """
|
|
199
|
+
pass
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# These are specified with hardcoded paths instead of relative, because 'create_module_template.py' copies the content.
|
|
2
2
|
from atomicshop.mitm.engines.__parent.responder___parent import ResponderParent
|
|
3
3
|
from atomicshop.mitm.shared_functions import create_custom_logger
|
|
4
|
+
from atomicshop.mitm.message import ClientMessage
|
|
4
5
|
|
|
5
6
|
"""
|
|
6
7
|
import time
|
|
@@ -22,6 +23,63 @@ class ResponderGeneral(ResponderParent):
|
|
|
22
23
|
|
|
23
24
|
self.logger = create_custom_logger()
|
|
24
25
|
|
|
26
|
+
def create_response(self, class_client_message: ClientMessage):
|
|
27
|
+
# noinspection GrazieInspection
|
|
28
|
+
"""
|
|
29
|
+
Function to create Response based on ClientMessage and its Request.
|
|
30
|
+
|
|
31
|
+
:param class_client_message: contains request and other parameters to help creating response.
|
|
32
|
+
:return: list of responses in bytes.
|
|
33
|
+
-----------------------------------
|
|
34
|
+
|
|
35
|
+
# Example of creating list of bytes using 'build_byte_response' function:
|
|
36
|
+
result_list: list[bytes] = list()
|
|
37
|
+
result_list.append(
|
|
38
|
+
self.build_byte_response(
|
|
39
|
+
http_version=class_client_message.request_raw_decoded.request_version,
|
|
40
|
+
status_code=200,
|
|
41
|
+
headers=response_headers,
|
|
42
|
+
body=b''
|
|
43
|
+
)
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
return result_list
|
|
47
|
+
-----------------------------------
|
|
48
|
+
# Example of extracting variables from URL PATH based on custom PATH TEMPLATE:
|
|
49
|
+
# (more examples in 'self.extract_variables_from_path_template' function description)
|
|
50
|
+
template_path: str = "/hithere/<variable1>/else/<variable2>/tested/"
|
|
51
|
+
path_variables: dict = extract_variables_from_path_template(
|
|
52
|
+
path=class_client_message.request_raw_decoded.path,
|
|
53
|
+
template_path=template_path
|
|
54
|
+
)
|
|
55
|
+
-----------------------------------
|
|
56
|
+
# Example of extracting value from URL PATH parameters after question mark:
|
|
57
|
+
parameter_value = extract_value_from_path_parameter(
|
|
58
|
+
path=class_client_message.request_raw_decoded.path,
|
|
59
|
+
parameter='test_id'
|
|
60
|
+
)
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
# byte_response: bytes = b''
|
|
64
|
+
# self.logger.info(f"Response: {byte_response}")
|
|
65
|
+
|
|
66
|
+
response_bytes_list: list[bytes] = list()
|
|
67
|
+
# response_bytes_list.append(byte_response)
|
|
68
|
+
return response_bytes_list
|
|
69
|
+
|
|
70
|
+
def create_connect_response(self, class_client_message: ClientMessage):
|
|
71
|
+
"""
|
|
72
|
+
This is almost the same as 'create_response' function, but it's used only when the client connects and before
|
|
73
|
+
sending any data.
|
|
74
|
+
"""
|
|
75
|
+
|
|
76
|
+
# byte_response: bytes = b''
|
|
77
|
+
# self.logger.info(f"Response: {byte_response}")
|
|
78
|
+
|
|
79
|
+
response_bytes_list: list[bytes] = list()
|
|
80
|
+
# response_bytes_list.append(byte_response)
|
|
81
|
+
return response_bytes_list
|
|
82
|
+
|
|
25
83
|
# ==================================================================================================================
|
|
26
84
|
# Uncomment this section in order to begin building custom responder.
|
|
27
85
|
# @staticmethod
|
|
@@ -89,7 +147,7 @@ class ResponderGeneral(ResponderParent):
|
|
|
89
147
|
# # === Building Headers. ===========================
|
|
90
148
|
# # Response Date example: 'Tue, 08 Nov 2022 14:23: 00 GMT'
|
|
91
149
|
# resp_headers = {
|
|
92
|
-
# 'Date': self.
|
|
150
|
+
# 'Date': self.get_current_formatted_time_http(),
|
|
93
151
|
# 'Content-Length': str(len(resp_body)),
|
|
94
152
|
# }
|
|
95
153
|
#
|
|
@@ -109,7 +167,7 @@ class ResponderGeneral(ResponderParent):
|
|
|
109
167
|
# # === Building Headers. ===========================
|
|
110
168
|
# # Response Date example: 'Tue, 08 Nov 2022 14:23: 00 GMT'
|
|
111
169
|
# resp_headers = {
|
|
112
|
-
# 'Date': self.
|
|
170
|
+
# 'Date': self.get_current_formatted_time_http(),
|
|
113
171
|
# 'Content-Length': str(len(resp_body)),
|
|
114
172
|
# 'Connection': 'keep-alive'
|
|
115
173
|
# }
|
|
@@ -118,10 +176,10 @@ class ResponderGeneral(ResponderParent):
|
|
|
118
176
|
#
|
|
119
177
|
# def create_response(self, class_client_message: ClientMessage):
|
|
120
178
|
# # Arranging important request entries to appropriate variables.
|
|
121
|
-
# req_path = class_client_message.
|
|
122
|
-
# req_command = class_client_message.
|
|
123
|
-
# req_headers = class_client_message.
|
|
124
|
-
# req_body = class_client_message.
|
|
179
|
+
# req_path = class_client_message.request_auto_parsed.path
|
|
180
|
+
# req_command = class_client_message.request_auto_parsed.command
|
|
181
|
+
# req_headers = class_client_message.request_auto_parsed.headers
|
|
182
|
+
# req_body = class_client_message.request_auto_parsed.body
|
|
125
183
|
#
|
|
126
184
|
# # ====================================
|
|
127
185
|
# # Case specific.
|
|
@@ -144,10 +202,12 @@ class ResponderGeneral(ResponderParent):
|
|
|
144
202
|
#
|
|
145
203
|
# # ==============================================================================
|
|
146
204
|
# # === Building byte response. ==================================================
|
|
147
|
-
# self.build_byte_response(
|
|
148
|
-
# http_version=class_client_message.
|
|
205
|
+
# byte_response = self.build_byte_response(
|
|
206
|
+
# http_version=class_client_message.request_auto_parsed.request_version,
|
|
149
207
|
# status_code=resp_status_code,
|
|
150
208
|
# headers=resp_headers,
|
|
151
|
-
# body=resp_body_bytes
|
|
152
|
-
# client_message=class_client_message
|
|
209
|
+
# body=resp_body_bytes
|
|
153
210
|
# )
|
|
211
|
+
#
|
|
212
|
+
# result_response_list: list[bytes] = [byte_response]
|
|
213
|
+
# return result_response_list
|
atomicshop/process.py
CHANGED
|
@@ -82,7 +82,18 @@ def execute_with_live_output(
|
|
|
82
82
|
:return: Boolean, If execution was successful, return True, if not - False.
|
|
83
83
|
"""
|
|
84
84
|
|
|
85
|
-
|
|
85
|
+
if isinstance(cmd, str):
|
|
86
|
+
shell = True
|
|
87
|
+
elif isinstance(cmd, list):
|
|
88
|
+
shell = False
|
|
89
|
+
else:
|
|
90
|
+
raise TypeError(f'cmd must be a string or list, not {type(cmd)}')
|
|
91
|
+
|
|
92
|
+
if wsl:
|
|
93
|
+
if isinstance(cmd, str):
|
|
94
|
+
cmd = 'wsl ' + cmd
|
|
95
|
+
elif isinstance(cmd, list):
|
|
96
|
+
cmd = ['wsl'] + cmd
|
|
86
97
|
|
|
87
98
|
# Needed imports:
|
|
88
99
|
# from subprocess import Popen, PIPE, STDOUT
|
|
@@ -103,7 +114,7 @@ def execute_with_live_output(
|
|
|
103
114
|
# The buffer size is system-dependent and usually chosen by the underlying implementation to optimize performance.
|
|
104
115
|
# # bufsize=0: This means no buffering.
|
|
105
116
|
# The I/O is unbuffered, and data is written or read from the stream immediately.
|
|
106
|
-
with subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, bufsize=1, text=True) as process:
|
|
117
|
+
with subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, bufsize=1, text=True, shell=shell) as process:
|
|
107
118
|
# We'll count the number of lines from 'process.stdout'.
|
|
108
119
|
counter: int = 0
|
|
109
120
|
# And also get list of all the lines.
|
|
@@ -698,6 +698,10 @@ def find(
|
|
|
698
698
|
|
|
699
699
|
Example for searching for a value that starts with 'test':
|
|
700
700
|
filter_query = {'field_name': {'$regex': '^test'}}
|
|
701
|
+
|
|
702
|
+
If you need to escape the string for regex special characters you will typically use:
|
|
703
|
+
re.escape(test)
|
|
704
|
+
If you're string contains characters like parentheses "()", you will need to escape them.
|
|
701
705
|
$options: The options for the regex search.
|
|
702
706
|
'i': case-insensitive search.
|
|
703
707
|
Example for case-insensitive search:
|
|
@@ -170,10 +170,24 @@ def fetch_urls_content_in_threads(
|
|
|
170
170
|
return contents
|
|
171
171
|
|
|
172
172
|
|
|
173
|
-
def
|
|
173
|
+
def fetch_urls_content(
|
|
174
|
+
urls: list[str],
|
|
175
|
+
number_of_characters_per_link: int
|
|
176
|
+
) -> list[str]:
|
|
177
|
+
""" The function to fetch all URLs not concurrently without using threads """
|
|
178
|
+
contents = []
|
|
179
|
+
|
|
180
|
+
for url in urls:
|
|
181
|
+
data = _fetch_content(url, number_of_characters_per_link)
|
|
182
|
+
contents.append(data)
|
|
183
|
+
|
|
184
|
+
return contents
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def _fetch_content(url, number_of_characters_per_link, headless: bool = True):
|
|
174
188
|
""" Function to fetch content from a single URL using the synchronous Playwright API """
|
|
175
189
|
with sync_playwright() as p:
|
|
176
|
-
browser = p.chromium.launch(headless=
|
|
190
|
+
browser = p.chromium.launch(headless=headless)
|
|
177
191
|
page = browser.new_page()
|
|
178
192
|
page.goto(url)
|
|
179
193
|
|
|
@@ -67,6 +67,8 @@ def get_wmi_network_configuration(
|
|
|
67
67
|
current_adapter = None
|
|
68
68
|
if use_default_interface:
|
|
69
69
|
default_connection_name_dict: dict = networks.get_default_connection_name()
|
|
70
|
+
if not default_connection_name_dict:
|
|
71
|
+
raise NetworkAdapterNotFoundError("Default network adapter not found.")
|
|
70
72
|
# Get the first key from the dictionary.
|
|
71
73
|
connection_name: str = list(default_connection_name_dict.keys())[0]
|
|
72
74
|
|
|
@@ -142,6 +142,7 @@ def get_default_dns_gateway() -> tuple[bool, list[str]]:
|
|
|
142
142
|
Get the default DNS gateway from the Windows registry.
|
|
143
143
|
|
|
144
144
|
:return: tuple(is dynamic boolean, list of DNS server IPv4s).
|
|
145
|
+
If nothing found will return (None, None).
|
|
145
146
|
"""
|
|
146
147
|
|
|
147
148
|
def get_current_interface_status(current_interface_settings: dict) -> tuple[bool, list[str]]:
|
|
@@ -199,5 +200,8 @@ def get_default_dns_gateway() -> tuple[bool, list[str]]:
|
|
|
199
200
|
|
|
200
201
|
break
|
|
201
202
|
|
|
203
|
+
if not function_result:
|
|
204
|
+
function_result = (None, None)
|
|
205
|
+
|
|
202
206
|
# noinspection PyTypeChecker
|
|
203
207
|
return function_result
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
atomicshop/__init__.py,sha256=
|
|
1
|
+
atomicshop/__init__.py,sha256=4FSjqwMFkYpX_2ecHcCr9_kKJr3wxoGRDCSyZgRd6Dw,123
|
|
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
|
|
@@ -14,19 +14,19 @@ atomicshop/dns.py,sha256=5Gimq_WY2arqg7BeGmR7P--fGfnH0Dsh8lrOt_H0jRY,6817
|
|
|
14
14
|
atomicshop/domains.py,sha256=Rxu6JhhMqFZRcoFs69IoEd1PtYca0lMCG6F1AomP7z4,3197
|
|
15
15
|
atomicshop/emails.py,sha256=I0KyODQpIMEsNRi9YWSOL8EUPBiWyon3HRdIuSj3AEU,1410
|
|
16
16
|
atomicshop/file_types.py,sha256=-0jzQMRlmU1AP9DARjk-HJm1tVE22E6ngP2mRblyEjY,763
|
|
17
|
-
atomicshop/filesystem.py,sha256=
|
|
17
|
+
atomicshop/filesystem.py,sha256=8Y5xLaTutQtEjWPxIwH_H88laN7plEMp2r4OLHk-3xc,58259
|
|
18
18
|
atomicshop/functions.py,sha256=pK8hoCE9z61PtWCxQJsda7YAphrLH1wxU5x-1QJP-sY,499
|
|
19
19
|
atomicshop/get_process_list.py,sha256=8cxb7gKe9sl4R6H2yMi8J6oe-RkonTvCdKjRFqi-Fs4,6075
|
|
20
20
|
atomicshop/get_process_name_cmd_dll.py,sha256=CtaSp3mgxxJKCCVW8BLx6BJNx4giCklU_T7USiCEwfc,5162
|
|
21
21
|
atomicshop/hashing.py,sha256=Le8qGFyt3_wX-zGTeQShz7L2HL_b6nVv9PnawjglyHo,3474
|
|
22
22
|
atomicshop/http_parse.py,sha256=1Tna9YbOM0rE3t6i_M-klBlwd1KNSA9skA_BqKGXDFc,11861
|
|
23
23
|
atomicshop/inspect_wrapper.py,sha256=sGRVQhrJovNygHTydqJj0hxES-aB2Eg9KbIk3G31apw,11429
|
|
24
|
-
atomicshop/ip_addresses.py,sha256=
|
|
24
|
+
atomicshop/ip_addresses.py,sha256=penRFeJ1-LDVTko4Q0EwK4JiN5cU-KzCBR2VXg9qbUY,1238
|
|
25
25
|
atomicshop/keyboard_press.py,sha256=1W5kRtOB75fulVx-uF2yarBhW0_IzdI1k73AnvXstk0,452
|
|
26
26
|
atomicshop/on_exit.py,sha256=Rpg2SaF0aginuO7JYwA49YJYnS8F6K2jUqhjH65WzuU,6889
|
|
27
27
|
atomicshop/pbtkmultifile_argparse.py,sha256=aEk8nhvoQVu-xyfZosK3ma17CwIgOjzO1erXXdjwtS4,4574
|
|
28
28
|
atomicshop/print_api.py,sha256=q9dAQCASk3pHp_PtYIpr6iZmRcW_lvrV_gPPNwTMRsw,11152
|
|
29
|
-
atomicshop/process.py,sha256=
|
|
29
|
+
atomicshop/process.py,sha256=dmje2YIDPVM8zS38ylAqyOhDBXk6ay_N1xeewKdEIX4,16966
|
|
30
30
|
atomicshop/python_file_patcher.py,sha256=-uhbUX-um5k-If_XXuOfCr8wMzZ3QE6h9N8xGWw6W_o,5486
|
|
31
31
|
atomicshop/python_functions.py,sha256=BPZ3sv5DgQs6Xrl3nIMdPABRpgrau3XSrsnDIz-LEwY,6175
|
|
32
32
|
atomicshop/question_answer_engine.py,sha256=7nM6kGDSFjQNi87b87-kP9lYM0vTjBHn1rEQGNAfdGA,825
|
|
@@ -77,9 +77,9 @@ atomicshop/addons/process_list/compiled/Win10x64/process_list.exp,sha256=cbvukIT
|
|
|
77
77
|
atomicshop/addons/process_list/compiled/Win10x64/process_list.lib,sha256=T2Ncs0MwKlAaCq8UKFMvfQAfcJdDx-nWiHVBfglrLIU,2112
|
|
78
78
|
atomicshop/archiver/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
79
79
|
atomicshop/archiver/_search_in_zip.py,sha256=dd8qFSvIhcKmtnPj_uYNJFPmMwZp4tZys0kKgTw_ACw,8385
|
|
80
|
-
atomicshop/archiver/search_in_archive.py,sha256=
|
|
80
|
+
atomicshop/archiver/search_in_archive.py,sha256=EmWif1EmIy-IpOLgcj-y-Sqrh2M3MtLN94aNQzUhrrQ,12300
|
|
81
81
|
atomicshop/archiver/sevenz_app_w.py,sha256=BWcJb4f7jZEiETDBKyNLE0f5YLFPQx6B91_ObEIXWf8,3007
|
|
82
|
-
atomicshop/archiver/sevenzs.py,sha256=
|
|
82
|
+
atomicshop/archiver/sevenzs.py,sha256=b9rI-nF36ZNawwKsPWOgsnm0p-jYDfD1NYV3eA8LoQ0,2491
|
|
83
83
|
atomicshop/archiver/shutils.py,sha256=BomnK7zT-nQXA1z0i2R2aTv8eu88wPx7tf2HtOdbmEc,1280
|
|
84
84
|
atomicshop/archiver/zips.py,sha256=0Z_1MWs7YRiCBVpyaG8llnzRguHSO4R51KDMN3FJZt8,16984
|
|
85
85
|
atomicshop/basics/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -127,7 +127,7 @@ atomicshop/file_io/xmls.py,sha256=zh3SuK-dNaFq2NDNhx6ivcf4GYCfGM8M10PcEwDSpxk,21
|
|
|
127
127
|
atomicshop/mitm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
128
128
|
atomicshop/mitm/config_static.py,sha256=HIzxyMEj7DZksYvJsN5VuKpB-_HSVvuR6U59ztS9gi0,7871
|
|
129
129
|
atomicshop/mitm/config_toml_editor.py,sha256=2p1CMcktWRR_NW-SmyDwylu63ad5e0-w1QPMa8ZLDBw,1635
|
|
130
|
-
atomicshop/mitm/connection_thread_worker.py,sha256=
|
|
130
|
+
atomicshop/mitm/connection_thread_worker.py,sha256=9IWN4LP5ZoYqVJTpoIhaOUiusn6kXUbj7_g4kXOKFIU,27169
|
|
131
131
|
atomicshop/mitm/import_config.py,sha256=0Ij14aISTllTOiWYJpIUMOWobQqGofD6uafui5uWllE,9272
|
|
132
132
|
atomicshop/mitm/initialize_engines.py,sha256=NWz0yBErSrYBn0xWkJDBcHStBJ-kcsv9VtorcSP9x5M,8258
|
|
133
133
|
atomicshop/mitm/message.py,sha256=mNo4Lphr_Jo6IlNX5mPJzABpogWGkjOhwI4meAivwHw,2987
|
|
@@ -141,11 +141,11 @@ atomicshop/mitm/engines/create_module_template_example.py,sha256=X5xhvbV6-g9jU_b
|
|
|
141
141
|
atomicshop/mitm/engines/__parent/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
142
142
|
atomicshop/mitm/engines/__parent/parser___parent.py,sha256=HHaCXhScl3OlPjz6eUxsDpJaZyk6BNuDMc9xCkeo2Ws,661
|
|
143
143
|
atomicshop/mitm/engines/__parent/recorder___parent.py,sha256=exfElkgOU57hupV6opRCeYPHw91GIkIZL6UY3f2OClM,5635
|
|
144
|
-
atomicshop/mitm/engines/__parent/responder___parent.py,sha256=
|
|
144
|
+
atomicshop/mitm/engines/__parent/responder___parent.py,sha256=qIxfPiVZs4ZDDFYYeJJAiBWYg0cSfNDC-ibpGYnB2tA,8926
|
|
145
145
|
atomicshop/mitm/engines/__reference_general/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
146
146
|
atomicshop/mitm/engines/__reference_general/parser___reference_general.py,sha256=57MEPZMAjTO6xBDZ-yt6lgGJyqRrP0Do5Gk_cgCiPns,2998
|
|
147
147
|
atomicshop/mitm/engines/__reference_general/recorder___reference_general.py,sha256=El2_YHLoHUCiKfkAmGlXxtFpmSjsUFdsb8I1MvSAFaM,653
|
|
148
|
-
atomicshop/mitm/engines/__reference_general/responder___reference_general.py,sha256=
|
|
148
|
+
atomicshop/mitm/engines/__reference_general/responder___reference_general.py,sha256=r7WMv59xlVNttz15ppUvQbH2j5eKHAI-yIy1SCCu2lw,9523
|
|
149
149
|
atomicshop/mitm/statistic_analyzer_helper/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
150
150
|
atomicshop/mitm/statistic_analyzer_helper/analyzer_helper.py,sha256=pk6L1t1ea1kvlBoR9QEJptOmaX-mumhwLsP2GCKukbk,5920
|
|
151
151
|
atomicshop/mitm/statistic_analyzer_helper/moving_average_helper.py,sha256=UnnY_FSTiXEfZ8SkDKU2s2qpgPYu1oOT99ghmY-zzas,19992
|
|
@@ -262,7 +262,7 @@ atomicshop/wrappers/mongodbw/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NM
|
|
|
262
262
|
atomicshop/wrappers/mongodbw/install_mongodb_ubuntu.py,sha256=pmI9AwWJ2cv5h8GionSpSJkllg6kfp0M381pk6y4Y5U,4015
|
|
263
263
|
atomicshop/wrappers/mongodbw/install_mongodb_win.py,sha256=64EUQYx7VuMC3ndO2x3nSErh5NZ_BsqMwGvPcybfC-Q,8499
|
|
264
264
|
atomicshop/wrappers/mongodbw/mongo_infra.py,sha256=IjEF0jPzQz866MpTm7rnksnyyWQeUT_B2h2DA9ryAio,2034
|
|
265
|
-
atomicshop/wrappers/mongodbw/mongodbw.py,sha256=
|
|
265
|
+
atomicshop/wrappers/mongodbw/mongodbw.py,sha256=ih3Gd45rg_70y4sGeu0eEJ3sJd9tEN4I5IqHZelRZJw,52854
|
|
266
266
|
atomicshop/wrappers/nodejsw/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
267
267
|
atomicshop/wrappers/nodejsw/install_nodejs.py,sha256=TKGa3jSlSqZTL2NA0nMkWDFtlkz7rxGGn44ywCg7MN8,5228
|
|
268
268
|
atomicshop/wrappers/playwrightw/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -275,7 +275,7 @@ atomicshop/wrappers/playwrightw/javascript.py,sha256=_bW7CAtm0Y8IHYrAalg5HpPFnk6
|
|
|
275
275
|
atomicshop/wrappers/playwrightw/keyboard.py,sha256=zN3YddGO-qUkn6C0CRVFejP4cTuaUwXLDNFhFREjERY,422
|
|
276
276
|
atomicshop/wrappers/playwrightw/locators.py,sha256=6wsLywZxDuii7mwv-zQsRbqQC8r7j96Bma5b5_7ZoVo,2411
|
|
277
277
|
atomicshop/wrappers/playwrightw/mouse.py,sha256=-2FZbQtjgH7tdXWld6ZPGqlKFUdf5in0ujN0hewxa50,656
|
|
278
|
-
atomicshop/wrappers/playwrightw/scenarios.py,sha256=
|
|
278
|
+
atomicshop/wrappers/playwrightw/scenarios.py,sha256=HopJJ-caAHuXxH8kiJHtlcFSI-89Zx7Fc6caGPOHC2A,8786
|
|
279
279
|
atomicshop/wrappers/playwrightw/waits.py,sha256=PBFdz_PoM7Fo7O8hLqMrxNPzBEYgPoXwZceFFCGGeu8,7182
|
|
280
280
|
atomicshop/wrappers/psutilw/cpus.py,sha256=w6LPBMINqS-T_X8vzdYkLS2Wzuve28Ydp_GafTCngrc,236
|
|
281
281
|
atomicshop/wrappers/psutilw/disks.py,sha256=3ZSVoommKH1TWo37j_83frB-NqXF4Nf5q5mBCX8G4jE,9221
|
|
@@ -299,7 +299,7 @@ atomicshop/wrappers/pywin32w/win_event_log/subscribes/process_terminate.py,sha25
|
|
|
299
299
|
atomicshop/wrappers/pywin32w/win_event_log/subscribes/schannel_logging.py,sha256=8nxIcNcbeEuvoBwhujgh7-oIpL9A6J-gg1NM8hOGAVA,3442
|
|
300
300
|
atomicshop/wrappers/pywin32w/wmis/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
301
301
|
atomicshop/wrappers/pywin32w/wmis/helpers.py,sha256=uMXa27UfBpqXInvnmk7CZlqwRI2pg_I_HXelxO9nLLg,5020
|
|
302
|
-
atomicshop/wrappers/pywin32w/wmis/win32networkadapter.py,sha256=
|
|
302
|
+
atomicshop/wrappers/pywin32w/wmis/win32networkadapter.py,sha256=Jzl95viXZExrrlDTGHR0-wiXJo3jQRztmLXkigahFww,5574
|
|
303
303
|
atomicshop/wrappers/pywin32w/wmis/win32process.py,sha256=qMzXtJ5hBZ5ydAyqpDbSx0nO2RJQL95HdmV5SzNKMhk,6826
|
|
304
304
|
atomicshop/wrappers/socketw/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
305
305
|
atomicshop/wrappers/socketw/accepter.py,sha256=hZZKVYlF3LOHQJsSIEKXZUf6QXXWm-AtqXZevvaYigE,1732
|
|
@@ -318,9 +318,9 @@ atomicshop/wrappers/socketw/socket_wrapper.py,sha256=WtylpezgIIBuz-A6PfM0hO1sm9E
|
|
|
318
318
|
atomicshop/wrappers/socketw/ssl_base.py,sha256=kmiif84kMhBr5yjQW17p935sfjR5JKG0LxIwBA4iVvU,2275
|
|
319
319
|
atomicshop/wrappers/socketw/statistics_csv.py,sha256=fgMzDXI0cybwUEqAxprRmY3lqbh30KAV-jOpoFKT-m8,3395
|
|
320
320
|
atomicshop/wrappers/winregw/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
321
|
-
atomicshop/wrappers/winregw/winreg_network.py,sha256=
|
|
322
|
-
atomicshop-2.18.
|
|
323
|
-
atomicshop-2.18.
|
|
324
|
-
atomicshop-2.18.
|
|
325
|
-
atomicshop-2.18.
|
|
326
|
-
atomicshop-2.18.
|
|
321
|
+
atomicshop/wrappers/winregw/winreg_network.py,sha256=AENV88H1qDidrcpyM9OwEZxX5svfi-Jb4N6FkS1xtqA,8851
|
|
322
|
+
atomicshop-2.18.8.dist-info/LICENSE.txt,sha256=lLU7EYycfYcK2NR_1gfnhnRC8b8ccOTElACYplgZN88,1094
|
|
323
|
+
atomicshop-2.18.8.dist-info/METADATA,sha256=37oxDInywUGEbgwoNSHN5Lu2UUt4zTNruStPlhVdfmg,10576
|
|
324
|
+
atomicshop-2.18.8.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
|
325
|
+
atomicshop-2.18.8.dist-info/top_level.txt,sha256=EgKJB-7xcrAPeqTRF2laD_Np2gNGYkJkd4OyXqpJphA,11
|
|
326
|
+
atomicshop-2.18.8.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|