atomicshop 2.16.35__py3-none-any.whl → 2.16.37__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/basics/exceptions.py +5 -1
- atomicshop/mitm/connection_thread_worker.py +2 -0
- atomicshop/wrappers/socketw/dns_server.py +2 -2
- atomicshop/wrappers/socketw/sender.py +1 -1
- atomicshop/wrappers/socketw/socket_client.py +59 -66
- {atomicshop-2.16.35.dist-info → atomicshop-2.16.37.dist-info}/METADATA +1 -1
- {atomicshop-2.16.35.dist-info → atomicshop-2.16.37.dist-info}/RECORD +11 -11
- {atomicshop-2.16.35.dist-info → atomicshop-2.16.37.dist-info}/LICENSE.txt +0 -0
- {atomicshop-2.16.35.dist-info → atomicshop-2.16.37.dist-info}/WHEEL +0 -0
- {atomicshop-2.16.35.dist-info → atomicshop-2.16.37.dist-info}/top_level.txt +0 -0
atomicshop/__init__.py
CHANGED
atomicshop/basics/exceptions.py
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
# v1.0.3 - 28.03.2023 17:20
|
|
2
1
|
import sys
|
|
3
2
|
|
|
4
3
|
from .threads import current_thread_id
|
|
@@ -15,3 +14,8 @@ def print_exception() -> None:
|
|
|
15
14
|
exc_type, exc_value, exc_traceback = sys.exc_info()
|
|
16
15
|
|
|
17
16
|
print(f"{error_log_prefix} Thread {thread_id}: * Details: {exc_type}, {exc_value}")
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def get_exception_type_string(exception: Exception) -> str:
|
|
20
|
+
""" Get exception type string """
|
|
21
|
+
return type(exception).__name__
|
|
@@ -316,7 +316,7 @@ class DnsServer:
|
|
|
316
316
|
print_api(message, logger=self.logger)
|
|
317
317
|
|
|
318
318
|
message = f"Current engine domains: {self.tcp_resolve_domain_list}"
|
|
319
|
-
print_api(message, logger=self.logger, color='
|
|
319
|
+
print_api(message, logger=self.logger, color='blue')
|
|
320
320
|
|
|
321
321
|
if self.resolve_to_tcp_server_all_domains:
|
|
322
322
|
message = "Routing all domains to Built-in TCP Server."
|
|
@@ -324,7 +324,7 @@ class DnsServer:
|
|
|
324
324
|
|
|
325
325
|
if self.resolve_regular:
|
|
326
326
|
message = f"Routing all domains to Live DNS Service: {self.forwarding_dns_service_ipv4}"
|
|
327
|
-
print_api(message, logger=self.logger, color='
|
|
327
|
+
print_api(message, logger=self.logger, color='blue')
|
|
328
328
|
|
|
329
329
|
# The list that will hold all the threads that can be joined later
|
|
330
330
|
threads_list: list = list()
|
|
@@ -76,7 +76,7 @@ class Sender:
|
|
|
76
76
|
destination_address = self.ssl_socket.server_hostname
|
|
77
77
|
destination: str = f'[{source_address}:{source_port}<->{destination_address}:{destination_port}]'
|
|
78
78
|
|
|
79
|
-
error_class_type =
|
|
79
|
+
error_class_type = type(e).__name__
|
|
80
80
|
exception_error = tracebacks.get_as_string(one_line=True)
|
|
81
81
|
|
|
82
82
|
if 'ssl' in error_class_type.lower():
|
|
@@ -18,6 +18,7 @@ from .. import cryptographyw
|
|
|
18
18
|
from ..loggingw import loggingw
|
|
19
19
|
from ...print_api import print_api
|
|
20
20
|
from ...file_io import file_io
|
|
21
|
+
from ...basics import tracebacks
|
|
21
22
|
|
|
22
23
|
|
|
23
24
|
class SocketClient:
|
|
@@ -55,6 +56,12 @@ class SocketClient:
|
|
|
55
56
|
self.connection_ip = connection_ip
|
|
56
57
|
self.dns_servers_list = dns_servers_list
|
|
57
58
|
|
|
59
|
+
if logger:
|
|
60
|
+
# Create child logger for the provided logger with the module's name.
|
|
61
|
+
self.logger: logging.Logger = loggingw.get_logger_with_level(f'{logger.name}.{Path(__file__).stem}')
|
|
62
|
+
else:
|
|
63
|
+
self.logger: logging.Logger = logger
|
|
64
|
+
|
|
58
65
|
self.socket_instance = None
|
|
59
66
|
|
|
60
67
|
# If 'connection_ip' was specified, but no 'dns_servers_list', then this IP will be used for 'socket.connect()'.
|
|
@@ -68,12 +75,6 @@ class SocketClient:
|
|
|
68
75
|
elif self.connection_ip and self.dns_servers_list:
|
|
69
76
|
raise ValueError("Both 'connection_ip' and 'dns_servers_list' were specified.")
|
|
70
77
|
|
|
71
|
-
if logger:
|
|
72
|
-
# Create child logger for the provided logger with the module's name.
|
|
73
|
-
self.logger: logging.Logger = loggingw.get_logger_with_level(f'{logger.name}.{Path(__file__).stem}')
|
|
74
|
-
else:
|
|
75
|
-
self.logger: logging.Logger = logger
|
|
76
|
-
|
|
77
78
|
# Function to create SSL socket to destination service
|
|
78
79
|
def create_service_socket(self):
|
|
79
80
|
# If TLS is enabled.
|
|
@@ -86,8 +87,18 @@ class SocketClient:
|
|
|
86
87
|
return creator.wrap_socket_with_ssl_context_client___default_certs___ignore_verification(
|
|
87
88
|
socket_object, self.service_name)
|
|
88
89
|
|
|
89
|
-
def service_connection(
|
|
90
|
-
|
|
90
|
+
def service_connection(
|
|
91
|
+
self
|
|
92
|
+
) -> tuple[
|
|
93
|
+
Union[socket.socket, ssl.SSLSocket, None],
|
|
94
|
+
Union[str, None]]:
|
|
95
|
+
"""
|
|
96
|
+
Function to establish connection to server
|
|
97
|
+
|
|
98
|
+
:return: Tuple with socket object and error string.
|
|
99
|
+
If connection was successful, the error string will be None.
|
|
100
|
+
If connection wasn't successful, the socket object will be None.
|
|
101
|
+
"""
|
|
91
102
|
# Check if socket to service domain exists.
|
|
92
103
|
# If not
|
|
93
104
|
if not self.socket_instance:
|
|
@@ -106,8 +117,8 @@ class SocketClient:
|
|
|
106
117
|
f"Socket already defined to [{self.service_name}:{self.service_port}]. "
|
|
107
118
|
f"Should be connected - Reusing.")
|
|
108
119
|
# Since, restart the function each send_receive iteration, and there's still a connection we need to
|
|
109
|
-
#
|
|
110
|
-
return
|
|
120
|
+
# return the socket, or the socket object will be nullified in the next step.
|
|
121
|
+
return self.socket_instance
|
|
111
122
|
|
|
112
123
|
# If 'dns_servers_list' was provided, we will resolve the domain to ip through these servers.
|
|
113
124
|
if self.dns_servers_list:
|
|
@@ -125,11 +136,13 @@ class SocketClient:
|
|
|
125
136
|
# Get only the first entry of the list of IPs [0]
|
|
126
137
|
self.connection_ip = function_server_address[0].to_text()
|
|
127
138
|
self.logger.info(f"Resolved to [{self.connection_ip}]")
|
|
128
|
-
except dns.resolver.NXDOMAIN:
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
139
|
+
except dns.resolver.NXDOMAIN as e:
|
|
140
|
+
exception_type: str = type(e).__name__
|
|
141
|
+
error_string = (
|
|
142
|
+
f"Socket Client Connect: {exception_type}: "
|
|
143
|
+
f"Domain {self.service_name} doesn't exist - Couldn't resolve with {self.dns_servers_list}.")
|
|
144
|
+
print_api(error_string, logger=self.logger, logger_method='error')
|
|
145
|
+
return None, error_string
|
|
133
146
|
|
|
134
147
|
# If DNS was resolved correctly or DNS servers weren't specified - we can try connecting.
|
|
135
148
|
# If 'connection_ip' was manually specified or resolved with 'dnspython' - the connection
|
|
@@ -144,49 +157,31 @@ class SocketClient:
|
|
|
144
157
|
try:
|
|
145
158
|
# "connect()" to the server using address and port
|
|
146
159
|
self.socket_instance.connect((destination, self.service_port))
|
|
147
|
-
except
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
except ssl.SSLError:
|
|
167
|
-
message = f"SSLError raised on connection to {self.service_name}."
|
|
168
|
-
print_api(message, logger=self.logger, logger_method='error', traceback_string=True, oneline=True)
|
|
169
|
-
# Socket close will be handled in the thread_worker_main
|
|
170
|
-
pass
|
|
171
|
-
return None
|
|
172
|
-
except TimeoutError:
|
|
173
|
-
message = f"TimeoutError raised on connection to {self.service_name}."
|
|
174
|
-
print_api(message, logger=self.logger, logger_method='error', traceback_string=True, oneline=True)
|
|
175
|
-
# Socket close will be handled in the thread_worker_main
|
|
176
|
-
pass
|
|
177
|
-
return None
|
|
178
|
-
except ValueError as e:
|
|
179
|
-
message = f'{str(e)} | on connect to [{self.service_name}].'
|
|
180
|
-
print_api(message, logger=self.logger, logger_method='error')
|
|
181
|
-
# Socket close will be handled in the thread_worker_main
|
|
182
|
-
pass
|
|
183
|
-
return None
|
|
160
|
+
except Exception as e:
|
|
161
|
+
exception_type: str = type(e).__name__
|
|
162
|
+
exception_error: str = tracebacks.get_as_string(one_line=True)
|
|
163
|
+
error_string: str = f"Socket Client Connect: {destination}: {exception_type}"
|
|
164
|
+
|
|
165
|
+
if exception_type in ['ConnectionRefusedError', 'ConnectionAbortedError', 'ConnectionResetError',
|
|
166
|
+
'ssl.SSLError', 'TimeoutError']:
|
|
167
|
+
error_message: str = f"{error_string}: {exception_error}"
|
|
168
|
+
print_api(error_message, logger=self.logger, logger_method='error')
|
|
169
|
+
return None, error_message
|
|
170
|
+
elif exception_type == 'socket.gaierror':
|
|
171
|
+
custom_error_message: str = (
|
|
172
|
+
f"Couldn't resolve [{self.service_name}] to IP using default methods. "
|
|
173
|
+
f"Domain doesn't exist or there's no IP assigned to it.")
|
|
174
|
+
error_message: str = f"{error_string}: {custom_error_message}"
|
|
175
|
+
print_api(error_message, logger=self.logger, logger_method='error')
|
|
176
|
+
return None, error_message
|
|
177
|
+
else:
|
|
178
|
+
raise e
|
|
184
179
|
|
|
185
180
|
# If everything was fine, we'll log the connection.
|
|
186
181
|
self.logger.info("Connected...")
|
|
187
182
|
|
|
188
183
|
# Return the connected socket.
|
|
189
|
-
return self.socket_instance
|
|
184
|
+
return self.socket_instance, None
|
|
190
185
|
|
|
191
186
|
def get_socket(self):
|
|
192
187
|
return self.socket_instance
|
|
@@ -200,14 +195,12 @@ class SocketClient:
|
|
|
200
195
|
def send_receive_to_service(self, request_bytes: bytearray):
|
|
201
196
|
# Define variables
|
|
202
197
|
function_service_data = None
|
|
203
|
-
|
|
198
|
+
error_message = None
|
|
204
199
|
|
|
200
|
+
service_socket, error_message = self.service_connection()
|
|
205
201
|
# If connection to service server wasn't successful
|
|
206
|
-
if
|
|
207
|
-
|
|
208
|
-
print_api(error_string, logger=self.logger, logger_method='error')
|
|
209
|
-
|
|
210
|
-
# We'll close the socket and nullify the object
|
|
202
|
+
if error_message:
|
|
203
|
+
# Wasn't able to connect to service, closing the destination service socket and nullify the object.
|
|
211
204
|
self.close_socket()
|
|
212
205
|
# If the connection to the service was successful
|
|
213
206
|
else:
|
|
@@ -227,7 +220,7 @@ class SocketClient:
|
|
|
227
220
|
|
|
228
221
|
# If the socket disconnected on data send
|
|
229
222
|
if error_on_send:
|
|
230
|
-
|
|
223
|
+
error_message = f"Service socket closed on data send: {error_on_send}"
|
|
231
224
|
|
|
232
225
|
# We'll close the socket and nullify the object
|
|
233
226
|
self.close_socket()
|
|
@@ -238,12 +231,12 @@ class SocketClient:
|
|
|
238
231
|
|
|
239
232
|
# If data received is empty meaning the socket was closed on the other side
|
|
240
233
|
if not function_service_data:
|
|
241
|
-
|
|
234
|
+
error_message = "Service server closed the connection on receive"
|
|
242
235
|
|
|
243
236
|
# We'll close the socket and nullify the object
|
|
244
237
|
self.close_socket()
|
|
245
238
|
|
|
246
|
-
return function_service_data,
|
|
239
|
+
return function_service_data, error_message, self.connection_ip, self.socket_instance
|
|
247
240
|
|
|
248
241
|
def send_receive_message_list_with_interval(
|
|
249
242
|
self, requests_bytes_list: list, intervals_list: list, intervals_defaults: int, cycles: int = 1):
|
|
@@ -316,15 +309,15 @@ class SocketClient:
|
|
|
316
309
|
# be passed.
|
|
317
310
|
# If there was connection error or socket close, then "ssl_socket" of the "service_client"
|
|
318
311
|
# will be empty.
|
|
319
|
-
response_raw_bytes,
|
|
312
|
+
response_raw_bytes, error_message, self.connection_ip, service_ssl_socket = \
|
|
320
313
|
self.send_receive_to_service(request_raw_bytes)
|
|
321
314
|
|
|
322
315
|
# Adding the response to responses list. Same for error.
|
|
323
316
|
responses_list.append(response_raw_bytes)
|
|
324
|
-
errors_list.append(
|
|
317
|
+
errors_list.append(error_message)
|
|
325
318
|
|
|
326
319
|
self.logger.info(f"Response: {response_raw_bytes}")
|
|
327
|
-
self.logger.info(f"Error: {
|
|
320
|
+
self.logger.info(f"Error: {error_message}")
|
|
328
321
|
|
|
329
322
|
# So if the socket was closed and there was an error we can break the loop.
|
|
330
323
|
# This is needed for more complex operations
|
|
@@ -359,7 +352,7 @@ class SocketClient:
|
|
|
359
352
|
raise ValueError("If 'save_as_file' is True, then 'cert_file_path' must be provided.")
|
|
360
353
|
|
|
361
354
|
# Connect and get the connected socket.
|
|
362
|
-
server_socket_for_certificate = self.service_connection()
|
|
355
|
+
server_socket_for_certificate, error_message = self.service_connection()
|
|
363
356
|
# Get the DER byte certificate from the socket.
|
|
364
357
|
certificate_from_socket_der_bytes = ssl_base.get_certificate_from_socket(server_socket_for_certificate)
|
|
365
358
|
print_api('Fetched certificate from socket.', logger=self.logger, **kwargs)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
atomicshop/__init__.py,sha256=
|
|
1
|
+
atomicshop/__init__.py,sha256=ym3OPl2oH_mHsSJELO-ElUvWSSDSZmEGXFuzBQB5lt8,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
|
|
@@ -90,7 +90,7 @@ atomicshop/basics/dicts.py,sha256=DeYHIh940pMMBrFhpXt4dsigFVYzTrlqWymNo4Pq_Js,14
|
|
|
90
90
|
atomicshop/basics/dicts_nested.py,sha256=StYxYnYPa0SEJr1lmEwAv5zfERWWqoULeyG8e0zRAwE,4107
|
|
91
91
|
atomicshop/basics/enumerations.py,sha256=41VVQYh_vnVapggxKg2IRU5e_EiMpZzX1n1mtxvoSzM,1364
|
|
92
92
|
atomicshop/basics/enums.py,sha256=aAk1jFeQLvrC4NOpk9kgyX1-DCBr2ArPhZ8Ad7cMAVA,3537
|
|
93
|
-
atomicshop/basics/exceptions.py,sha256
|
|
93
|
+
atomicshop/basics/exceptions.py,sha256=8mhhdQloYVz8D3u16I5O_cMeuIf5pPTXoi1iY94O9zw,616
|
|
94
94
|
atomicshop/basics/guids.py,sha256=iRx5n18ATZWhpo748BwEjuLWLsu9y3OwF5-Adp-Dtik,403
|
|
95
95
|
atomicshop/basics/hexs.py,sha256=i8CTG-J0TGGa25yFSbWEvpVyHFnof_qSWUrmXY-ylKM,1054
|
|
96
96
|
atomicshop/basics/if_else.py,sha256=MakivJChofZCpr0mOVjwCthzpiaBxXVB-zv7GwMOqVo,202
|
|
@@ -125,7 +125,7 @@ atomicshop/file_io/xmls.py,sha256=zh3SuK-dNaFq2NDNhx6ivcf4GYCfGM8M10PcEwDSpxk,21
|
|
|
125
125
|
atomicshop/mitm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
126
126
|
atomicshop/mitm/config_static.py,sha256=ROAtbibSWSsF3BraUbhu-QO3MPIFqYY5KUKgsQbiSkk,7813
|
|
127
127
|
atomicshop/mitm/config_toml_editor.py,sha256=2p1CMcktWRR_NW-SmyDwylu63ad5e0-w1QPMa8ZLDBw,1635
|
|
128
|
-
atomicshop/mitm/connection_thread_worker.py,sha256=
|
|
128
|
+
atomicshop/mitm/connection_thread_worker.py,sha256=YdPL2E2ZYV5nnuaXXtyBZssT4qDalVb05BVO62MwW0k,16627
|
|
129
129
|
atomicshop/mitm/import_config.py,sha256=ZKQXxbtjVqzN9fpRrMwPNQREecH06RG8F_nXZAKTUJM,8182
|
|
130
130
|
atomicshop/mitm/initialize_engines.py,sha256=VyJE8QnzlgD3QbX5inz5o6rC3zQ3is9CeTL7-B10g1w,8292
|
|
131
131
|
atomicshop/mitm/message.py,sha256=URR5JKSuAT8XmGIkyprEjlPW2GW4ef_gfUz_GgcFseE,2184
|
|
@@ -299,21 +299,21 @@ atomicshop/wrappers/socketw/accepter.py,sha256=hZZKVYlF3LOHQJsSIEKXZUf6QXXWm-Atq
|
|
|
299
299
|
atomicshop/wrappers/socketw/base.py,sha256=evoOIxg5Xff3THJnrVX00D5HobaOpDp6_e_gso7TJmA,2191
|
|
300
300
|
atomicshop/wrappers/socketw/certificator.py,sha256=3CpQKtcW68FSbH6LVSEZTqWBS6Yg_-3K0x4nFkId4UY,12236
|
|
301
301
|
atomicshop/wrappers/socketw/creator.py,sha256=3_OraDkw2DAWZfoSdY3svCGMOIxpjLEEY7NxWd7M5P4,9873
|
|
302
|
-
atomicshop/wrappers/socketw/dns_server.py,sha256=
|
|
302
|
+
atomicshop/wrappers/socketw/dns_server.py,sha256=RklzINNuoMQn4PGGQEI5hiAldprbVwwvikY6u9X-jTY,49067
|
|
303
303
|
atomicshop/wrappers/socketw/exception_wrapper.py,sha256=B-X5SHLSUIWToihH2MKnOB1F4A81_X0DpLLfnYKYbEc,7067
|
|
304
304
|
atomicshop/wrappers/socketw/get_process.py,sha256=aJC-_qFUv3NgWCSUzDI72E4z8_-VTZE9NVZ0CwUoNlM,5698
|
|
305
305
|
atomicshop/wrappers/socketw/receiver.py,sha256=XVvWOoeCo3vA0O5p19ryi-hcDIyx382WNG7WzMNVeYk,9322
|
|
306
|
-
atomicshop/wrappers/socketw/sender.py,sha256=
|
|
306
|
+
atomicshop/wrappers/socketw/sender.py,sha256=vjgU1TaADJjaYiZOkLzfxcdCbmkvjhEhVjSV5mmIbw8,4969
|
|
307
307
|
atomicshop/wrappers/socketw/sni.py,sha256=J1kPnQ77XwKN1pO5aOI1c_VfhuivCm95OOaQxMpPuZ0,17627
|
|
308
|
-
atomicshop/wrappers/socketw/socket_client.py,sha256=
|
|
308
|
+
atomicshop/wrappers/socketw/socket_client.py,sha256=B_4jI0RWorHcO3i9R9KLoX1-4NlTf2pfJfgXiMGH0jM,19861
|
|
309
309
|
atomicshop/wrappers/socketw/socket_server_tester.py,sha256=Qobmh4XV8ZxLUaw-eW4ESKAbeSLecCKn2OWFzMhadk0,6420
|
|
310
310
|
atomicshop/wrappers/socketw/socket_wrapper.py,sha256=WtylpezgIIBuz-A6PfM0hO1sm9Exd4j3qhDXcFc74-E,35567
|
|
311
311
|
atomicshop/wrappers/socketw/ssl_base.py,sha256=kmiif84kMhBr5yjQW17p935sfjR5JKG0LxIwBA4iVvU,2275
|
|
312
312
|
atomicshop/wrappers/socketw/statistics_csv.py,sha256=w1AH-zf4mBuT4euf28UKij9ihM-b1BRU9Qfby0QDdqI,2957
|
|
313
313
|
atomicshop/wrappers/winregw/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
314
314
|
atomicshop/wrappers/winregw/winreg_network.py,sha256=bQ8Jql8bVGBJ0dt3VQ56lga_1LBOMLI3Km_otvvbU6c,7138
|
|
315
|
-
atomicshop-2.16.
|
|
316
|
-
atomicshop-2.16.
|
|
317
|
-
atomicshop-2.16.
|
|
318
|
-
atomicshop-2.16.
|
|
319
|
-
atomicshop-2.16.
|
|
315
|
+
atomicshop-2.16.37.dist-info/LICENSE.txt,sha256=lLU7EYycfYcK2NR_1gfnhnRC8b8ccOTElACYplgZN88,1094
|
|
316
|
+
atomicshop-2.16.37.dist-info/METADATA,sha256=ZuxU8sOc4ZRnmt_V-mWPB5p-Itv8PYnSrWGloBL_dTU,10473
|
|
317
|
+
atomicshop-2.16.37.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
|
318
|
+
atomicshop-2.16.37.dist-info/top_level.txt,sha256=EgKJB-7xcrAPeqTRF2laD_Np2gNGYkJkd4OyXqpJphA,11
|
|
319
|
+
atomicshop-2.16.37.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|