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

Files changed (27) hide show
  1. atomicshop/__init__.py +1 -1
  2. atomicshop/basics/classes.py +19 -0
  3. atomicshop/mitm/connection_thread_worker.py +8 -4
  4. atomicshop/mitm/engines/__parent/parser___parent.py +2 -11
  5. atomicshop/mitm/engines/__parent/recorder___parent.py +2 -3
  6. atomicshop/mitm/engines/__parent/responder___parent.py +4 -7
  7. atomicshop/mitm/engines/__reference_general/parser___reference_general.py +10 -7
  8. atomicshop/mitm/engines/__reference_general/recorder___reference_general.py +3 -3
  9. atomicshop/mitm/engines/__reference_general/responder___reference_general.py +3 -3
  10. atomicshop/mitm/initialize_engines.py +11 -12
  11. atomicshop/mitm/mitm_main.py +7 -1
  12. atomicshop/mitm/statistic_analyzer.py +6 -23
  13. atomicshop/mitm/statistic_analyzer_helper/moving_average_helper.py +37 -6
  14. atomicshop/ssh_remote.py +19 -9
  15. atomicshop/wrappers/loggingw/loggers.py +8 -0
  16. atomicshop/wrappers/loggingw/loggingw.py +8 -10
  17. atomicshop/wrappers/socketw/dns_server.py +21 -3
  18. atomicshop/wrappers/socketw/get_process.py +6 -2
  19. atomicshop/wrappers/socketw/receiver.py +13 -3
  20. atomicshop/wrappers/socketw/sender.py +14 -3
  21. atomicshop/wrappers/socketw/socket_client.py +20 -5
  22. atomicshop/wrappers/socketw/socket_wrapper.py +2 -1
  23. {atomicshop-2.16.21.dist-info → atomicshop-2.16.23.dist-info}/METADATA +1 -1
  24. {atomicshop-2.16.21.dist-info → atomicshop-2.16.23.dist-info}/RECORD +27 -27
  25. {atomicshop-2.16.21.dist-info → atomicshop-2.16.23.dist-info}/LICENSE.txt +0 -0
  26. {atomicshop-2.16.21.dist-info → atomicshop-2.16.23.dist-info}/WHEEL +0 -0
  27. {atomicshop-2.16.21.dist-info → atomicshop-2.16.23.dist-info}/top_level.txt +0 -0
atomicshop/__init__.py CHANGED
@@ -1,4 +1,4 @@
1
1
  """Atomic Basic functions and classes to make developer life easier"""
2
2
 
3
3
  __author__ = "Den Kras"
4
- __version__ = '2.16.21'
4
+ __version__ = '2.16.23'
@@ -7,6 +7,25 @@ from pathlib import Path
7
7
  from ..file_io.file_io import read_file
8
8
 
9
9
 
10
+ """
11
+ class ParserParent:
12
+ # Initializing the logger in the "class variable" section will leave the instance of the logger initiated
13
+ # and the rest of the instances of the class will use the same logger.
14
+ # It is not in the "__init__" section, so it's not going to be initiated again.
15
+ # The name of the logger using "__name__" variable, which is the full name of the module package.
16
+ # Example: classes.parsers.parser_1_reference_general
17
+
18
+ # The code outside the functions will be executed during import of the module. When initializing a class
19
+ # in the script these lines will not be called again, only the "init" function.
20
+ logger = create_custom_logger()
21
+
22
+ def __init__(self, class_client_message: ClientMessage):
23
+ self.class_client_message: ClientMessage = class_client_message
24
+
25
+ # Usage: self.logger.info("Message")
26
+ """
27
+
28
+
10
29
  def create_empty_class():
11
30
  """
12
31
  Function creates empty class, you can add parameters to it dynamically.
@@ -125,7 +125,8 @@ def thread_worker_main(
125
125
 
126
126
  network_logger.info("Initializing Receiver")
127
127
  # Getting message from the client over the socket using specific class.
128
- client_received_raw_data = receiver.Receiver(function_client_socket_object).receive()
128
+ client_received_raw_data = receiver.Receiver(
129
+ ssl_socket=function_client_socket_object, logger=network_logger).receive()
129
130
 
130
131
  # If the message is empty, then the connection was closed already by the other side,
131
132
  # so we can close the socket as well.
@@ -239,13 +240,14 @@ def thread_worker_main(
239
240
  service_name=client_message.server_name, service_port=client_message.destination_port,
240
241
  tls=is_tls,
241
242
  dns_servers_list=(
242
- config_static.TCPServer.forwarding_dns_service_ipv4_list___only_for_localhost)
243
+ config_static.TCPServer.forwarding_dns_service_ipv4_list___only_for_localhost),
244
+ logger=network_logger
243
245
  )
244
246
  # If we're not on localhost, then connect to domain directly.
245
247
  else:
246
248
  service_client = socket_client.SocketClient(
247
249
  service_name=client_message.server_name, service_port=client_message.destination_port,
248
- tls=is_tls)
250
+ tls=is_tls, logger=network_logger)
249
251
 
250
252
  # Sending current client message and receiving a response.
251
253
  # If there was an error it will be passed to "client_message" object class and if not, "None" will
@@ -301,7 +303,9 @@ def thread_worker_main(
301
303
 
302
304
  # Iterate through the list of byte responses.
303
305
  for response_raw_bytes in client_message.response_list_of_raw_bytes:
304
- function_data_sent = sender.Sender(function_client_socket_object, response_raw_bytes).send()
306
+ function_data_sent = sender.Sender(
307
+ ssl_socket=function_client_socket_object, class_message=response_raw_bytes,
308
+ logger=network_logger).send()
305
309
 
306
310
  # If there was problem with sending data, we'll break current loop.
307
311
  if not function_data_sent:
@@ -2,20 +2,11 @@ from ...shared_functions import create_custom_logger
2
2
  from ...message import ClientMessage
3
3
 
4
4
 
5
- # Class that parses the message received from client.
6
5
  class ParserParent:
7
- # Initializing the logger in the "class variable" section will leave the instance of the logger initiated
8
- # and the rest of the instances of the class will use the same logger.
9
- # It is not in the "__init__" section, so it's not going to be initiated again.
10
- # The name of the logger using "__name__" variable, which is the full name of the module package.
11
- # Example: classes.parsers.parser_1_reference_general
12
-
13
- # The code outside the functions will be executed during import of the module. When initializing a class
14
- # in the script these lines will not be called again, only the "init" function.
15
- logger = create_custom_logger()
16
-
6
+ """Class that parses the message received from client."""
17
7
  def __init__(self, class_client_message: ClientMessage):
18
8
  self.class_client_message: ClientMessage = class_client_message
9
+ self.logger = create_custom_logger()
19
10
 
20
11
  def parse(self):
21
12
  # This is general parser, so we don't parse anything and 'request_body_parsed' gets empty byte string.
@@ -9,9 +9,6 @@ from ....file_io import file_io
9
9
 
10
10
  # The class that is responsible for Recording Requests / Responses.
11
11
  class RecorderParent:
12
- # The code outside the functions will be executed during import of the module. When initializing a class
13
- # in the script these lines will not be called again, only the "init" function.
14
- logger = create_custom_logger()
15
12
 
16
13
  def __init__(self, class_client_message: message.ClientMessage, record_path: str):
17
14
  self.class_client_message: message.ClientMessage = class_client_message
@@ -22,6 +19,8 @@ class RecorderParent:
22
19
  self.engine_record_path: str = str()
23
20
  self.record_file_path: str = str()
24
21
 
22
+ self.logger = create_custom_logger()
23
+
25
24
  # Get engine name and module name
26
25
  self.get_engine_module()
27
26
  # Build full file path.
@@ -7,20 +7,17 @@ from urllib.parse import unquote
7
7
  from urllib.parse import urlparse
8
8
  from urllib.parse import parse_qs
9
9
 
10
- from ...shared_functions import create_custom_logger
11
10
  from ...message import ClientMessage
12
11
  from ....http_parse import HTTPResponseParse
13
12
  from ....print_api import print_api
14
13
 
14
+ from atomicshop.mitm.shared_functions import create_custom_logger
15
15
 
16
- # The class that is responsible for generating response to client based on the received message.
17
- class ResponderParent:
18
- # The code outside the functions will be executed during import of the module. When initializing a class
19
- # in the script these lines will not be called again, only the "init" function.
20
- logger = create_custom_logger()
21
16
 
17
+ class ResponderParent:
18
+ """The class that is responsible for generating response to client based on the received message."""
22
19
  def __init__(self):
23
- return
20
+ self.logger = create_custom_logger()
24
21
 
25
22
  @staticmethod
26
23
  def get_path_parts(path: str):
@@ -3,21 +3,24 @@ from atomicshop.mitm.engines.__parent.parser___parent import ParserParent
3
3
  from atomicshop.mitm.shared_functions import create_custom_logger
4
4
  from atomicshop.mitm.message import ClientMessage
5
5
 
6
- # # This is 'example' '.proto' file that contains message 'ExampleRequest'.
7
- # from .example_pb2 import ExampleRequest
8
- # # Import from 'protobuf' library of function 'MessageToDict' that
9
- # converts protobuf message object type to python dict.
10
- # from google.protobuf.json_format import MessageToDict
6
+
7
+ """
8
+ # This is 'example' '.proto' file that contains message 'ExampleRequest'.
9
+ from .example_pb2 import ExampleRequest
10
+ # Import from 'protobuf' library of function 'MessageToDict' that
11
+ converts protobuf message object type to python dict.
12
+ from google.protobuf.json_format import MessageToDict
13
+ """
11
14
 
12
15
 
13
16
  # Class that parses the message received from client.
14
17
  class ParserGeneral(ParserParent):
15
- logger = create_custom_logger()
16
-
17
18
  # When initializing main classes through "super" you need to pass parameters to init
18
19
  def __init__(self, class_client_message: ClientMessage):
19
20
  super().__init__(class_client_message)
20
21
 
22
+ self.logger = create_custom_logger()
23
+
21
24
  # ==================================================================================================================
22
25
  # Uncomment this section in order to begin building custom responder.
23
26
  # def parse_example_request(self):
@@ -4,10 +4,10 @@ from atomicshop.mitm.shared_functions import create_custom_logger
4
4
  from atomicshop.mitm.message import ClientMessage
5
5
 
6
6
 
7
- # The class that is responsible for Recording Requests / Responses
8
7
  class RecorderGeneral(RecorderParent):
9
- logger = create_custom_logger()
10
-
8
+ """The class that is responsible for Recording Requests / Responses"""
11
9
  # When initializing main classes through "super" you need to pass parameters to init
12
10
  def __init__(self, class_client_message: ClientMessage, record_path):
13
11
  super().__init__(class_client_message, record_path)
12
+
13
+ self.logger = create_custom_logger()
@@ -14,14 +14,14 @@ from google.protobuf import json_format
14
14
  """
15
15
 
16
16
 
17
- # The class that is responsible for generating response to client based on the received message.
18
17
  class ResponderGeneral(ResponderParent):
19
- logger = create_custom_logger()
20
-
18
+ """The class that is responsible for generating response to client based on the received message."""
21
19
  # When initializing main classes through "super" you need to pass parameters to init
22
20
  def __init__(self):
23
21
  super().__init__()
24
22
 
23
+ self.logger = create_custom_logger()
24
+
25
25
  # ==================================================================================================================
26
26
  # Uncomment this section in order to begin building custom responder.
27
27
  # @staticmethod
@@ -62,6 +62,17 @@ class ModuleCategory:
62
62
  engine_directory_path, get_file=True, file_name_check_pattern=configuration_data['recorder_file'])[0].path
63
63
 
64
64
  def initialize_engine(self, logs_path: str, logger=None, reference_general: bool = False, **kwargs):
65
+ # Initiating logger for each engine by its name
66
+ loggingw.create_logger(
67
+ logger_name=self.engine_name,
68
+ directory_path=logs_path,
69
+ add_stream=True,
70
+ add_timedfile=True,
71
+ formatter_streamhandler='DEFAULT',
72
+ formatter_filehandler='DEFAULT',
73
+ backupCount=config_static.LogRec.store_logs_for_x_days
74
+ )
75
+
65
76
  if not reference_general:
66
77
  self.parser_class_object = import_first_class_name_from_file_path(
67
78
  self.script_directory, self.parser_file_path, logger=logger, stdout=False)
@@ -83,18 +94,6 @@ class ModuleCategory:
83
94
  logger.error_exception(f"Exception while initializing responder: {exception_object}")
84
95
  sys.exit()
85
96
 
86
- # Initiating logger for each engine by its name
87
- # initiate_logger(current_module.engine_name, log_file_extension)
88
- loggingw.create_logger(
89
- logger_name=self.engine_name,
90
- directory_path=logs_path,
91
- add_stream=True,
92
- add_timedfile=True,
93
- formatter_streamhandler='DEFAULT',
94
- formatter_filehandler='DEFAULT',
95
- backupCount=config_static.LogRec.store_logs_for_x_days
96
- )
97
-
98
97
 
99
98
  # Assigning external class object by message domain received from client. If the domain is not in the list,
100
99
  # the reference general module will be assigned.
@@ -242,7 +242,8 @@ def mitm_server_main(config_file_path: str):
242
242
  resolve_to_tcp_server_all_domains=config_static.DNSServer.resolve_to_tcp_server_all_domains,
243
243
  resolve_regular=config_static.DNSServer.resolve_regular,
244
244
  cache_timeout_minutes=config_static.DNSServer.cache_timeout_minutes,
245
- request_domain_queue=domain_queue
245
+ request_domain_queue=domain_queue,
246
+ logger=network_logger
246
247
  )
247
248
  except (dns_server.DnsPortInUseError, dns_server.DnsConfigurationValuesError) as e:
248
249
  print_api(e, error_type=True, color="red", logger=system_logger)
@@ -302,6 +303,11 @@ def mitm_server_main(config_file_path: str):
302
303
  # Wait for the message to be printed and saved to file.
303
304
  time.sleep(1)
304
305
  return 1
306
+ except socket_wrapper.SocketWrapperConfigurationValuesError as e:
307
+ print_api(e, error_type=True, color="red", logger=system_logger, logger_method='critical')
308
+ # Wait for the message to be printed and saved to file.
309
+ time.sleep(1)
310
+ return 1
305
311
 
306
312
  statistics_writer = socket_wrapper_instance.statistics_writer
307
313
 
@@ -429,30 +429,13 @@ def deviation_calculator_by_moving_average(
429
429
 
430
430
  if deviation_list:
431
431
  if summary:
432
- summary_deviation_list: list = []
433
432
  for deviation in deviation_list:
434
- value = deviation.get('value', None)
435
- ma_value = deviation.get('ma_value', None)
436
- if not value or not ma_value:
437
- total_entries_averaged = None
438
- else:
439
- total_entries_averaged = deviation['data']['count']
440
-
441
- summary_deviation_list.append({
442
- 'day': deviation['day'],
443
- 'host': deviation['host'],
444
- 'message': deviation['message'],
445
- 'value': deviation.get('value', None),
446
- 'ma_value': deviation.get('ma_value', None),
447
- 'deviation_percentage': deviation.get('deviation_percentage', None),
448
- 'total_entries_averaged': total_entries_averaged,
449
- 'median_request_size': deviation.get('median_request_size', None),
450
- 'median_response_size': deviation.get('median_response_size', None),
451
- 'mm_request_size': deviation.get('mm_request_size', None),
452
- 'mm_response_size': deviation.get('mm_response_size', None),
453
- })
454
-
455
- deviation_list = summary_deviation_list
433
+ _ = deviation.pop('check_type')
434
+ _ = deviation.pop('percentage')
435
+ _ = deviation.pop('ma_value_checked')
436
+ _ = deviation.pop('deviation_type')
437
+ _ = deviation.pop('data')
438
+ _ = deviation.pop('ma_data')
456
439
 
457
440
  if output_file_path:
458
441
  if not summary:
@@ -270,6 +270,7 @@ def compute_average_for_current_day_from_past_x_days(
270
270
  ma_count = statistics.mean(host_dict['counts'])
271
271
  ma_request_size = statistics.mean(host_dict['avg_request_sizes'])
272
272
  ma_response_size = statistics.mean(host_dict['avg_response_sizes'])
273
+ mm_count = statistics.median(host_dict['counts'])
273
274
  mm_request_size = statistics.median(host_dict['median_request_sizes'])
274
275
  mm_response_size = statistics.median(host_dict['median_response_sizes'])
275
276
 
@@ -277,6 +278,7 @@ def compute_average_for_current_day_from_past_x_days(
277
278
  'ma_count': ma_count,
278
279
  'ma_request_size': ma_request_size,
279
280
  'ma_response_size': ma_response_size,
281
+ 'mm_count': mm_count,
280
282
  'mm_request_size': mm_request_size,
281
283
  'mm_response_size': mm_response_size,
282
284
  'counts': host_dict['counts'],
@@ -332,8 +334,28 @@ def find_deviation_from_moving_average(
332
334
  deviation_percentage = (
333
335
  (host_moving_average_by_type - day_statistics_content_dict[check_type]) /
334
336
  host_moving_average_by_type)
337
+
335
338
  if deviation_type:
336
339
  message = f'[{check_type}] is [{deviation_type}] the moving average.'
340
+
341
+ # Get the right moving median.
342
+ if check_type == 'count':
343
+ median_type_string: str = 'count'
344
+ moving_median_type_string: str = 'mm_count'
345
+ else:
346
+ median_type_string: str = check_type.replace('avg', 'median')
347
+ moving_median_type_string: str = check_type.replace('avg', 'mm')
348
+
349
+ # The median and the total count are None for the count, Since they are the count.
350
+ if check_type == 'count':
351
+ total_entries_averaged = None
352
+ median_size = None
353
+ else:
354
+ total_entries_averaged = day_statistics_content_dict['count']
355
+ median_size = day_statistics_content_dict[median_type_string]
356
+
357
+ moving_median_size = moving_averages_dict[host][moving_median_type_string]
358
+
337
359
  deviation_list.append({
338
360
  'day': day,
339
361
  'host': host,
@@ -344,11 +366,10 @@ def find_deviation_from_moving_average(
344
366
  'percentage': top_bottom_deviation_percentage,
345
367
  'ma_value_checked': check_type_moving_above,
346
368
  'deviation_percentage': deviation_percentage,
369
+ 'total_entries_averaged': total_entries_averaged,
347
370
  'deviation_type': deviation_type,
348
- 'median_request_size': day_statistics_content_dict['median_request_size'],
349
- 'median_response_size': day_statistics_content_dict['median_response_size'],
350
- 'mm_request_size': moving_averages_dict[host]['mm_request_size'],
351
- 'mm_response_size': moving_averages_dict[host]['mm_response_size'],
371
+ 'median_size': median_size,
372
+ 'mm_size': moving_median_size,
352
373
  'data': day_statistics_content_dict,
353
374
  'ma_data': moving_averages_dict[host]
354
375
  })
@@ -373,9 +394,19 @@ def find_deviation_from_moving_average(
373
394
  deviation_list.append({
374
395
  'day': day,
375
396
  'host': host,
376
- 'data': host_dict,
377
397
  'message': message,
378
- 'type': 'clear'
398
+ 'value': None,
399
+ 'ma_value': None,
400
+ 'check_type': None,
401
+ 'percentage': None,
402
+ 'ma_value_checked': None,
403
+ 'deviation_percentage': None,
404
+ 'total_entries_averaged': None,
405
+ 'deviation_type': 'clear',
406
+ 'median_size': None,
407
+ 'mm_size': None,
408
+ 'data': host_dict,
409
+ 'ma_data': previous_day_moving_average_dict
379
410
  })
380
411
  continue
381
412
 
atomicshop/ssh_remote.py CHANGED
@@ -1,19 +1,19 @@
1
1
  import sys
2
2
  import base64
3
3
  import socket
4
+ import logging
5
+ from pathlib import Path
4
6
 
5
- from .print_api import print_api
6
- from .wrappers.loggingw import loggingw
7
- from .wrappers.socketw import base
8
-
9
-
10
- # External Libraries
11
7
  try:
12
8
  import paramiko
13
9
  except ImportError as exception_object:
14
10
  print(f"Library missing: {exception_object.name}. Install by executing: pip install paramiko")
15
11
  sys.exit()
16
12
 
13
+ from .print_api import print_api
14
+ from .wrappers.loggingw import loggingw
15
+ from .wrappers.socketw import base
16
+
17
17
 
18
18
  class SSHRemote:
19
19
  """
@@ -87,9 +87,13 @@ class SSHRemote:
87
87
  sys.exit(main())
88
88
 
89
89
  """
90
- logger = loggingw.get_logger_with_level("network." + __name__.rpartition('.')[2])
91
-
92
- def __init__(self, ip_address: str, username: str, password: str):
90
+ def __init__(
91
+ self,
92
+ ip_address: str,
93
+ username: str,
94
+ password: str,
95
+ logger: logging.Logger = None
96
+ ):
93
97
  self.ip_address: str = ip_address
94
98
  self.username: str = username
95
99
  self.password: str = password
@@ -97,6 +101,12 @@ class SSHRemote:
97
101
  # Initializing paramiko SSHClient class
98
102
  self.ssh_client = paramiko.SSHClient()
99
103
 
104
+ if logger:
105
+ # Create child logger for the provided logger with the module's name.
106
+ self.logger: logging.Logger = loggingw.get_logger_with_level(f'{logger.name}.{Path(__file__).stem}')
107
+ else:
108
+ self.logger: logging.Logger = logger
109
+
100
110
  def connect(self):
101
111
  error: str = str()
102
112
 
@@ -25,6 +25,14 @@ def is_logger_exists(
25
25
  return logger_name in logging.Logger.manager.loggerDict
26
26
 
27
27
 
28
+ def get_all_existing_loggers_names() -> list:
29
+ """
30
+ Function to get all existing loggers names.
31
+ :return: list, List of all existing loggers names.
32
+ """
33
+ return list(logging.Logger.manager.loggerDict.keys())
34
+
35
+
28
36
  def get_logger(logger_name: str) -> logging.Logger:
29
37
  """
30
38
  Function to get a logger.
@@ -5,10 +5,13 @@ from typing import Literal, Union
5
5
  from . import loggers, handlers
6
6
 
7
7
 
8
+ class LoggingwLoggerAlreadyExistsError(Exception):
9
+ pass
10
+
11
+
8
12
  # noinspection PyPep8Naming
9
13
  def create_logger(
10
14
  logger_name: str,
11
- get_existing_if_exists: bool = True,
12
15
  file_path: str = None,
13
16
  directory_path: str = None,
14
17
  add_stream: bool = False,
@@ -43,8 +46,6 @@ def create_logger(
43
46
  Function to get a logger and add StreamHandler and TimedRotatingFileHandler to it.
44
47
 
45
48
  :param logger_name: Name of the logger.
46
- :param get_existing_if_exists: bool, If set to True, the logger will be returned if it already exists.
47
- If set to False, the new stream/file handler will be added to existing logger again.
48
49
  :param file_path: full path to the log file. If you don't want to use the file, set it to None.
49
50
  You can set the directory_path only and then the 'logger_name' will be used as the file name with the
50
51
  'file_type' as the file extension.
@@ -165,6 +166,10 @@ def create_logger(
165
166
  main()
166
167
  """
167
168
 
169
+ # Check if the logger exists before creating it.
170
+ if loggers.is_logger_exists(logger_name):
171
+ raise LoggingwLoggerAlreadyExistsError(f"Logger '{logger_name}' already exists.")
172
+
168
173
  if not directory_path and not file_path:
169
174
  raise ValueError("You need to provide 'directory_path' or 'file_path'.")
170
175
  if directory_path and file_path:
@@ -176,15 +181,8 @@ def create_logger(
176
181
 
177
182
  file_path = f"{directory_path}{os.sep}{logger_name}.{file_type}"
178
183
 
179
- # Check if the logger exists before creating it/getting the existing.
180
- is_logger_exists = loggers.is_logger_exists(logger_name)
181
-
182
184
  logger = get_logger_with_level(logger_name, logging_level)
183
185
 
184
- # If the logger already exists, and we don't want to add the handlers again, return the logger.
185
- if get_existing_if_exists and is_logger_exists:
186
- return logger
187
-
188
186
  if add_stream:
189
187
  handlers.add_stream_handler(
190
188
  logger=logger, logging_level=logging_level, formatter=formatter_streamhandler,
@@ -3,6 +3,8 @@ import datetime
3
3
  import time
4
4
  import threading
5
5
  import socket
6
+ import logging
7
+ from pathlib import Path
6
8
 
7
9
  from ...print_api import print_api
8
10
  from ..loggingw import loggingw
@@ -28,8 +30,7 @@ class DnsServer:
28
30
  """
29
31
  DnsServer class is responsible to handle DNS Requests on port 53 based on configuration and send DNS Response back.
30
32
  """
31
- logger = loggingw.get_logger_with_level("network." + __name__.rpartition('.')[2])
32
-
33
+ # noinspection PyPep8Naming
33
34
  def __init__(
34
35
  self,
35
36
  listening_interface: str,
@@ -49,6 +50,7 @@ class DnsServer:
49
50
  response_ttl: int = 60,
50
51
  dns_service_retries: int = 5,
51
52
  cache_timeout_minutes: int = 60,
53
+ logger: logging.Logger = None
52
54
  ):
53
55
  """
54
56
  Initialize the DNS Server object with all the necessary settings.
@@ -80,6 +82,7 @@ class DnsServer:
80
82
  (socket connect / request send / response receive).
81
83
  :param cache_timeout_minutes: int: Timeout in minutes to clear the DNS Cache.
82
84
  server. Each domain will be pass in the queue as a string.
85
+ :param logger: logging.Logger: Logger object to use for logging. If not provided, a new logger will be created.
83
86
  """
84
87
 
85
88
  self.listening_interface: str = listening_interface
@@ -127,13 +130,28 @@ class DnsServer:
127
130
  # Logger that logs all the DNS Requests and responses in DNS format. These entries will not present in
128
131
  # network log of TCP Server module.
129
132
  self.dns_full_logger = loggingw.create_logger(
130
- logger_name="dns",
133
+ logger_name="dns_full",
131
134
  directory_path=self.log_directory_path,
132
135
  add_timedfile=True,
133
136
  formatter_filehandler='DEFAULT',
134
137
  backupCount=backupCount_log_files_x_days
135
138
  )
136
139
 
140
+ # Check if the logger was provided, if not, create a new logger.
141
+ if not logger:
142
+ self.logger = loggingw.create_logger(
143
+ logger_name=Path(__file__).stem,
144
+ directory_path=self.log_directory_path,
145
+ add_stream=True,
146
+ add_timedfile=True,
147
+ formatter_streamhandler='DEFAULT',
148
+ formatter_filehandler='DEFAULT',
149
+ backupCount=backupCount_log_files_x_days
150
+ )
151
+ else:
152
+ # Create child logger for the provided logger with the module's name.
153
+ self.logger: logging.Logger = loggingw.get_logger_with_level(f'{logger.name}.{Path(__file__).stem}')
154
+
137
155
  self.test_config()
138
156
 
139
157
  def test_config(self):
@@ -1,6 +1,7 @@
1
1
  # Needed to redirect output from console to logger on LOCALHOST process command line harvesting.
2
2
  import io
3
3
  from contextlib import redirect_stdout
4
+ import logging
4
5
 
5
6
  from . import base
6
7
  from ...ssh_remote import SSHRemote
@@ -15,12 +16,14 @@ class GetCommandLine:
15
16
  client_socket=None,
16
17
  ssh_script_processor=None,
17
18
  ssh_user: str = None,
18
- ssh_pass: str = None
19
+ ssh_pass: str = None,
20
+ logger: logging.Logger = None
19
21
  ):
20
22
  self.client_socket = client_socket
21
23
  self.ssh_script_processor = ssh_script_processor
22
24
  self.ssh_user: str = ssh_user
23
25
  self.ssh_pass: str = ssh_pass
26
+ self.logger: logging.Logger = logger
24
27
 
25
28
  def get_process_name(self, print_kwargs: dict = None):
26
29
  # Get client ip and the source port.
@@ -53,7 +56,8 @@ class GetCommandLine:
53
56
 
54
57
  print_api(f"Initializing SSH connection to [{client_ip}]", **print_kwargs)
55
58
  # Initializing SSHRemote class.
56
- current_ssh_client = SSHRemote(ip_address=client_ip, username=self.ssh_user, password=self.ssh_pass)
59
+ current_ssh_client = SSHRemote(
60
+ ip_address=client_ip, username=self.ssh_user, password=self.ssh_pass, logger=self.logger)
57
61
 
58
62
  execution_output, execution_error = current_ssh_client.connect_get_client_commandline(script_string)
59
63
  # Else, if we're on localhost, then execute the script directly without SSH.
@@ -1,5 +1,7 @@
1
+ import logging
1
2
  import socket
2
3
  import ssl
4
+ from pathlib import Path
3
5
 
4
6
  from ...print_api import print_api
5
7
  from ..loggingw import loggingw
@@ -20,9 +22,11 @@ def peek_first_bytes(client_socket, bytes_amount: int = 1) -> bytes:
20
22
 
21
23
  class Receiver:
22
24
  """ Receiver Class is responsible for receiving the message from socket and populate the message class """
23
- logger = loggingw.get_logger_with_level("network." + __name__.rpartition('.')[2])
24
-
25
- def __init__(self, ssl_socket: ssl.SSLSocket):
25
+ def __init__(
26
+ self,
27
+ ssl_socket: ssl.SSLSocket,
28
+ logger: logging.Logger = None
29
+ ):
26
30
  self.ssl_socket: ssl.SSLSocket = ssl_socket
27
31
  self.buffer_size_receive: int = 16384
28
32
  # Timeout of 2 is enough for regular HTTP sessions`.
@@ -39,6 +43,12 @@ class Receiver:
39
43
  # Will get client Local port from the socket
40
44
  self.class_client_local_port: int = int()
41
45
 
46
+ if logger:
47
+ # Create child logger for the provided logger with the module's name.
48
+ self.logger: logging.Logger = loggingw.get_logger_with_level(f'{logger.name}.{Path(__file__).stem}')
49
+ else:
50
+ self.logger: logging.Logger = logger
51
+
42
52
  # Function to receive only the buffer, with error handling
43
53
  def socket_receive_message_buffer(self):
44
54
  # Defining the data variable
@@ -1,16 +1,27 @@
1
1
  import ssl
2
+ import logging
3
+ from pathlib import Path
2
4
 
3
5
  from ...print_api import print_api
4
6
  from ..loggingw import loggingw
5
7
 
6
8
 
7
9
  class Sender:
8
- logger = loggingw.get_logger_with_level("network." + __name__.rpartition('.')[2])
9
-
10
- def __init__(self, ssl_socket: ssl.SSLSocket, class_message: bytearray):
10
+ def __init__(
11
+ self,
12
+ ssl_socket: ssl.SSLSocket,
13
+ class_message: bytearray,
14
+ logger: logging.Logger = None
15
+ ):
11
16
  self.class_message: bytearray = class_message
12
17
  self.ssl_socket: ssl.SSLSocket = ssl_socket
13
18
 
19
+ if logger:
20
+ # Create child logger for the provided logger with the module's name.
21
+ self.logger: logging.Logger = loggingw.get_logger_with_level(f'{logger.name}.{Path(__file__).stem}')
22
+ else:
23
+ self.logger: logging.Logger = logger
24
+
14
25
  # Function to send a message to server
15
26
  def send(self):
16
27
  # "socket.send()" returns number of bytes sent. "0" meaning that the socket was closed by the other side.
@@ -2,6 +2,8 @@ import socket
2
2
  import ssl
3
3
  import time
4
4
  from typing import Literal, Union
5
+ import logging
6
+ from pathlib import Path
5
7
 
6
8
  from cryptography import x509
7
9
 
@@ -18,11 +20,15 @@ import dns.resolver
18
20
 
19
21
 
20
22
  class SocketClient:
21
- logger = loggingw.get_logger_with_level("network." + __name__.rpartition('.')[2])
22
-
23
23
  def __init__(
24
24
  self,
25
- service_name: str, service_port: int, tls: bool = False, connection_ip=None, dns_servers_list=None):
25
+ service_name: str,
26
+ service_port: int,
27
+ tls: bool = False,
28
+ connection_ip=None,
29
+ dns_servers_list=None,
30
+ logger: logging.Logger = None
31
+ ):
26
32
  """
27
33
  If you have a certificate for domain, but not for the IPv4 address, the SSL Socket context can be created for
28
34
  domain and the connection itself (socket.connect()) made for the IP. This way YOU decide to which IPv4 your
@@ -38,6 +44,7 @@ class SocketClient:
38
44
  'service_name' by these DNS servers, with the first IPv4 result.
39
45
  :param dns_servers_list: (Optional) List object with dns IPv4 addresses that 'service_name' will be resolved
40
46
  with, using 'dnspython' module. 'connection_ip' will be populated with first resolved IP.
47
+ :param logger: (Optional) Logger object. If not provided, the default logger will be used.
41
48
 
42
49
  If both 'connection_ip' and 'dns_servers_list' specified, ValueException with raise.
43
50
  """
@@ -60,6 +67,12 @@ class SocketClient:
60
67
  elif self.connection_ip and self.dns_servers_list:
61
68
  raise ValueError("Both 'connection_ip' and 'dns_servers_list' were specified.")
62
69
 
70
+ if logger:
71
+ # Create child logger for the provided logger with the module's name.
72
+ self.logger: logging.Logger = loggingw.get_logger_with_level(f'{logger.name}.{Path(__file__).stem}')
73
+ else:
74
+ self.logger: logging.Logger = logger
75
+
63
76
  # Function to create SSL socket to destination service
64
77
  def create_service_socket(self):
65
78
  # If TLS is enabled.
@@ -208,7 +221,8 @@ class SocketClient:
208
221
  f"[{self.service_name}] resolves to ip: [{self.connection_ip}]. Pulled IP from the socket.")
209
222
 
210
223
  # Send the data received from the client to the service over socket
211
- function_data_sent = Sender(self.socket_instance, request_bytes).send()
224
+ function_data_sent = Sender(
225
+ ssl_socket=self.socket_instance, class_message=request_bytes, logger=self.logger).send()
212
226
 
213
227
  # If the socket disconnected on data send
214
228
  if not function_data_sent:
@@ -218,7 +232,8 @@ class SocketClient:
218
232
  self.close_socket()
219
233
  # Else if send was successful
220
234
  else:
221
- function_service_data = Receiver(self.socket_instance).receive()
235
+ function_service_data = Receiver(
236
+ ssl_socket=self.socket_instance, logger=self.logger).receive()
222
237
 
223
238
  # If data received is empty meaning the socket was closed on the other side
224
239
  if not function_service_data:
@@ -432,7 +432,8 @@ class SocketWrapper:
432
432
  client_socket=client_socket,
433
433
  ssh_script_processor=self.ssh_script_processor,
434
434
  ssh_user=self.ssh_user,
435
- ssh_pass=self.ssh_pass)
435
+ ssh_pass=self.ssh_pass,
436
+ logger=self.logger)
436
437
  process_name = get_command_instance.get_process_name(print_kwargs={'logger': self.logger})
437
438
 
438
439
  # If 'accept()' function worked well, SSL worked well, then 'client_socket' won't be empty.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: atomicshop
3
- Version: 2.16.21
3
+ Version: 2.16.23
4
4
  Summary: Atomic functions and classes to make developer life easier
5
5
  Author: Denis Kras
6
6
  License: MIT License
@@ -1,4 +1,4 @@
1
- atomicshop/__init__.py,sha256=zKVPai5VQ8seJQHyf_xQ-rQvYdF2i_Ndo5C7J_u4bvA,124
1
+ atomicshop/__init__.py,sha256=nFFyrQAHTstcKiEqAJ9esDeQ3MmcErpmeonwOprd9VU,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
@@ -35,7 +35,7 @@ atomicshop/scheduling.py,sha256=MvF20M6uU0Kh_CQn2ERxMTLvvF-ToBrdMhXNrKxYFj8,4682
35
35
  atomicshop/script_as_string_processor.py,sha256=uAIWwhHE-eP2FniuwBqEiM6VzyQX96uwdE3aA31rIm8,1883
36
36
  atomicshop/sound.py,sha256=tHiQQbFBk7EYN3pAfGNcxfF9oNsoYnZgu9z9iq8hxQE,24352
37
37
  atomicshop/speech_recognize.py,sha256=55-dIjgkpF93mvJnJuxSFuft5H5eRvGNlUj9BeIOZxk,5903
38
- atomicshop/ssh_remote.py,sha256=HUP4FHaEHexI0EnoLI9i2AgVQNTpsMNPNC4ZCI22EAA,17029
38
+ atomicshop/ssh_remote.py,sha256=Mxixqs2-xGy1bhbcP0LKqjxKTNPz1Gmzz8PzO8aLB4c,17345
39
39
  atomicshop/sys_functions.py,sha256=MTBxRve5bh58SPvhX3gMiGqHlSBuI_rdNN1NnnBBWqI,906
40
40
  atomicshop/system_resource_monitor.py,sha256=WvnnQrD5W9NRqOWI2YNcL-ut2UrvhrYToVlRR2c1vs8,13720
41
41
  atomicshop/system_resources.py,sha256=0mhDZBEcMzToCOw5ArJhtqYjktOW6iJGdyRkJ01Cpwk,9272
@@ -84,7 +84,7 @@ atomicshop/basics/ansi_escape_codes.py,sha256=WtIkm-BjSZS5J5irDUdAMBNvdX-qXFZcTX
84
84
  atomicshop/basics/argparse_template.py,sha256=horwgSf3MX1ZgRnYxtmmQuz9OU_vKrKggF65gmjlmfg,5836
85
85
  atomicshop/basics/booleans.py,sha256=QM0pibMmEKRKtBlpW9M5hkfD4S4rzirde0f8TSTnScE,2198
86
86
  atomicshop/basics/bytes_arrays.py,sha256=WvSRDhIGt1ywF95t-yNgpxLm1nlZUbM1Dz6QckcyE8Y,5915
87
- atomicshop/basics/classes.py,sha256=EijW_g4EhdNBnKPMG3nT3HjFspTchtM7to6zm9Ad_Mk,9771
87
+ atomicshop/basics/classes.py,sha256=T0Bm13hKvkXG3med68ptL7XuoWiCi3TE-K5TMINDlrY,10655
88
88
  atomicshop/basics/dicts.py,sha256=DeYHIh940pMMBrFhpXt4dsigFVYzTrlqWymNo4Pq_Js,14049
89
89
  atomicshop/basics/dicts_nested.py,sha256=StYxYnYPa0SEJr1lmEwAv5zfERWWqoULeyG8e0zRAwE,4107
90
90
  atomicshop/basics/enumerations.py,sha256=41VVQYh_vnVapggxKg2IRU5e_EiMpZzX1n1mtxvoSzM,1364
@@ -124,28 +124,28 @@ atomicshop/file_io/xmls.py,sha256=zh3SuK-dNaFq2NDNhx6ivcf4GYCfGM8M10PcEwDSpxk,21
124
124
  atomicshop/mitm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
125
125
  atomicshop/mitm/config_static.py,sha256=UNvRTb3ZuFVGZpF33fvaIf0xw_VGyml2ExIwqW_uYcg,7777
126
126
  atomicshop/mitm/config_toml_editor.py,sha256=2p1CMcktWRR_NW-SmyDwylu63ad5e0-w1QPMa8ZLDBw,1635
127
- atomicshop/mitm/connection_thread_worker.py,sha256=1MBpRoLpzWJMvxqQKizo6IVQ4XYsbKGsjxianNQLUlE,20051
127
+ atomicshop/mitm/connection_thread_worker.py,sha256=rfullUfMRR5YUEI45KJdGXlbOGYF89GfPkhUBoHizhM,20297
128
128
  atomicshop/mitm/import_config.py,sha256=_nu8mgA-M4s6dZ8_QWx3x0aVb75upvsCuX_PIUg4X2w,8345
129
- atomicshop/mitm/initialize_engines.py,sha256=kBG8TBnyFuwlJ1uKaWDzc5AiZNpwdvouq2pr-PYrdEA,8349
129
+ atomicshop/mitm/initialize_engines.py,sha256=Od1vC1ZGls0BNZiPgoRQj8Mc44UO8INJj3w1p5YQw5A,8274
130
130
  atomicshop/mitm/message.py,sha256=d_sm3O_aoZf87dDQP44xOMNEG-uZBN1ZecQgMCacbZs,1814
131
- atomicshop/mitm/mitm_main.py,sha256=CdCv4nYt_jwd23AI14v6lC2H8SZeIZqsXjFhwq61UtM,21285
131
+ atomicshop/mitm/mitm_main.py,sha256=gA8sV7hI107OnoeedCHpy8f3zcE4vAsBc44l_VTjVFo,21622
132
132
  atomicshop/mitm/recs_files.py,sha256=B8fSuvYXlh50LWfwLRw_bYswreTjmdZLuHJzbDC5Gss,2930
133
133
  atomicshop/mitm/shared_functions.py,sha256=hplm98tz8pgJ4WHUVI9sf_oVqUM2KJ1Y2pD6EFSb8P0,1879
134
- atomicshop/mitm/statistic_analyzer.py,sha256=0QYmkdSp5tjHkyl5MGWVEsgpRR3FgN7A2fE6pKTSO8I,27164
134
+ atomicshop/mitm/statistic_analyzer.py,sha256=c1Iv9qGy6_IGg95VxhRQ06sleygLdJi_B13MjZ0FJAU,26183
135
135
  atomicshop/mitm/engines/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
136
136
  atomicshop/mitm/engines/create_module_template.py,sha256=tRjVSm1sD6FzML71Qbuwvita0qsusdFGm8NZLsZ-XMs,4853
137
137
  atomicshop/mitm/engines/create_module_template_example.py,sha256=X5xhvbV6-g9jU_bQVhf_crZmaH50LRWz3bS-faQ18ds,489
138
138
  atomicshop/mitm/engines/__parent/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
139
- atomicshop/mitm/engines/__parent/parser___parent.py,sha256=Q1hEhbOXa8oBm9uD1VG2hLRCzUzpMjGeeS2Npd0a4Hw,1336
140
- atomicshop/mitm/engines/__parent/recorder___parent.py,sha256=G1TNVxUKFfRopUgENcLCQS0XGzNJmKYBep70wWHvPAQ,4650
141
- atomicshop/mitm/engines/__parent/responder___parent.py,sha256=gufSZP2Pic6iF7eTzbIi0z5-TPIDeIgoRQAplUwtcNk,12185
139
+ atomicshop/mitm/engines/__parent/parser___parent.py,sha256=VjV_cDuB3V0a3dPbJqLBEo3674Asa8-HVzvqxGULME8,720
140
+ atomicshop/mitm/engines/__parent/recorder___parent.py,sha256=s_FZwqBMZrX3SJZ5wmJNR3qQ5ODiIwmkTMLZ6JQ26DE,4466
141
+ atomicshop/mitm/engines/__parent/responder___parent.py,sha256=7WQeR3UmMnN74bDwn-0nz2OfhXJ3-ClXpNGUFZ7wJUE,12004
142
142
  atomicshop/mitm/engines/__reference_general/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
143
- atomicshop/mitm/engines/__reference_general/parser___reference_general.py,sha256=QolWZKm8SiPxxSoyWY_UK7ODam7EUMAgVfOPFnXxODE,2987
144
- atomicshop/mitm/engines/__reference_general/recorder___reference_general.py,sha256=KENDVf9OwXD9gwSh4B1XxACCe7iHYjrvnW1t6F64wdE,695
145
- atomicshop/mitm/engines/__reference_general/responder___reference_general.py,sha256=1AM49UaFTKA0AHw-k3SV3uH3QbG-o6ux0c-GoWkKNU0,6993
143
+ atomicshop/mitm/engines/__reference_general/parser___reference_general.py,sha256=57MEPZMAjTO6xBDZ-yt6lgGJyqRrP0Do5Gk_cgCiPns,2998
144
+ atomicshop/mitm/engines/__reference_general/recorder___reference_general.py,sha256=3eCGxD2oDulpVDgmMq19TyXohjsY-O_3HUiN8oKsUI4,712
145
+ atomicshop/mitm/engines/__reference_general/responder___reference_general.py,sha256=IUyQYMPeEhIARfALWiKPFeXagSQD6lRzAxUdi4ZIT88,7010
146
146
  atomicshop/mitm/statistic_analyzer_helper/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
147
147
  atomicshop/mitm/statistic_analyzer_helper/analyzer_helper.py,sha256=pk6L1t1ea1kvlBoR9QEJptOmaX-mumhwLsP2GCKukbk,5920
148
- atomicshop/mitm/statistic_analyzer_helper/moving_average_helper.py,sha256=Wge-OfbbClfjeEWwOyksd-x9C5QZdRD3KRSjtP9VL9Q,16651
148
+ atomicshop/mitm/statistic_analyzer_helper/moving_average_helper.py,sha256=XkJBAKD20j4rBpTWuhRJG3ONDWsktOh3PfOqzVDSORo,17883
149
149
  atomicshop/monitor/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
150
150
  atomicshop/monitor/change_monitor.py,sha256=K5NlVp99XIDDPnQQMdru4BDmua_DtcDIhVAzkTOvD5s,7673
151
151
  atomicshop/monitor/checks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -248,8 +248,8 @@ atomicshop/wrappers/loggingw/consts.py,sha256=JWiUJEydjhwatBxtIJsGTmDUSTLbmIRidt
248
248
  atomicshop/wrappers/loggingw/filters.py,sha256=CMs5PAMb68zxJgBcQobaOFDG5kLJBOVYnoBHjDgksO8,2859
249
249
  atomicshop/wrappers/loggingw/formatters.py,sha256=7XUJvlB0CK4DCkEp8NTL0S0dkyrZD0UTADgEwkStKOY,5483
250
250
  atomicshop/wrappers/loggingw/handlers.py,sha256=hAPFJQ-wFoNO8QzGrJRSvyuP09Q1F0Dl9_w7zzlgcW0,18155
251
- atomicshop/wrappers/loggingw/loggers.py,sha256=QH5QainlGLyrDpsDu4T1C8-WQQau3JW2OS5RgC-kXpM,2677
252
- atomicshop/wrappers/loggingw/loggingw.py,sha256=6HUn2z4ZW8PgakPscosKx23qYwHlBQcLiZGw-VZHi-k,12374
251
+ atomicshop/wrappers/loggingw/loggers.py,sha256=mmM__XR3W4QC82wbsDRG_M4_0JYGGEP0Qn0WCOSp-go,2910
252
+ atomicshop/wrappers/loggingw/loggingw.py,sha256=nt4UxOBHL--M-Ls9b3eicffCrspYWDWG1q4ZVlHATIs,12068
253
253
  atomicshop/wrappers/loggingw/reading.py,sha256=ERBSiQbEksySKpXpu2E_6k9dZ6MPH95ZIsmdjWW9MUE,16436
254
254
  atomicshop/wrappers/mongodbw/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
255
255
  atomicshop/wrappers/mongodbw/install_mongodb.py,sha256=3ZPqrXxj3lC-PnAKGXclylLuOqsbyXYeUpb5iGjdeUU,6626
@@ -296,21 +296,21 @@ atomicshop/wrappers/socketw/accepter.py,sha256=hZZKVYlF3LOHQJsSIEKXZUf6QXXWm-Atq
296
296
  atomicshop/wrappers/socketw/base.py,sha256=evoOIxg5Xff3THJnrVX00D5HobaOpDp6_e_gso7TJmA,2191
297
297
  atomicshop/wrappers/socketw/certificator.py,sha256=3CpQKtcW68FSbH6LVSEZTqWBS6Yg_-3K0x4nFkId4UY,12236
298
298
  atomicshop/wrappers/socketw/creator.py,sha256=3_OraDkw2DAWZfoSdY3svCGMOIxpjLEEY7NxWd7M5P4,9873
299
- atomicshop/wrappers/socketw/dns_server.py,sha256=53S52lkA9RWetNlee-mjt000OJW4Mi7Ktcru0WXrMZE,45504
299
+ atomicshop/wrappers/socketw/dns_server.py,sha256=G3roqkj_gMRTkVs2kgwiQR9S7YqA-uQWraCt8FqKjlo,46375
300
300
  atomicshop/wrappers/socketw/exception_wrapper.py,sha256=B-X5SHLSUIWToihH2MKnOB1F4A81_X0DpLLfnYKYbEc,7067
301
- atomicshop/wrappers/socketw/get_process.py,sha256=_YMVxYhVlzjJpeOR36tphZ5QWeKYwk03Ilw0muCxDbg,5950
302
- atomicshop/wrappers/socketw/receiver.py,sha256=G3hDTacm7nwwUNHEbKZpxO0c8rHcl0NeKpZy7Xc6zpA,9008
303
- atomicshop/wrappers/socketw/sender.py,sha256=d7YQFlCBMFTYtkGxbS-8cm5rh5WWFeBVvrEivWHYstI,3666
301
+ atomicshop/wrappers/socketw/get_process.py,sha256=zKEqh98cB9UDLFhtxVpperfXsCjyIMNANHilDD06p0U,6094
302
+ atomicshop/wrappers/socketw/receiver.py,sha256=XVvWOoeCo3vA0O5p19ryi-hcDIyx382WNG7WzMNVeYk,9322
303
+ atomicshop/wrappers/socketw/sender.py,sha256=OcX1aeI2OBDPPfvQkiEcV4Ak22DSJVvjMGYKOlgfpmI,3993
304
304
  atomicshop/wrappers/socketw/sni.py,sha256=fVwyh3h9IqfLMnf4__bMIzcF4c-Kk9mlbDWMRXKN-ow,17155
305
- atomicshop/wrappers/socketw/socket_client.py,sha256=FNmTt94YvjZP0X4RPb7icO3xD_nBHQ_XynnObdWFiAU,19682
305
+ atomicshop/wrappers/socketw/socket_client.py,sha256=hcHtOh43UhJAxYe7DSg4YVSJnCEKLRWKPiZ8DD8ite8,20237
306
306
  atomicshop/wrappers/socketw/socket_server_tester.py,sha256=Qobmh4XV8ZxLUaw-eW4ESKAbeSLecCKn2OWFzMhadk0,6420
307
- atomicshop/wrappers/socketw/socket_wrapper.py,sha256=DiDzg9OlgahxpqAsnOkCKHNcE-H-YAY3ndVMeU-oCjw,33363
307
+ atomicshop/wrappers/socketw/socket_wrapper.py,sha256=M47tjC8SoXZJV2fC_OYmSNNTs-3-ZQcpaB1WmvqVCTU,33408
308
308
  atomicshop/wrappers/socketw/ssl_base.py,sha256=kmiif84kMhBr5yjQW17p935sfjR5JKG0LxIwBA4iVvU,2275
309
309
  atomicshop/wrappers/socketw/statistics_csv.py,sha256=V_m1D0KpizQox3IEWp2AUcncwWy5kG25hbFrc-mBSJE,3029
310
310
  atomicshop/wrappers/winregw/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
311
311
  atomicshop/wrappers/winregw/winreg_network.py,sha256=bQ8Jql8bVGBJ0dt3VQ56lga_1LBOMLI3Km_otvvbU6c,7138
312
- atomicshop-2.16.21.dist-info/LICENSE.txt,sha256=lLU7EYycfYcK2NR_1gfnhnRC8b8ccOTElACYplgZN88,1094
313
- atomicshop-2.16.21.dist-info/METADATA,sha256=laLfi_M6QxDCtlg45NOSU4pblQDzfKTAavug5lp8Ewo,10473
314
- atomicshop-2.16.21.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
315
- atomicshop-2.16.21.dist-info/top_level.txt,sha256=EgKJB-7xcrAPeqTRF2laD_Np2gNGYkJkd4OyXqpJphA,11
316
- atomicshop-2.16.21.dist-info/RECORD,,
312
+ atomicshop-2.16.23.dist-info/LICENSE.txt,sha256=lLU7EYycfYcK2NR_1gfnhnRC8b8ccOTElACYplgZN88,1094
313
+ atomicshop-2.16.23.dist-info/METADATA,sha256=Ye4Ij67GZEdRL0YppIdiL1YjtpKcJWWbIzIG3ldpxsg,10473
314
+ atomicshop-2.16.23.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
315
+ atomicshop-2.16.23.dist-info/top_level.txt,sha256=EgKJB-7xcrAPeqTRF2laD_Np2gNGYkJkd4OyXqpJphA,11
316
+ atomicshop-2.16.23.dist-info/RECORD,,