atomicshop 3.3.0__py3-none-any.whl → 3.3.2__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/argparse_template.py +2 -0
- atomicshop/certificates.py +9 -2
- atomicshop/filesystem.py +5 -1
- atomicshop/mitm/import_config.py +4 -1
- atomicshop/mitm/initialize_engines.py +8 -2
- atomicshop/mitm/mitm_main.py +84 -55
- atomicshop/wrappers/certauthw/certauth.py +1 -0
- atomicshop/wrappers/cryptographyw.py +24 -5
- atomicshop/wrappers/playwrightw/engine.py +2 -2
- atomicshop/wrappers/pyopensslw.py +9 -2
- atomicshop/wrappers/socketw/dns_server.py +15 -7
- atomicshop/wrappers/socketw/sni.py +13 -9
- atomicshop/wrappers/socketw/socket_wrapper.py +23 -37
- {atomicshop-3.3.0.dist-info → atomicshop-3.3.2.dist-info}/METADATA +7 -28
- {atomicshop-3.3.0.dist-info → atomicshop-3.3.2.dist-info}/RECORD +20 -20
- {atomicshop-3.3.0.dist-info → atomicshop-3.3.2.dist-info}/WHEEL +1 -1
- {atomicshop-3.3.0.dist-info → atomicshop-3.3.2.dist-info}/entry_points.txt +0 -0
- {atomicshop-3.3.0.dist-info → atomicshop-3.3.2.dist-info/licenses}/LICENSE.txt +0 -0
- {atomicshop-3.3.0.dist-info → atomicshop-3.3.2.dist-info}/top_level.txt +0 -0
atomicshop/__init__.py
CHANGED
|
@@ -36,6 +36,8 @@ class ArgparseWrapper:
|
|
|
36
36
|
# formatter_class=RawTextHelpFormatter: shows raw text and not the default argparse text parsing.
|
|
37
37
|
self.parser = argparse.ArgumentParser(description=self.description_full,
|
|
38
38
|
usage=self.usage_variable,
|
|
39
|
+
# usage=argparse.SUPPRESS # Remove usage line from the beginning.
|
|
40
|
+
# add_help=False, # Remove help line from the end.
|
|
39
41
|
formatter_class=RawTextHelpFormatter)
|
|
40
42
|
|
|
41
43
|
def add_arguments(self) -> None:
|
atomicshop/certificates.py
CHANGED
|
@@ -68,7 +68,8 @@ def is_certificate_in_store(
|
|
|
68
68
|
by_cert_issuer: bool = True,
|
|
69
69
|
by_cert_thumbprint: bool = True,
|
|
70
70
|
issuer_name: str = None,
|
|
71
|
-
store_location: str = "ROOT"
|
|
71
|
+
store_location: str = "ROOT",
|
|
72
|
+
print_kwargs: dict = None
|
|
72
73
|
) -> tuple[bool, list]:
|
|
73
74
|
"""
|
|
74
75
|
The function will check if the CA certificate is installed in the Windows certificate Trusted Root store.
|
|
@@ -89,6 +90,7 @@ def is_certificate_in_store(
|
|
|
89
90
|
certificates with the same issuer name.
|
|
90
91
|
:param issuer_name: string, issuer name to search for. You can search by certificate or by issuer name.
|
|
91
92
|
:param store_location: string, store location to search in. Default is "ROOT".
|
|
93
|
+
:param print_kwargs: dict, print_api kwargs.
|
|
92
94
|
:return: tuple(bool - True if certificate is installed and False if not, list of certificates found)
|
|
93
95
|
"""
|
|
94
96
|
|
|
@@ -102,7 +104,7 @@ def is_certificate_in_store(
|
|
|
102
104
|
|
|
103
105
|
if certificate:
|
|
104
106
|
# Make sure the certificate is x509.Certificate object.
|
|
105
|
-
certificate_x509 = cryptographyw.convert_object_to_x509(certificate)
|
|
107
|
+
certificate_x509 = cryptographyw.convert_object_to_x509(certificate, print_kwargs=print_kwargs)
|
|
106
108
|
# Get the certificate thumbprint.
|
|
107
109
|
provided_thumbprint = cryptographyw.get_sha1_thumbprint_from_x509(certificate_x509)
|
|
108
110
|
provided_issuer_common_name: str = cryptographyw.get_issuer_common_name_from_x509(certificate_x509)
|
|
@@ -117,7 +119,12 @@ def is_certificate_in_store(
|
|
|
117
119
|
result_found_list: list = []
|
|
118
120
|
found: bool = False
|
|
119
121
|
for cert, encoding, trust in ssl.enum_certificates(store_location):
|
|
122
|
+
# Some certificates in the store can have zero or negative serial number.
|
|
123
|
+
# We will skip them, since they're deprecated by the cryptography library.
|
|
120
124
|
store_certificate = cryptographyw.convert_object_to_x509(cert)
|
|
125
|
+
if not store_certificate:
|
|
126
|
+
continue
|
|
127
|
+
|
|
121
128
|
store_issuer_common_name: str = cryptographyw.get_issuer_common_name_from_x509(store_certificate)
|
|
122
129
|
store_thumbprint = cryptographyw.get_sha1_thumbprint_from_x509(store_certificate)
|
|
123
130
|
|
atomicshop/filesystem.py
CHANGED
|
@@ -288,7 +288,11 @@ def remove_file(file_path: str, **kwargs) -> bool:
|
|
|
288
288
|
return False
|
|
289
289
|
|
|
290
290
|
|
|
291
|
-
def remove_directory(
|
|
291
|
+
def remove_directory(
|
|
292
|
+
directory_path: str,
|
|
293
|
+
force_readonly: bool = False,
|
|
294
|
+
print_kwargs: dict = None
|
|
295
|
+
) -> bool:
|
|
292
296
|
"""
|
|
293
297
|
Remove directory if it exists.
|
|
294
298
|
|
atomicshop/mitm/import_config.py
CHANGED
|
@@ -93,7 +93,10 @@ def import_engines_configs(print_kwargs: dict) -> int:
|
|
|
93
93
|
for engine_config_path in engine_config_path_list:
|
|
94
94
|
# Initialize engine.
|
|
95
95
|
current_module: initialize_engines.ModuleCategory = initialize_engines.ModuleCategory(config_static.MainConfig.SCRIPT_DIRECTORY)
|
|
96
|
-
current_module.fill_engine_fields_from_config(engine_config_path.path, print_kwargs=print_kwargs or {})
|
|
96
|
+
result_code, error = current_module.fill_engine_fields_from_config(engine_config_path.path, print_kwargs=print_kwargs or {})
|
|
97
|
+
if result_code != 0:
|
|
98
|
+
print_api(f"Error reading engine config file: {engine_config_path.path}\n{error}", color='red')
|
|
99
|
+
return result_code
|
|
97
100
|
result_code, error = current_module.initialize_engine(print_kwargs=print_kwargs or {})
|
|
98
101
|
if result_code != 0:
|
|
99
102
|
print_api(f"Error initializing engine from directory: {Path(engine_config_path.path).parent}\n{error}", color='red')
|
|
@@ -45,7 +45,7 @@ class ModuleCategory:
|
|
|
45
45
|
self,
|
|
46
46
|
engine_config_file_path: str,
|
|
47
47
|
print_kwargs: dict = None
|
|
48
|
-
):
|
|
48
|
+
) -> tuple[int, str]:
|
|
49
49
|
# Read the configuration file of the engine.
|
|
50
50
|
configuration_data = tomls.read_toml_file(engine_config_file_path, **(print_kwargs or {}))
|
|
51
51
|
|
|
@@ -82,7 +82,11 @@ class ModuleCategory:
|
|
|
82
82
|
|
|
83
83
|
for domain_index, domain_port_string in enumerate(self.domain_list):
|
|
84
84
|
# Splitting the domain and port
|
|
85
|
-
|
|
85
|
+
if ':' in domain_port_string:
|
|
86
|
+
domain, port = domain_port_string.split(':')
|
|
87
|
+
else:
|
|
88
|
+
error_string: str = f"No [domain:port] pair found in: {domain_port_string}"
|
|
89
|
+
return 1, error_string
|
|
86
90
|
|
|
87
91
|
self.domain_target_dict[domain] = {'ip': None, 'port': port}
|
|
88
92
|
|
|
@@ -96,6 +100,8 @@ class ModuleCategory:
|
|
|
96
100
|
for subdomain, file_name in self.mtls.items():
|
|
97
101
|
self.mtls[subdomain] = f'{engine_directory_path}{os.sep}{file_name}'
|
|
98
102
|
|
|
103
|
+
return 0, ''
|
|
104
|
+
|
|
99
105
|
def initialize_engine(
|
|
100
106
|
self,
|
|
101
107
|
reference_general: bool = False,
|
atomicshop/mitm/mitm_main.py
CHANGED
|
@@ -320,7 +320,7 @@ def mitm_server(config_file_path: str, script_version: str):
|
|
|
320
320
|
return 1
|
|
321
321
|
|
|
322
322
|
# Import the configuration file.
|
|
323
|
-
result = config_static.load_config(config_file_path)
|
|
323
|
+
result = config_static.load_config(config_file_path, print_kwargs=dict(stdout=False))
|
|
324
324
|
if result != 0:
|
|
325
325
|
return result
|
|
326
326
|
|
|
@@ -392,49 +392,22 @@ def mitm_server(config_file_path: str, script_version: str):
|
|
|
392
392
|
# Logging Startup information.
|
|
393
393
|
startup_output(system_logger, script_version)
|
|
394
394
|
|
|
395
|
-
print_api.print_api("Press [Ctrl]+[C] to stop.", color='blue')
|
|
396
|
-
|
|
397
395
|
multiprocess_list: list[multiprocessing.Process] = list()
|
|
398
396
|
# noinspection PyTypeHints
|
|
399
397
|
is_ready_multiprocessing_event_list: list[multiprocessing.Event] = list()
|
|
400
398
|
|
|
401
|
-
# === Initialize DNS module ====================================================================================
|
|
402
|
-
if config_static.DNSServer.enable:
|
|
403
|
-
is_dns_process_ready: multiprocessing.Event = multiprocessing.Event()
|
|
404
|
-
is_ready_multiprocessing_event_list.append(is_dns_process_ready)
|
|
405
|
-
|
|
406
|
-
dns_server_kwargs: dict = dict(
|
|
407
|
-
listening_address=config_static.DNSServer.listening_address,
|
|
408
|
-
log_directory_path=config_static.LogRec.logs_path,
|
|
409
|
-
backupCount_log_files_x_days=config_static.LogRec.store_logs_for_x_days,
|
|
410
|
-
forwarding_dns_service_ipv4=config_static.DNSServer.forwarding_dns_service_ipv4,
|
|
411
|
-
forwarding_dns_service_port=config_static.DNSServer.forwarding_dns_service_port,
|
|
412
|
-
resolve_by_engine=(
|
|
413
|
-
config_static.DNSServer.resolve_by_engine, config_static.ENGINES_LIST),
|
|
414
|
-
resolve_regular_pass_thru=config_static.DNSServer.resolve_regular_pass_thru,
|
|
415
|
-
resolve_all_domains_to_ipv4=(
|
|
416
|
-
config_static.DNSServer.resolve_all_domains_to_ipv4_enable, config_static.DNSServer.target_ipv4),
|
|
417
|
-
offline_mode=config_static.MainConfig.offline,
|
|
418
|
-
cache_timeout_minutes=config_static.DNSServer.cache_timeout_minutes,
|
|
419
|
-
logging_queue=NETWORK_LOGGER_QUEUE,
|
|
420
|
-
logger_name=network_logger_name,
|
|
421
|
-
is_ready_multiprocessing=is_dns_process_ready
|
|
422
|
-
)
|
|
423
|
-
|
|
424
|
-
dns_process = multiprocessing.Process(
|
|
425
|
-
target=dns_server.start_dns_server_multiprocessing_worker,
|
|
426
|
-
kwargs=dns_server_kwargs,
|
|
427
|
-
name="dns_server",
|
|
428
|
-
daemon=True
|
|
429
|
-
)
|
|
430
|
-
dns_process.start()
|
|
431
|
-
|
|
432
|
-
multiprocess_list.append(dns_process)
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
# === EOF Initialize DNS module ================================================================================
|
|
436
399
|
# === Initialize TCP Server ====================================================================================
|
|
437
400
|
if config_static.TCPServer.enable:
|
|
401
|
+
# Get the default network adapter configuration and set the one from config.
|
|
402
|
+
# We set the virtual IPs in the network adapter here, so the server multiprocessing processes can listen on them.
|
|
403
|
+
setting_result: int = _add_virtual_ips_set_default_dns_gateway(system_logger)
|
|
404
|
+
if setting_result != 0:
|
|
405
|
+
print_api.print_api("Failed to set the default DNS gateway.", error_type=True, color="red",
|
|
406
|
+
logger=system_logger)
|
|
407
|
+
# Wait for the message to be printed and saved to file.
|
|
408
|
+
time.sleep(1)
|
|
409
|
+
return setting_result
|
|
410
|
+
|
|
438
411
|
# Start statistics CSV Queue listener and the logger.
|
|
439
412
|
_ = statistics_csv.StatisticsCSVWriter(
|
|
440
413
|
directory_path=config_static.LogRec.logs_path,
|
|
@@ -515,9 +488,11 @@ def mitm_server(config_file_path: str, script_version: str):
|
|
|
515
488
|
exceptions_logger_name=EXCEPTIONS_CSV_LOGGER_NAME,
|
|
516
489
|
exceptions_logger_queue=EXCEPTIONS_CSV_LOGGER_QUEUE,
|
|
517
490
|
forwarding_dns_service_ipv4_list___only_for_localhost=[config_static.DNSServer.forwarding_dns_service_ipv4],
|
|
518
|
-
skip_extension_id_list=config_static.SkipExtensions.SKIP_EXTENSION_ID_LIST
|
|
491
|
+
skip_extension_id_list=config_static.SkipExtensions.SKIP_EXTENSION_ID_LIST,
|
|
492
|
+
print_kwargs=dict(stdout=False)
|
|
519
493
|
)
|
|
520
494
|
|
|
495
|
+
# noinspection PyTypeHints
|
|
521
496
|
is_tcp_process_ready: multiprocessing.Event = multiprocessing.Event()
|
|
522
497
|
is_ready_multiprocessing_event_list.append(is_tcp_process_ready)
|
|
523
498
|
|
|
@@ -541,25 +516,52 @@ def mitm_server(config_file_path: str, script_version: str):
|
|
|
541
516
|
recs_archiver_thread.start()
|
|
542
517
|
|
|
543
518
|
# Check that all the multiprocesses are ready.
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
logger=system_logger)
|
|
548
|
-
# Wait for the message to be printed and saved to file.
|
|
549
|
-
time.sleep(1)
|
|
550
|
-
return 1
|
|
519
|
+
if not _wait_for_events(is_ready_multiprocessing_event_list, timeout=30, system_logger=system_logger):
|
|
520
|
+
return 1
|
|
521
|
+
# === EOF Initialize TCP Server ====================================================================================
|
|
551
522
|
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
523
|
+
# === Initialize DNS module ========================================================================================
|
|
524
|
+
if config_static.DNSServer.enable:
|
|
525
|
+
# noinspection PyTypeHints
|
|
526
|
+
is_dns_process_ready: multiprocessing.Event = multiprocessing.Event()
|
|
527
|
+
|
|
528
|
+
dns_server_kwargs: dict = dict(
|
|
529
|
+
listening_address=config_static.DNSServer.listening_address,
|
|
530
|
+
log_directory_path=config_static.LogRec.logs_path,
|
|
531
|
+
backupCount_log_files_x_days=config_static.LogRec.store_logs_for_x_days,
|
|
532
|
+
forwarding_dns_service_ipv4=config_static.DNSServer.forwarding_dns_service_ipv4,
|
|
533
|
+
forwarding_dns_service_port=config_static.DNSServer.forwarding_dns_service_port,
|
|
534
|
+
resolve_by_engine=(
|
|
535
|
+
config_static.DNSServer.resolve_by_engine, config_static.ENGINES_LIST),
|
|
536
|
+
resolve_regular_pass_thru=config_static.DNSServer.resolve_regular_pass_thru,
|
|
537
|
+
resolve_all_domains_to_ipv4=(
|
|
538
|
+
config_static.DNSServer.resolve_all_domains_to_ipv4_enable, config_static.DNSServer.target_ipv4),
|
|
539
|
+
offline_mode=config_static.MainConfig.offline,
|
|
540
|
+
cache_timeout_minutes=config_static.DNSServer.cache_timeout_minutes,
|
|
541
|
+
logging_queue=NETWORK_LOGGER_QUEUE,
|
|
542
|
+
logger_name=network_logger_name,
|
|
543
|
+
is_ready_multiprocessing=is_dns_process_ready
|
|
544
|
+
)
|
|
545
|
+
|
|
546
|
+
dns_process = multiprocessing.Process(
|
|
547
|
+
target=dns_server.start_dns_server_multiprocessing_worker,
|
|
548
|
+
kwargs=dns_server_kwargs,
|
|
549
|
+
name="dns_server",
|
|
550
|
+
daemon=True
|
|
551
|
+
)
|
|
552
|
+
dns_process.start()
|
|
553
|
+
|
|
554
|
+
multiprocess_list.append(dns_process)
|
|
555
|
+
|
|
556
|
+
# Check that the multiprocess is ready.
|
|
557
|
+
if not _wait_for_events([is_dns_process_ready], timeout=30, system_logger=system_logger):
|
|
558
|
+
return 1
|
|
559
|
+
# === EOF Initialize DNS module ====================================================================================
|
|
560
560
|
|
|
561
561
|
if config_static.DNSServer.enable or config_static.TCPServer.enable:
|
|
562
562
|
print_api.print_api("The Server is Ready for Operation!", color="green", logger=system_logger)
|
|
563
|
+
print_api.print_api("Press [Ctrl]+[C] to stop.", color='blue', logger=system_logger)
|
|
564
|
+
|
|
563
565
|
# Get al the queue listener processes (basically this is not necessary, since they're 'daemons', but this is a good practice).
|
|
564
566
|
multiprocess_list.extend(loggingw.get_listener_processes())
|
|
565
567
|
|
|
@@ -577,6 +579,7 @@ def mitm_server(config_file_path: str, script_version: str):
|
|
|
577
579
|
time.sleep(1)
|
|
578
580
|
|
|
579
581
|
|
|
582
|
+
# noinspection PyTypeHints
|
|
580
583
|
def _create_tcp_server_process(
|
|
581
584
|
socket_wrapper_kwargs: dict,
|
|
582
585
|
config_file_path: str,
|
|
@@ -628,7 +631,33 @@ def _create_tcp_server_process(
|
|
|
628
631
|
sys.exit(0)
|
|
629
632
|
|
|
630
633
|
|
|
631
|
-
|
|
634
|
+
# noinspection PyTypeHints
|
|
635
|
+
def _wait_for_events(
|
|
636
|
+
events: list[multiprocessing.Event],
|
|
637
|
+
timeout: int = 30,
|
|
638
|
+
system_logger: logging.Logger = None
|
|
639
|
+
) -> bool:
|
|
640
|
+
"""
|
|
641
|
+
Wait for all events in the list to be set.
|
|
642
|
+
|
|
643
|
+
:param events: List of multiprocessing.Event objects.
|
|
644
|
+
:param timeout: Maximum time to wait for all events to be set.
|
|
645
|
+
:return: True if all events are set, False if timeout occurs.
|
|
646
|
+
"""
|
|
647
|
+
|
|
648
|
+
# Check that all the multiprocesses are ready.
|
|
649
|
+
for event in events:
|
|
650
|
+
if not event.wait(timeout=timeout):
|
|
651
|
+
print_api.print_api("One of the processes didn't start in time.", error_type=True, color="red",
|
|
652
|
+
logger=system_logger)
|
|
653
|
+
# Wait for the message to be printed and saved to file.
|
|
654
|
+
time.sleep(1)
|
|
655
|
+
return False
|
|
656
|
+
|
|
657
|
+
return True
|
|
658
|
+
|
|
659
|
+
|
|
660
|
+
def _add_virtual_ips_set_default_dns_gateway(system_logger: logging.Logger) -> int:
|
|
632
661
|
"""
|
|
633
662
|
The function reads the current DNS gateway setting and sets the new one.
|
|
634
663
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from typing import Union
|
|
2
2
|
import os
|
|
3
|
+
import warnings
|
|
3
4
|
|
|
4
5
|
from ..print_api import print_api
|
|
5
6
|
from ..file_io import file_io
|
|
@@ -9,6 +10,7 @@ from cryptography.x509 import Certificate
|
|
|
9
10
|
from cryptography.hazmat.primitives.asymmetric import rsa
|
|
10
11
|
from cryptography.hazmat.primitives import serialization
|
|
11
12
|
from cryptography.hazmat.primitives import hashes
|
|
13
|
+
from cryptography.utils import CryptographyDeprecationWarning
|
|
12
14
|
|
|
13
15
|
|
|
14
16
|
"""
|
|
@@ -22,7 +24,10 @@ OID_TO_BUILDER_CLASS_EXTENSION_NAME: dict = {
|
|
|
22
24
|
}
|
|
23
25
|
|
|
24
26
|
|
|
25
|
-
def convert_object_to_x509(
|
|
27
|
+
def convert_object_to_x509(
|
|
28
|
+
certificate: Union[str, bytes, Certificate],
|
|
29
|
+
print_kwargs: dict = None
|
|
30
|
+
) -> x509.Certificate | None:
|
|
26
31
|
"""Convert certificate to x509 object.
|
|
27
32
|
|
|
28
33
|
:param certificate: any object that can be converted to x509 object.
|
|
@@ -32,7 +37,8 @@ def convert_object_to_x509(certificate):
|
|
|
32
37
|
string that is PEM certificate will be converted to bytes, then x509.Certificate
|
|
33
38
|
bytes of PEM or DER will be converted to x509.Certificate.
|
|
34
39
|
x509.Certificate will be returned as is.
|
|
35
|
-
:
|
|
40
|
+
:param print_kwargs: dict, additional arguments to pass to the print function.
|
|
41
|
+
:return: certificate in x509 object of 'cryptography' module. Or None if the certificate is not valid.
|
|
36
42
|
"""
|
|
37
43
|
|
|
38
44
|
# Check if 'certificate' is a string and a path.
|
|
@@ -40,7 +46,7 @@ def convert_object_to_x509(certificate):
|
|
|
40
46
|
if not os.path.isfile(certificate):
|
|
41
47
|
raise FileNotFoundError(f'File not found: {certificate}')
|
|
42
48
|
# Import the certificate from the path.
|
|
43
|
-
certificate = file_io.read_file(certificate, file_mode='rb')
|
|
49
|
+
certificate = file_io.read_file(certificate, file_mode='rb', **(print_kwargs or {}))
|
|
44
50
|
|
|
45
51
|
# Check if 'certificate' is a bytes object and PEM format.
|
|
46
52
|
# We're checking if it starts with '-----BEGIN ' since the pem certificate can include PRIVATE KEY and will be
|
|
@@ -82,14 +88,27 @@ def convert_pem_to_x509_object(certificate: Union[str, bytes]) -> x509.Certifica
|
|
|
82
88
|
return x509.load_pem_x509_certificate(certificate)
|
|
83
89
|
|
|
84
90
|
|
|
85
|
-
def convert_der_to_x509_object(certificate: bytes) -> x509.Certificate:
|
|
91
|
+
def convert_der_to_x509_object(certificate: bytes) -> x509.Certificate | None:
|
|
86
92
|
"""Convert DER certificate from socket to x509 object.
|
|
87
93
|
|
|
88
94
|
:param certificate: bytes, certificate to convert.
|
|
89
95
|
:return: certificate in x509 object of 'cryptography' module.
|
|
90
96
|
"""
|
|
91
97
|
|
|
92
|
-
|
|
98
|
+
# Some certificates in the store can have zero or negative serial number.
|
|
99
|
+
# We will skip them, since they're deprecated by the cryptography library.
|
|
100
|
+
|
|
101
|
+
try:
|
|
102
|
+
with warnings.catch_warnings():
|
|
103
|
+
# Turn the deprecation warning into an exception we can trap.
|
|
104
|
+
warnings.filterwarnings("error", category=CryptographyDeprecationWarning)
|
|
105
|
+
converted_certificate = x509.load_der_x509_certificate(certificate)
|
|
106
|
+
except (CryptographyDeprecationWarning, ValueError):
|
|
107
|
+
return None # serial was 0/negative → skip
|
|
108
|
+
if converted_certificate.serial_number <= 0: # belt-and-braces
|
|
109
|
+
return None
|
|
110
|
+
|
|
111
|
+
return converted_certificate
|
|
93
112
|
|
|
94
113
|
|
|
95
114
|
def convert_x509_object_to_pem_bytes(certificate) -> bytes:
|
|
@@ -8,7 +8,7 @@ from tempfile import gettempdir
|
|
|
8
8
|
# noinspection PyPackageRequirements
|
|
9
9
|
from playwright.sync_api import sync_playwright, Error
|
|
10
10
|
# Stealth options for playwright. External.
|
|
11
|
-
from playwright_stealth import stealth_sync
|
|
11
|
+
# from playwright_stealth import stealth_sync
|
|
12
12
|
|
|
13
13
|
from ...keyboard_press import send_alt_tab
|
|
14
14
|
from ... import filesystem, print_api
|
|
@@ -150,7 +150,7 @@ class PlaywrightEngine:
|
|
|
150
150
|
self.page = self.browser.new_page()
|
|
151
151
|
|
|
152
152
|
# Making playwright stealthier with less footprint of automation.
|
|
153
|
-
stealth_sync(self.page)
|
|
153
|
+
# stealth_sync(self.page)
|
|
154
154
|
|
|
155
155
|
def close_browser(self) -> None:
|
|
156
156
|
self.page.close()
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
from secrets import randbits
|
|
2
2
|
from OpenSSL import crypto
|
|
3
3
|
|
|
4
4
|
from .. import certificates
|
|
@@ -121,7 +121,14 @@ def generate_server_certificate_empty(
|
|
|
121
121
|
"""
|
|
122
122
|
|
|
123
123
|
cert = crypto.X509()
|
|
124
|
-
|
|
124
|
+
|
|
125
|
+
# RFC 5280: serial must be positive and non-zero
|
|
126
|
+
# 1 … 2⁶⁴-1
|
|
127
|
+
cert.set_serial_number(randbits(64))
|
|
128
|
+
current_serial = cert.get_serial_number()
|
|
129
|
+
if current_serial <= 0:
|
|
130
|
+
raise RuntimeError(f"Refusing to create a certificate with non-positive serial: {str(current_serial)}")
|
|
131
|
+
|
|
125
132
|
cert.get_subject().CN = certname
|
|
126
133
|
|
|
127
134
|
cert.set_version(2)
|
|
@@ -393,29 +393,37 @@ class DnsServer:
|
|
|
393
393
|
is_ready_multiprocessing.set()
|
|
394
394
|
|
|
395
395
|
while True:
|
|
396
|
+
forward_to_tcp_server = False # reset every request
|
|
397
|
+
|
|
396
398
|
# Needed this logging line when DNS was separate process.
|
|
397
399
|
# self.logger.info("Waiting to receive new requests...")
|
|
398
400
|
|
|
399
|
-
# noinspection PyBroadException
|
|
400
401
|
try:
|
|
401
402
|
client_data, client_address = main_socket_object.recvfrom(self.buffer_size_receive)
|
|
402
403
|
client_data: bytes
|
|
403
404
|
client_address: tuple
|
|
404
405
|
except ConnectionResetError:
|
|
406
|
+
client_address = (str(), int())
|
|
405
407
|
traceback_string = tracebacks.get_as_string(one_line=True)
|
|
406
408
|
# This error happens when the client closes the connection before the server.
|
|
407
409
|
# This is not an error for a DNS Server, but we'll log it anyway only with the full DNS logger.
|
|
408
410
|
message = (f"Error: to receive DNS request, An existing connection was forcibly closed | "
|
|
409
411
|
f"{traceback_string}")
|
|
412
|
+
# print_api(message, logger=self.logger, logger_method='critical', traceback_string=True)
|
|
410
413
|
self.dns_statistics_csv_writer.write_error(
|
|
411
414
|
dns_type='request', client_address=client_address, error_message=message)
|
|
412
|
-
pass
|
|
413
415
|
continue
|
|
414
|
-
except
|
|
415
|
-
message = "
|
|
416
|
-
print_api(
|
|
417
|
-
|
|
418
|
-
|
|
416
|
+
except KeyboardInterrupt:
|
|
417
|
+
# message = "KeyboardInterrupt: Stopping DNS Server..."
|
|
418
|
+
# print_api(message, logger=self.logger, logger_method='info')
|
|
419
|
+
# self.logger.info(message)
|
|
420
|
+
# Stop the server
|
|
421
|
+
break
|
|
422
|
+
except Exception as e:
|
|
423
|
+
message = f"Unknown Exception to receive DNS request: {str(e)}"
|
|
424
|
+
print_api(message, logger=self.logger, logger_method='critical', traceback_string=True)
|
|
425
|
+
self.dns_statistics_csv_writer.write_error(
|
|
426
|
+
dns_type='request', client_address=client_address, error_message=message)
|
|
419
427
|
continue
|
|
420
428
|
|
|
421
429
|
# noinspection PyBroadException
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import ssl
|
|
2
2
|
from dataclasses import dataclass
|
|
3
|
+
from typing import Callable, Any
|
|
3
4
|
|
|
4
5
|
from ..loggingw import loggingw
|
|
5
6
|
from ...domains import get_domain_without_first_subdomain_if_no_subdomain_return_as_is
|
|
@@ -31,7 +32,7 @@ class SNISetup:
|
|
|
31
32
|
default_server_certificate_name: str,
|
|
32
33
|
default_server_certificate_directory: str,
|
|
33
34
|
default_certificate_domain_list: list,
|
|
34
|
-
sni_custom_callback_function:
|
|
35
|
+
sni_custom_callback_function: Callable[..., Any],
|
|
35
36
|
sni_use_default_callback_function: bool,
|
|
36
37
|
sni_use_default_callback_function_extended: bool,
|
|
37
38
|
sni_add_new_domains_to_default_server_certificate: bool,
|
|
@@ -54,7 +55,7 @@ class SNISetup:
|
|
|
54
55
|
self.default_server_certificate_name = default_server_certificate_name
|
|
55
56
|
self.default_server_certificate_directory = default_server_certificate_directory
|
|
56
57
|
self.default_certificate_domain_list = default_certificate_domain_list
|
|
57
|
-
self.sni_custom_callback_function:
|
|
58
|
+
self.sni_custom_callback_function: Callable[..., Any] = sni_custom_callback_function
|
|
58
59
|
self.sni_use_default_callback_function: bool = sni_use_default_callback_function
|
|
59
60
|
self.sni_use_default_callback_function_extended: bool = sni_use_default_callback_function_extended
|
|
60
61
|
self.sni_add_new_domains_to_default_server_certificate = sni_add_new_domains_to_default_server_certificate
|
|
@@ -259,20 +260,23 @@ class SNIHandler:
|
|
|
259
260
|
# If DNS server is enabled we'll get the domain from dns server.
|
|
260
261
|
if self.domain_from_dns_server:
|
|
261
262
|
self.sni_received_parameters.destination_name = self.domain_from_dns_server
|
|
262
|
-
message =
|
|
263
|
-
f"SNI
|
|
263
|
+
message = (
|
|
264
|
+
f"SNI Passed: False\n"
|
|
265
|
+
f"SNI Handler: No SNI was passed, using domain from DNS Server: {self.domain_from_dns_server}")
|
|
264
266
|
print_api(message, color="yellow", **(print_kwargs or {}))
|
|
265
267
|
# If DNS server is disabled, the domain from dns server will be empty.
|
|
266
268
|
else:
|
|
267
|
-
message =
|
|
268
|
-
|
|
269
|
+
message = (
|
|
270
|
+
f"SNI Passed: False\n"
|
|
271
|
+
f"SNI Handler: No SNI was passed, No domain passed from DNS Server. Service name will be 'None'.")
|
|
269
272
|
print_api(message, color="yellow", **(print_kwargs or {}))
|
|
270
273
|
|
|
271
274
|
# Setting "server_hostname" as a domain.
|
|
272
275
|
self.sni_received_parameters.ssl_socket.server_hostname = self.sni_received_parameters.destination_name
|
|
273
|
-
message =
|
|
274
|
-
f"SNI
|
|
275
|
-
f"
|
|
276
|
+
message = (
|
|
277
|
+
f"SNI Passed: True\n"
|
|
278
|
+
f"SNI Handler: port {self.sni_received_parameters.ssl_socket.getsockname()[1]}: "
|
|
279
|
+
f"Incoming connection for [{self.sni_received_parameters.ssl_socket.server_hostname}]")
|
|
276
280
|
print_api(message, **(print_kwargs or {}))
|
|
277
281
|
except Exception as exception_object:
|
|
278
282
|
message = f"SNI Handler: Undocumented exception general settings section: {exception_object}"
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import multiprocessing
|
|
2
2
|
import threading
|
|
3
3
|
import select
|
|
4
|
-
from typing import Literal, Union
|
|
4
|
+
from typing import Literal, Union, Callable, Any
|
|
5
5
|
from pathlib import Path
|
|
6
6
|
import socket
|
|
7
|
+
import shutil
|
|
8
|
+
import os
|
|
7
9
|
|
|
8
10
|
from ...mitm import initialize_engines
|
|
9
11
|
from ..psutilw import psutil_networks
|
|
@@ -47,7 +49,7 @@ class SocketWrapper:
|
|
|
47
49
|
default_server_certificate_name: str = None,
|
|
48
50
|
default_certificate_domain_list: list = None,
|
|
49
51
|
default_server_certificate_directory: str = None,
|
|
50
|
-
sni_custom_callback_function:
|
|
52
|
+
sni_custom_callback_function: Callable[..., Any] = None,
|
|
51
53
|
sni_use_default_callback_function: bool = False,
|
|
52
54
|
sni_use_default_callback_function_extended: bool = False,
|
|
53
55
|
sni_add_new_domains_to_default_server_certificate: bool = False,
|
|
@@ -76,9 +78,7 @@ class SocketWrapper:
|
|
|
76
78
|
statistics_logger_queue: multiprocessing.Queue = None,
|
|
77
79
|
exceptions_logger_name: str = 'SocketWrapperExceptions',
|
|
78
80
|
exceptions_logger_queue: multiprocessing.Queue = None,
|
|
79
|
-
|
|
80
|
-
no_engines_listening_address_list: list[str] = None,
|
|
81
|
-
engines_list: list[initialize_engines.ModuleCategory] = None
|
|
81
|
+
print_kwargs: dict = None,
|
|
82
82
|
):
|
|
83
83
|
"""
|
|
84
84
|
Socket Wrapper class that will be used to create sockets, listen on them, accept connections and send them to
|
|
@@ -171,22 +171,7 @@ class SocketWrapper:
|
|
|
171
171
|
:param exceptions_logger_name: string, name of the logger that will be used to log exceptions.
|
|
172
172
|
:param exceptions_logger_queue: multiprocessing.Queue, queue that will be used to log exceptions in
|
|
173
173
|
multiprocessing. You need to start the logger listener in the main process to handle the queue.
|
|
174
|
-
:param
|
|
175
|
-
but the "no_engines_listening_address_list" parameter will be used instead.
|
|
176
|
-
:param no_engines_listening_address_list: list, of ips+ports that will be listened on.
|
|
177
|
-
Example: ['0.0.0.0:443', '0.0.0.0:80']
|
|
178
|
-
:param engines_list: list, of engines that will be used to process the requests. Structure of engine_config.toml:
|
|
179
|
-
[engine]
|
|
180
|
-
"domains" = ["example.com"]
|
|
181
|
-
|
|
182
|
-
[mtls]
|
|
183
|
-
# "subdomain.domain.com" = "file_name_in_current_dir.pem"
|
|
184
|
-
|
|
185
|
-
[no_sni]
|
|
186
|
-
#get_from_dns = 1 # Blocking, the accept function will wait until the domain is received from DNS.
|
|
187
|
-
#get_from_engine = 0
|
|
188
|
-
#try_to_get_from_dns_on_empty_get_from_engine = 0 # Non-blocking, on empty DNS server queue, accept() will connect to the domain from below.
|
|
189
|
-
#"domain" = "example.com"
|
|
174
|
+
:param print_kwargs: dict, additional arguments to pass to the print function.
|
|
190
175
|
"""
|
|
191
176
|
|
|
192
177
|
self.ip_address: str = ip_address
|
|
@@ -202,7 +187,7 @@ class SocketWrapper:
|
|
|
202
187
|
self.default_server_certificate_name: str = default_server_certificate_name
|
|
203
188
|
self.default_certificate_domain_list: list = default_certificate_domain_list
|
|
204
189
|
self.default_server_certificate_directory: str = default_server_certificate_directory
|
|
205
|
-
self.sni_custom_callback_function:
|
|
190
|
+
self.sni_custom_callback_function: Callable[..., Any] = sni_custom_callback_function
|
|
206
191
|
self.sni_use_default_callback_function: bool = sni_use_default_callback_function
|
|
207
192
|
self.sni_use_default_callback_function_extended: bool = sni_use_default_callback_function_extended
|
|
208
193
|
self.sni_add_new_domains_to_default_server_certificate: bool = sni_add_new_domains_to_default_server_certificate
|
|
@@ -221,9 +206,7 @@ class SocketWrapper:
|
|
|
221
206
|
self.ssh_script_to_execute = ssh_script_to_execute
|
|
222
207
|
self.forwarding_dns_service_ipv4_list___only_for_localhost = (
|
|
223
208
|
forwarding_dns_service_ipv4_list___only_for_localhost)
|
|
224
|
-
|
|
225
|
-
# self.no_engines_listening_address_list: list[str] = no_engines_listening_address_list
|
|
226
|
-
# self.engines_list: list[initialize_engines.ModuleCategory] = engines_list
|
|
209
|
+
self.print_kwargs: dict = print_kwargs
|
|
227
210
|
|
|
228
211
|
self.socket_object = None
|
|
229
212
|
|
|
@@ -313,13 +296,6 @@ class SocketWrapper:
|
|
|
313
296
|
"You can't set both [sni_use_default_callback_function = True] and [sni_custom_callback_function]."
|
|
314
297
|
raise SocketWrapperConfigurationValuesError(message)
|
|
315
298
|
|
|
316
|
-
# if self.no_engine_usage_enable and not self.no_engines_listening_address_list:
|
|
317
|
-
# message = "You set [no_engine_usage_enable = True], but you didn't set [no_engines_listening_address_list]."
|
|
318
|
-
# raise SocketWrapperConfigurationValuesError(message)
|
|
319
|
-
# elif not self.no_engine_usage_enable and not self.engines_list:
|
|
320
|
-
# message = "You set [no_engine_usage_enable = False], but you didn't set [engines_list]."
|
|
321
|
-
# raise SocketWrapperConfigurationValuesError(message)
|
|
322
|
-
|
|
323
299
|
try:
|
|
324
300
|
booleans.is_only_1_true_in_list(
|
|
325
301
|
booleans_list_of_tuples=[
|
|
@@ -392,6 +368,13 @@ class SocketWrapper:
|
|
|
392
368
|
pem_file_path=self.ca_certificate_filepath,
|
|
393
369
|
crt_file_path=self.ca_certificate_crt_filepath)
|
|
394
370
|
|
|
371
|
+
# If someone removed the CA certificate file manually, and now it was created, we also need to
|
|
372
|
+
# clear the cached certificates.
|
|
373
|
+
shutil.rmtree(self.sni_server_certificates_cache_directory)
|
|
374
|
+
os.makedirs(self.sni_server_certificates_cache_directory, exist_ok=True)
|
|
375
|
+
print_api("Removed cached server certificates.", logger=self.logger)
|
|
376
|
+
|
|
377
|
+
|
|
395
378
|
if self.install_ca_certificate_to_root_store:
|
|
396
379
|
if not self.ca_certificate_filepath:
|
|
397
380
|
message = "You set [install_ca_certificate_to_root_store = True],\n" \
|
|
@@ -411,7 +394,8 @@ class SocketWrapper:
|
|
|
411
394
|
# If there is only one certificate with the same name, check if it is the same certificate.
|
|
412
395
|
elif is_installed_by_name and len(certificate_list_by_name) == 1:
|
|
413
396
|
is_installed_by_file, certificate_list_by_file = certificates.is_certificate_in_store(
|
|
414
|
-
certificate=self.ca_certificate_filepath, by_cert_thumbprint=True, by_cert_issuer=True
|
|
397
|
+
certificate=self.ca_certificate_filepath, by_cert_thumbprint=True, by_cert_issuer=True,
|
|
398
|
+
print_kwargs=self.print_kwargs)
|
|
415
399
|
# If the certificate is not the same, delete it.
|
|
416
400
|
if not is_installed_by_file:
|
|
417
401
|
if not permissions.is_admin():
|
|
@@ -427,7 +411,9 @@ class SocketWrapper:
|
|
|
427
411
|
if self.install_ca_certificate_to_root_store:
|
|
428
412
|
# Install CA certificate to the root store if it is not installed.
|
|
429
413
|
is_installed_by_file, certificate_list_by_file = certificates.is_certificate_in_store(
|
|
430
|
-
certificate=self.ca_certificate_filepath, by_cert_thumbprint=True, by_cert_issuer=True
|
|
414
|
+
certificate=self.ca_certificate_filepath, by_cert_thumbprint=True, by_cert_issuer=True,
|
|
415
|
+
print_kwargs=self.print_kwargs
|
|
416
|
+
)
|
|
431
417
|
if not is_installed_by_file:
|
|
432
418
|
if not permissions.is_admin():
|
|
433
419
|
raise SocketWrapperConfigurationValuesError(
|
|
@@ -448,7 +434,7 @@ class SocketWrapper:
|
|
|
448
434
|
|
|
449
435
|
def start_listening_socket(
|
|
450
436
|
self,
|
|
451
|
-
callable_function:
|
|
437
|
+
callable_function: Callable[..., Any],
|
|
452
438
|
callable_args: tuple = ()
|
|
453
439
|
):
|
|
454
440
|
"""
|
|
@@ -478,7 +464,7 @@ class SocketWrapper:
|
|
|
478
464
|
def listening_socket_loop(
|
|
479
465
|
self,
|
|
480
466
|
listening_socket_object: socket.socket,
|
|
481
|
-
callable_function:
|
|
467
|
+
callable_function: Callable[..., Any],
|
|
482
468
|
callable_args=()
|
|
483
469
|
):
|
|
484
470
|
"""
|
|
@@ -688,7 +674,7 @@ class SocketWrapper:
|
|
|
688
674
|
|
|
689
675
|
|
|
690
676
|
def before_socket_thread_worker(
|
|
691
|
-
callable_function:
|
|
677
|
+
callable_function: Callable[..., Any],
|
|
692
678
|
callable_args: tuple,
|
|
693
679
|
exceptions_logger: loggingw.ExceptionCsvLogger = None
|
|
694
680
|
):
|
|
@@ -1,32 +1,11 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: atomicshop
|
|
3
|
-
Version: 3.3.
|
|
3
|
+
Version: 3.3.2
|
|
4
4
|
Summary: Atomic functions and classes to make developer life easier
|
|
5
5
|
Author: Denis Kras
|
|
6
|
-
License: MIT
|
|
7
|
-
|
|
8
|
-
Copyright (c) 2023 Bugsec, Denis Kras
|
|
9
|
-
|
|
10
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
-
in the Software without restriction, including without limitation the rights
|
|
13
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
-
furnished to do so, subject to the following conditions:
|
|
16
|
-
|
|
17
|
-
The above copyright notice and this permission notice shall be included in all
|
|
18
|
-
copies or substantial portions of the Software.
|
|
19
|
-
|
|
20
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
-
SOFTWARE.
|
|
6
|
+
License-Expression: MIT
|
|
27
7
|
Project-URL: Homepage, https://github.com/BugSec-Official/atomicshop
|
|
28
8
|
Classifier: Intended Audience :: Developers
|
|
29
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
30
9
|
Classifier: Programming Language :: Python :: 3
|
|
31
10
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
32
11
|
Requires-Python: >=3.10
|
|
@@ -38,7 +17,7 @@ Requires-Dist: cryptography
|
|
|
38
17
|
Requires-Dist: dnslib
|
|
39
18
|
Requires-Dist: dnspython
|
|
40
19
|
Requires-Dist: docker
|
|
41
|
-
Requires-Dist:
|
|
20
|
+
Requires-Dist: flask_socketio
|
|
42
21
|
Requires-Dist: google-api-python-client
|
|
43
22
|
Requires-Dist: google-generativeai
|
|
44
23
|
Requires-Dist: icmplib
|
|
@@ -49,16 +28,16 @@ Requires-Dist: pandas
|
|
|
49
28
|
Requires-Dist: paramiko
|
|
50
29
|
Requires-Dist: pefile
|
|
51
30
|
Requires-Dist: playwright
|
|
52
|
-
Requires-Dist: playwright-stealth ==1.0.6
|
|
53
31
|
Requires-Dist: protobuf
|
|
54
32
|
Requires-Dist: psutil
|
|
55
|
-
Requires-Dist: py7zr
|
|
33
|
+
Requires-Dist: py7zr==0.22.0
|
|
56
34
|
Requires-Dist: pyautogui
|
|
57
35
|
Requires-Dist: pymongo
|
|
58
36
|
Requires-Dist: pyopenssl
|
|
59
37
|
Requires-Dist: python-bidi
|
|
60
38
|
Requires-Dist: python-docx
|
|
61
39
|
Requires-Dist: python-magic
|
|
40
|
+
Requires-Dist: pywin32; platform_system == "Windows"
|
|
62
41
|
Requires-Dist: reportlab
|
|
63
42
|
Requires-Dist: setuptools
|
|
64
43
|
Requires-Dist: SoundCard
|
|
@@ -66,7 +45,7 @@ Requires-Dist: soundfile
|
|
|
66
45
|
Requires-Dist: SpeechRecognition
|
|
67
46
|
Requires-Dist: tldextract
|
|
68
47
|
Requires-Dist: websockets
|
|
69
|
-
|
|
48
|
+
Dynamic: license-file
|
|
70
49
|
|
|
71
50
|
<h1 align="center">Atomic Workshop</h1>
|
|
72
51
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
atomicshop/__init__.py,sha256=
|
|
1
|
+
atomicshop/__init__.py,sha256=8Ad5ESRJJbXiqt8GJU6Ro7MSdYdMqA0sQPjFqY8RsUU,122
|
|
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=
|
|
6
|
+
atomicshop/certificates.py,sha256=c9Z3VQvf7T5OD4sPHRzzfZO1M2gRzyRwpMLiMR06B0w,7942
|
|
7
7
|
atomicshop/command_line_processing.py,sha256=u5yT9Ger_cu7ni5ID0VFlRbVD46ARHeNC9tRM-_YXrQ,1038
|
|
8
8
|
atomicshop/config_init.py,sha256=G6_f25zPxyPlht5jJC4ZDrrQiuJfjHiuPd22VBjd9Cg,2683
|
|
9
9
|
atomicshop/console_output.py,sha256=AOSJjrRryE97PAGtgDL03IBtWSi02aNol8noDnW3k6M,4667
|
|
@@ -14,7 +14,7 @@ atomicshop/dns.py,sha256=XB0tijVi1bxWLWKV9hPzpt75jK4SrGbZCV5VJbiiQ74,7185
|
|
|
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=tCPRA6SQiJJkFL3BnPCoVhPCkvrkI2C4RyuSKzuxo1w,68060
|
|
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
|
|
@@ -91,7 +91,7 @@ atomicshop/archiver/shutils.py,sha256=BomnK7zT-nQXA1z0i2R2aTv8eu88wPx7tf2HtOdbmE
|
|
|
91
91
|
atomicshop/archiver/zips.py,sha256=0Z_1MWs7YRiCBVpyaG8llnzRguHSO4R51KDMN3FJZt8,16984
|
|
92
92
|
atomicshop/basics/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
93
93
|
atomicshop/basics/ansi_escape_codes.py,sha256=uGVRW01v2O052701sOfAdCaM_GLF_cu_jrssuYiPbzA,3216
|
|
94
|
-
atomicshop/basics/argparse_template.py,sha256=
|
|
94
|
+
atomicshop/basics/argparse_template.py,sha256=NRz63v2jr4tHcAGvqW1okYsGRt6n0u8FXuMQQT3dHPw,6071
|
|
95
95
|
atomicshop/basics/booleans.py,sha256=V36NaMf8AffhCom_ovQeOZlYcdtGyIcQwWKki6h7O0M,1745
|
|
96
96
|
atomicshop/basics/bytes_arrays.py,sha256=xfFW9CBQyzf0iXNWpx-EfrxtN3-tiKzuczPzOb6cOdU,7190
|
|
97
97
|
atomicshop/basics/classes.py,sha256=dBSQktjc1GmphpD_qOGYNDl-mQcmwg8OkhSqtXPfHEU,15301
|
|
@@ -137,10 +137,10 @@ atomicshop/mitm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
|
137
137
|
atomicshop/mitm/config_static.py,sha256=yNlELenRvLvW37dl2zXstts5zLklay9xF7sVu_AytKM,8839
|
|
138
138
|
atomicshop/mitm/config_toml_editor.py,sha256=2p1CMcktWRR_NW-SmyDwylu63ad5e0-w1QPMa8ZLDBw,1635
|
|
139
139
|
atomicshop/mitm/connection_thread_worker.py,sha256=50RP7De2t0WlUk4Ywmv6B63GwvtvoJ9mULo9Q3b-zcY,32992
|
|
140
|
-
atomicshop/mitm/import_config.py,sha256=
|
|
141
|
-
atomicshop/mitm/initialize_engines.py,sha256=
|
|
140
|
+
atomicshop/mitm/import_config.py,sha256=J3ZLF28AsKu1h76iRV_sCM52g0oh4dwDGddZl_XcJsU,18351
|
|
141
|
+
atomicshop/mitm/initialize_engines.py,sha256=qzz5jzh_lKC03bI1w5ebngVXo1K-RV3poAyW-nObyqo,11042
|
|
142
142
|
atomicshop/mitm/message.py,sha256=CDhhm4BTuZE7oNZCjvIZ4BuPOW4MuIzQLOg91hJaxDI,3065
|
|
143
|
-
atomicshop/mitm/mitm_main.py,sha256=
|
|
143
|
+
atomicshop/mitm/mitm_main.py,sha256=lHk66kai66W44y4Zu7z4eWRA2sZOwvuGHRzNjPHy31k,38291
|
|
144
144
|
atomicshop/mitm/recs_files.py,sha256=tv8XFhYZMkBv4DauvpiAdPgvSo0Bcm1CghnmwO7dx8M,5018
|
|
145
145
|
atomicshop/mitm/shared_functions.py,sha256=0lzeyINd44sVEfFbahJxQmz6KAMWbYrW5ou3UYfItvw,1777
|
|
146
146
|
atomicshop/mitm/statistic_analyzer.py,sha256=5_sAYGX2Xunzo_pS2W5WijNCwr_BlGJbbOO462y_wN4,27533
|
|
@@ -195,7 +195,7 @@ atomicshop/wrappers/_process_wrapper_curl.py,sha256=XkZZXYl7D0Q6UfdWqy-18AvpU0yV
|
|
|
195
195
|
atomicshop/wrappers/_process_wrapper_tar.py,sha256=WUMZFKNrlG4nJP9tWZ51W7BR1j_pIjsjgyAStmWjRGs,655
|
|
196
196
|
atomicshop/wrappers/astw.py,sha256=VkYfkfyc_PJLIOxByT6L7B8uUmKY6-I8XGZl4t_z828,4239
|
|
197
197
|
atomicshop/wrappers/configparserw.py,sha256=JwDTPjZoSrv44YKwIRcjyUnpN-FjgXVfMqMK_tJuSgU,22800
|
|
198
|
-
atomicshop/wrappers/cryptographyw.py,sha256=
|
|
198
|
+
atomicshop/wrappers/cryptographyw.py,sha256=QEUpDn8vUvMg3ADz6-4oC2kbDNC_woDlw7C0zU7qFVM,14233
|
|
199
199
|
atomicshop/wrappers/ffmpegw.py,sha256=wcq0ZnAe0yajBOuTKZCCaKI7CDBjkq7FAgdW5IsKcVE,6031
|
|
200
200
|
atomicshop/wrappers/githubw.py,sha256=DrFF_oN-rulPQV1iKgVzZadCjuYuCC5eKAjZp_3YD0g,23476
|
|
201
201
|
atomicshop/wrappers/msiw.py,sha256=GQLqud72nfex3kvO1bJSruNriCYTYX1_G1gSf1MPkIA,6118
|
|
@@ -204,11 +204,11 @@ atomicshop/wrappers/numpyw.py,sha256=sBV4gSKyr23kXTalqAb1oqttzE_2XxBooCui66jbAqc
|
|
|
204
204
|
atomicshop/wrappers/olefilew.py,sha256=biD5m58rogifCYmYhJBrAFb9O_Bn_spLek_9HofLeYE,2051
|
|
205
205
|
atomicshop/wrappers/pipw.py,sha256=mu4jnHkSaYNfpBiLZKMZxEX_E2LqW5BVthMZkblPB_c,1317
|
|
206
206
|
atomicshop/wrappers/process_wrapper_pbtk.py,sha256=ycPmBRnv627RWks6N8OhxJQe8Gu3h3Vwj-4HswPOw0k,599
|
|
207
|
-
atomicshop/wrappers/pyopensslw.py,sha256=
|
|
207
|
+
atomicshop/wrappers/pyopensslw.py,sha256=pklvXEbi0fHu5n1eRKKHEDLN_nsIqCTXv5Lv0bzReTo,7071
|
|
208
208
|
atomicshop/wrappers/sysmonw.py,sha256=CdawuWuy_uUi3ALCm6lKP7pSyKeTk1MXyzOaTMbBSO8,5346
|
|
209
209
|
atomicshop/wrappers/ubuntu_terminal.py,sha256=vGEBznz_EKzjhsFAXzefep3SwdP2toYPxWkagOjME3I,12328
|
|
210
210
|
atomicshop/wrappers/wslw.py,sha256=2Z7X0j5M2hoRZjbHfm_vqwNXZeptsdkNCdhdcM_S9vo,6998
|
|
211
|
-
atomicshop/wrappers/certauthw/certauth.py,sha256=
|
|
211
|
+
atomicshop/wrappers/certauthw/certauth.py,sha256=qLo593_MLU8VfbhYoNQ3J5BvtZuE71aFQROysEt6_dk,12225
|
|
212
212
|
atomicshop/wrappers/certauthw/certauthw.py,sha256=4WvhjANI7Kzqrr_nKmtA8Kf7B6rute_5wfP65gwQrjw,8082
|
|
213
213
|
atomicshop/wrappers/ctyping/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
214
214
|
atomicshop/wrappers/ctyping/file_details_winapi.py,sha256=dmdnCMwx4GgVEctiUIyniVShAoXmv_bZu_o81C450PY,2810
|
|
@@ -284,7 +284,7 @@ atomicshop/wrappers/playwrightw/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm
|
|
|
284
284
|
atomicshop/wrappers/playwrightw/_tryouts.py,sha256=l1BLkFsiIMNlgv7nfZd1XGEvXQkIQkIcg48__9OaC00,4920
|
|
285
285
|
atomicshop/wrappers/playwrightw/base.py,sha256=WeRpx8otdXuKSr-BjY-uCJTze21kbPpfitoOjKQz5-g,9818
|
|
286
286
|
atomicshop/wrappers/playwrightw/combos.py,sha256=215y7wugyyBrFK9_0WutnMXsF1jqJ2PLm9eHEa2PMz0,7145
|
|
287
|
-
atomicshop/wrappers/playwrightw/engine.py,sha256=
|
|
287
|
+
atomicshop/wrappers/playwrightw/engine.py,sha256=sw8TfQBNn-v0kMYDtmaWAA0wXndM57-4TMteWMw0jnA,15195
|
|
288
288
|
atomicshop/wrappers/playwrightw/infra.py,sha256=ncp62l6CgAgLz4lqBtKEWZO_6ES8cqnbzJBov-tlpBo,97
|
|
289
289
|
atomicshop/wrappers/playwrightw/javascript.py,sha256=_bW7CAtm0Y8IHYrAalg5HpPFnk6juiqicmkvZ9dITaA,1235
|
|
290
290
|
atomicshop/wrappers/playwrightw/keyboard.py,sha256=zN3YddGO-qUkn6C0CRVFejP4cTuaUwXLDNFhFREjERY,422
|
|
@@ -323,23 +323,23 @@ atomicshop/wrappers/socketw/accepter.py,sha256=4I9ORugRDvwaqSzm_gWSjZnRwQGY8hDTl
|
|
|
323
323
|
atomicshop/wrappers/socketw/base.py,sha256=EcosGkD8VzgBY3GeIHDSG29ThQfXwg3-GQPmBTAqTdw,3048
|
|
324
324
|
atomicshop/wrappers/socketw/certificator.py,sha256=mtWPJ_ew3OSwt0-1W4jaoco1VIY4NRCrMv3mDUxb_Cc,12418
|
|
325
325
|
atomicshop/wrappers/socketw/creator.py,sha256=LGI4gcgJ47thx6f96rjwjPz3CsTAIv6VxWFY4EyUF2E,13667
|
|
326
|
-
atomicshop/wrappers/socketw/dns_server.py,sha256=
|
|
326
|
+
atomicshop/wrappers/socketw/dns_server.py,sha256=iQym3LmrfUfBwrFmuSHdp_DgeUOueNpEKa_TPYQv0r4,55147
|
|
327
327
|
atomicshop/wrappers/socketw/exception_wrapper.py,sha256=qW_1CKyPgGlsIt7_jusKkMV4A4hih4bX324u0PLnoO8,7382
|
|
328
328
|
atomicshop/wrappers/socketw/get_process.py,sha256=aJC-_qFUv3NgWCSUzDI72E4z8_-VTZE9NVZ0CwUoNlM,5698
|
|
329
329
|
atomicshop/wrappers/socketw/receiver.py,sha256=9B3MvcDqr4C3x2fsnjG5SQognd1wRqsBgikxZa0wXG8,8243
|
|
330
330
|
atomicshop/wrappers/socketw/sender.py,sha256=aX_K8l_rHjd5AWb8bi5mt8-YTkMYVRDB6DnPqK_XDUE,4754
|
|
331
|
-
atomicshop/wrappers/socketw/sni.py,sha256=
|
|
331
|
+
atomicshop/wrappers/socketw/sni.py,sha256=PT50BFOHN5X0ZIyQRHA_Rl4z_lUbkv0em7Chl0viUlw,17819
|
|
332
332
|
atomicshop/wrappers/socketw/socket_client.py,sha256=McBd3DeCy787oDGCEMUEP2awWy3vdkPqr9w-aFh2fBM,22502
|
|
333
333
|
atomicshop/wrappers/socketw/socket_server_tester.py,sha256=Qobmh4XV8ZxLUaw-eW4ESKAbeSLecCKn2OWFzMhadk0,6420
|
|
334
|
-
atomicshop/wrappers/socketw/socket_wrapper.py,sha256=
|
|
334
|
+
atomicshop/wrappers/socketw/socket_wrapper.py,sha256=u_v0pjMMrgsdtI0iPPddiLe2wXnBoqTgNM9Y3zjGD4U,41013
|
|
335
335
|
atomicshop/wrappers/socketw/ssl_base.py,sha256=62-hPm7zla1rh3m_WvDnXqKH-sDUTdiRptD8STCkgdk,2313
|
|
336
336
|
atomicshop/wrappers/socketw/statistics_csv.py,sha256=_gA8bMX6Sw_UCXKi2y9wNAwlqifgExgDGfQIa9pFxQA,5543
|
|
337
337
|
atomicshop/wrappers/winregw/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
338
338
|
atomicshop/wrappers/winregw/winreg_installed_software.py,sha256=Qzmyktvob1qp6Tjk2DjLfAqr_yXV0sgWzdMW_9kwNjY,2345
|
|
339
339
|
atomicshop/wrappers/winregw/winreg_network.py,sha256=ih0BVNwByLvf9F_Lac4EdmDYYJA3PzMvmG0PieDZrsE,9905
|
|
340
|
-
atomicshop-3.3.
|
|
341
|
-
atomicshop-3.3.
|
|
342
|
-
atomicshop-3.3.
|
|
343
|
-
atomicshop-3.3.
|
|
344
|
-
atomicshop-3.3.
|
|
345
|
-
atomicshop-3.3.
|
|
340
|
+
atomicshop-3.3.2.dist-info/licenses/LICENSE.txt,sha256=lLU7EYycfYcK2NR_1gfnhnRC8b8ccOTElACYplgZN88,1094
|
|
341
|
+
atomicshop-3.3.2.dist-info/METADATA,sha256=0dnZPwzfNiqMA9qqJbgCwPT4OgNUkV1HWL9ZZhZ5YXY,9288
|
|
342
|
+
atomicshop-3.3.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
343
|
+
atomicshop-3.3.2.dist-info/entry_points.txt,sha256=SJEgEP0KoFtfxuGwe5tOzKfXkjR9Dv6YYug33KNYxyY,69
|
|
344
|
+
atomicshop-3.3.2.dist-info/top_level.txt,sha256=EgKJB-7xcrAPeqTRF2laD_Np2gNGYkJkd4OyXqpJphA,11
|
|
345
|
+
atomicshop-3.3.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|