atomicshop 2.18.1__py3-none-any.whl → 2.18.3__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 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.18.1'
4
+ __version__ = '2.18.3'
@@ -98,7 +98,6 @@ def thread_worker_main(
98
98
  raw_bytes: bytes,
99
99
  client_message: ClientMessage):
100
100
  nonlocal protocol
101
- nonlocal protocol3
102
101
 
103
102
  # Parsing the raw bytes as HTTP.
104
103
  request_http_parsed, is_http_request, request_parsing_error = (
@@ -120,9 +119,6 @@ def thread_worker_main(
120
119
  auto_parsed = response_http_parsed
121
120
  network_logger.info(
122
121
  f"HTTP Response Parsed: Status: {response_http_parsed.code}")
123
- protocol3 = auto_parsed.headers.get('Sec-WebSocket-Protocol', None)
124
- if protocol3:
125
- client_message.protocol3 = protocol3
126
122
  elif protocol == 'Websocket':
127
123
  client_message.protocol2 = 'Frame'
128
124
  auto_parsed = parse_websocket(raw_bytes)
@@ -137,12 +133,16 @@ def thread_worker_main(
137
133
  auto_parsed,
138
134
  client_message: ClientMessage):
139
135
  nonlocal protocol
136
+ nonlocal protocol3
140
137
 
141
138
  if protocol == 'HTTP':
142
139
  if auto_parsed and hasattr(auto_parsed, 'headers') and 'Upgrade' in auto_parsed.headers:
143
140
  if auto_parsed.headers['Upgrade'] == 'websocket':
144
141
  protocol = 'Websocket'
145
142
  client_message.protocol2 = 'Handshake'
143
+ protocol3 = auto_parsed.headers.get('Sec-WebSocket-Protocol', None)
144
+ if protocol3:
145
+ client_message.protocol3 = protocol3
146
146
 
147
147
  network_logger.info(f'Protocol upgraded to Websocket')
148
148
 
@@ -171,7 +171,7 @@ def thread_worker_main(
171
171
 
172
172
  # If it's the first cycle and the protocol is Websocket, then we'll create the HTTP Handshake
173
173
  # response automatically.
174
- if protocol == 'Websocket' and client_receive_count == 0:
174
+ if protocol == 'Websocket' and client_receive_count == 1:
175
175
  responses: list = list()
176
176
  responses.append(
177
177
  websocket_parse.create_byte_http_response(client_message.request_raw_bytes))
@@ -240,11 +240,12 @@ def thread_worker_main(
240
240
  return
241
241
 
242
242
  client_message.response_auto_parsed = parse_http(client_message.request_raw_bytes, client_message)
243
+ # This is needed for each cycle that is not HTTP, but its protocol maybe set by HTTP, like websocket.
243
244
  if protocol != '':
244
245
  client_message.protocol = protocol
245
246
 
246
247
  # Parse websocket frames only if it is not the first protocol upgrade request.
247
- if protocol == 'Websocket' and client_receive_count != 0:
248
+ if protocol == 'Websocket' and client_receive_count != 1:
248
249
  client_message.request_auto_parsed = parse_websocket(client_message.request_raw_bytes)
249
250
 
250
251
  # Custom parser, should parse HTTP body or the whole message if not HTTP.
@@ -291,6 +292,11 @@ def thread_worker_main(
291
292
  try:
292
293
  while True:
293
294
  client_message = responder_queue.get()
295
+
296
+ # If the message is not a ClientMessage object, then we'll break the loop, since it is the exit signal.
297
+ if not isinstance(client_message, ClientMessage):
298
+ return
299
+
294
300
  raw_responses: list[bytes] = create_responder_response(client_message)
295
301
 
296
302
  is_socket_closed: bool = False
@@ -377,10 +383,10 @@ def thread_worker_main(
377
383
  # the close on the opposite socket.
378
384
  record_and_statistics_write(client_message)
379
385
 
380
- if is_socket_closed:
381
- exception_or_close_in_receiving_thread = True
382
- finish_thread()
383
- return
386
+ # if is_socket_closed:
387
+ # exception_or_close_in_receiving_thread = True
388
+ # finish_thread()
389
+ # return
384
390
 
385
391
  # If we're in response mode, execute responder.
386
392
  if config_static.TCPServer.server_response_mode:
@@ -404,9 +410,10 @@ def thread_worker_main(
404
410
 
405
411
  record_and_statistics_write(client_message)
406
412
 
407
- # If the socket was closed, then we'll break the loop.
413
+ # If the socket was closed on message receive, then we'll break the loop only after send.
408
414
  if is_socket_closed or error_on_send:
409
415
  exception_or_close_in_receiving_thread = True
416
+ responder_queue.put('exit')
410
417
  finish_thread()
411
418
  return
412
419
  except Exception as exc:
@@ -437,6 +444,7 @@ def thread_worker_main(
437
444
  # record_and_statistics_write(client_message)
438
445
 
439
446
  finish_thread()
447
+ responder_queue.put('exit')
440
448
  exception_queue.put(exc)
441
449
 
442
450
  def handle_exceptions_on_main_connection_thread(
@@ -512,6 +520,9 @@ def thread_worker_main(
512
520
  responder_thread: threading.Thread = threading.Thread(
513
521
  target=responder_thread_worker, name=f"Thread-{thread_id}-Responder", daemon=True)
514
522
  responder_thread.start()
523
+ else:
524
+ # noinspection PyTypeChecker
525
+ responder_thread = None
515
526
 
516
527
  service_client = None
517
528
  client_receive_count: int = 0
@@ -557,6 +568,8 @@ def thread_worker_main(
557
568
 
558
569
  client_thread.join()
559
570
  service_thread.join()
571
+ if config_static.TCPServer.server_response_mode:
572
+ responder_thread.join()
560
573
 
561
574
  # If there was an exception in any of the threads, then we'll raise it here.
562
575
  if not client_exception_queue.empty():
@@ -3,6 +3,8 @@ import multiprocessing
3
3
  import time
4
4
  import datetime
5
5
 
6
+ from distro import minor_version
7
+
6
8
  import atomicshop # Importing atomicshop package to get the version of the package.
7
9
 
8
10
  from .. import filesystem, queues, dns, on_exit, print_api
@@ -65,7 +67,8 @@ def mitm_server(config_file_path: str):
65
67
  # Main function should return integer with error code, 0 is successful.
66
68
  # Since listening server is infinite, this will not be reached.
67
69
  # After modules import - we check for python version.
68
- check_python_version_compliance(minimum_version='3.12')
70
+ if not check_python_version_compliance(minor_version='3.12'):
71
+ return 1
69
72
 
70
73
  # Import the configuration file.
71
74
  result = config_static.load_config(config_file_path)
@@ -1,4 +1,5 @@
1
1
  import sys
2
+ from typing import Union
2
3
 
3
4
  from .print_api import print_api
4
5
 
@@ -43,23 +44,46 @@ def check_if_version_object_is_tuple_or_string(version_object: any,
43
44
 
44
45
 
45
46
  # noinspection PyUnusedLocal
46
- def check_python_version_compliance(minimum_version: any,
47
- maximum_version: any = None,
48
- **kwargs) -> bool:
47
+ def check_python_version_compliance(
48
+ minimum_version: Union[str, tuple] = None,
49
+ maximum_version: Union[str, tuple] = None,
50
+ minor_version: Union[str, tuple] = None,
51
+ **kwargs
52
+ ) -> bool:
49
53
  """
50
54
  Python version check. Should be executed before importing external libraries, since they depend on Python version.
51
55
 
52
56
  :param minimum_version: Can be string ('3.10') or tuple of integers ((3, 10)).
53
57
  :param maximum_version: Can be string ('3.10') or tuple of integers ((3, 10)).
54
58
  If maximum version is not specified, it will be considered as all versions above the minimum are compliant.
59
+ :param minor_version: Can be string ('3.10') or tuple of integers ((3, 10)).
60
+ If minor version is specified, it will be considered as all the versions with the same major, minor version
61
+ are compliant. Example: if minor_version is '3.10', then all the versions with '3.10.x' are compliant.
55
62
  :return:
56
63
  """
57
64
 
58
- # Check 'minimum_version' object for string or tuple and get the tuple.
59
- minimum_version_scheme: tuple = check_if_version_object_is_tuple_or_string(minimum_version, **kwargs)
65
+ if not minimum_version and not maximum_version and not minor_version:
66
+ raise ValueError("At least one of the version parameters should be passed.")
67
+
68
+ if minor_version and (minimum_version or maximum_version):
69
+ raise ValueError("Minor version should be passed alone.")
70
+
71
+ # Check objects for string or tuple and get the tuple.
72
+ if minimum_version:
73
+ minimum_version_scheme: tuple = check_if_version_object_is_tuple_or_string(minimum_version, **kwargs)
74
+ else:
75
+ minimum_version_scheme = tuple()
60
76
  # If 'maximum_version' object was passed, check it for string or tuple and get the tuple.
61
77
  if maximum_version:
62
78
  maximum_version_scheme: tuple = check_if_version_object_is_tuple_or_string(maximum_version, **kwargs)
79
+ else:
80
+ maximum_version_scheme = tuple()
81
+
82
+ # If 'minor_version' object was passed, check it for string or tuple and get the tuple.
83
+ if minor_version:
84
+ minor_version_scheme: tuple = check_if_version_object_is_tuple_or_string(minor_version, **kwargs)
85
+ else:
86
+ minor_version_scheme = tuple()
63
87
 
64
88
  # Get current python version.
65
89
  python_version_full: str = get_current_python_version_string()
@@ -67,24 +91,37 @@ def check_python_version_compliance(minimum_version: any,
67
91
  message = f"[*] Current Python Version: {python_version_full}"
68
92
  print_api(message, logger_method='info', **kwargs)
69
93
 
70
- # if 'maximum_version' passed and current python version is later or equals to the minimum and earlier than
71
- # maximum version required.
72
- if maximum_version:
94
+ if minor_version_scheme:
95
+ # Check if current python version is later or equals to the minimum required version.
96
+ if sys.version_info[:2] != minor_version_scheme:
97
+ message = f"[!!!] YOU NEED TO INSTALL ANY PYTHON " \
98
+ f"[{'.'.join(str(i) for i in minor_version_scheme)}] version, " \
99
+ f"to work properly."
100
+ print_api(message, error_type=True, logger_method='critical', **kwargs)
101
+
102
+ return False
103
+ elif minimum_version_scheme and maximum_version_scheme:
73
104
  if not sys.version_info >= minimum_version_scheme or not sys.version_info < maximum_version_scheme:
74
105
  message = f"[!!!] YOU NEED TO INSTALL AT LEAST PYTHON " \
75
- f"{'.'.join(str(i) for i in minimum_version_scheme)}, " \
76
- f"AND EARLIER THAN {'.'.join(str(i) for i in maximum_version_scheme)}, " \
77
- f"to work properly. Unhandled exceptions are inevitable!"
106
+ f"[{'.'.join(str(i) for i in minimum_version_scheme)}], " \
107
+ f"AND EARLIER THAN [{'.'.join(str(i) for i in maximum_version_scheme)}], " \
108
+ f"to work properly."
78
109
  print_api(message, error_type=True, logger_method='critical', **kwargs)
79
110
 
80
111
  return False
81
- # If 'maximum_version' wasn't passed.
82
- else:
83
- # Check if current python version is later or equals to the minimum required version.
112
+ elif minimum_version_scheme and not maximum_version_scheme:
84
113
  if not sys.version_info >= minimum_version_scheme:
85
114
  message = f"[!!!] YOU NEED TO INSTALL AT LEAST PYTHON " \
86
- f"{'.'.join(str(i) for i in minimum_version_scheme)}, " \
87
- f"to work properly. Unhandled exceptions are inevitable!"
115
+ f"[{'.'.join(str(i) for i in minimum_version_scheme)}], " \
116
+ f"to work properly."
117
+ print_api(message, error_type=True, logger_method='critical', **kwargs)
118
+
119
+ return False
120
+ elif not minimum_version_scheme and maximum_version_scheme:
121
+ if not sys.version_info < maximum_version_scheme:
122
+ message = f"[!!!] YOU NEED TO INSTALL EARLIER THAN PYTHON " \
123
+ f"[{'.'.join(str(i) for i in maximum_version_scheme)}], " \
124
+ f"to work properly."
88
125
  print_api(message, error_type=True, logger_method='critical', **kwargs)
89
126
 
90
127
  return False
@@ -133,11 +133,11 @@ class WebsocketFrameParser:
133
133
  elif current_frame.opcode == Opcode.BINARY:
134
134
  return current_frame.data, 'BINARY'
135
135
  elif current_frame.opcode == Opcode.CLOSE:
136
- return None, 'CLOSE'
136
+ return current_frame.data, 'CLOSE'
137
137
  elif current_frame.opcode == Opcode.PING:
138
- return None, 'PING'
138
+ return current_frame.data, 'PING'
139
139
  elif current_frame.opcode == Opcode.PONG:
140
- return None, 'PONG'
140
+ return current_frame.data, 'PONG'
141
141
  else:
142
142
  raise WebsocketParseWrongOpcode("Received unknown frame with opcode:", current_frame.opcode)
143
143
 
@@ -239,7 +239,7 @@ def create_websocket_frame(
239
239
  return frame_bytes
240
240
 
241
241
 
242
- def is_frame_masked(frame_bytes):
242
+ def is_frame_masked(frame_bytes: bytes):
243
243
  """
244
244
  Determine whether a WebSocket frame is masked.
245
245
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: atomicshop
3
- Version: 2.18.1
3
+ Version: 2.18.3
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=sd-5MCzdxJLvLvlvBmT3hqetHRPabTPPEglAUqrWUSo,123
1
+ atomicshop/__init__.py,sha256=aciLHL-9AkNeS_Ahx9NP3lvs533n84eEd96p1hCCdRU,123
2
2
  atomicshop/_basics_temp.py,sha256=6cu2dd6r2dLrd1BRNcVDKTHlsHs_26Gpw8QS6v32lQ0,3699
3
3
  atomicshop/_create_pdf_demo.py,sha256=Yi-PGZuMg0RKvQmLqVeLIZYadqEZwUm-4A9JxBl_vYA,3713
4
4
  atomicshop/_patch_import.py,sha256=ENp55sKVJ0e6-4lBvZnpz9PQCt3Otbur7F6aXDlyje4,6334
@@ -28,7 +28,7 @@ atomicshop/pbtkmultifile_argparse.py,sha256=aEk8nhvoQVu-xyfZosK3ma17CwIgOjzO1erX
28
28
  atomicshop/print_api.py,sha256=q9dAQCASk3pHp_PtYIpr6iZmRcW_lvrV_gPPNwTMRsw,11152
29
29
  atomicshop/process.py,sha256=PeLvyixXaCfftdUF3oMbohI1L4MdLtvQVDx2V1Tz_Rk,16662
30
30
  atomicshop/python_file_patcher.py,sha256=-uhbUX-um5k-If_XXuOfCr8wMzZ3QE6h9N8xGWw6W_o,5486
31
- atomicshop/python_functions.py,sha256=zJg4ogUwECxrDD7xdDN5JikIUctITM5lsyabr_ZNsRw,4435
31
+ atomicshop/python_functions.py,sha256=BPZ3sv5DgQs6Xrl3nIMdPABRpgrau3XSrsnDIz-LEwY,6175
32
32
  atomicshop/question_answer_engine.py,sha256=7nM6kGDSFjQNi87b87-kP9lYM0vTjBHn1rEQGNAfdGA,825
33
33
  atomicshop/queues.py,sha256=Al0fdC3ZJmdKfv-PyBeIck9lnfLr82BYchvzr189gsI,640
34
34
  atomicshop/scheduling.py,sha256=MvF20M6uU0Kh_CQn2ERxMTLvvF-ToBrdMhXNrKxYFj8,4682
@@ -46,7 +46,7 @@ atomicshop/uuids.py,sha256=JSQdm3ZTJiwPQ1gYe6kU0TKS_7suwVrHc8JZDGYlydM,2214
46
46
  atomicshop/venvs.py,sha256=D9lwOoObkYoRx-weuoAmbvN-RdSHhVm4DE9TVl-utAs,903
47
47
  atomicshop/virtualization.py,sha256=LPP4vjE0Vr10R6DA4lqhfX_WaNdDGRAZUW0Am6VeGco,494
48
48
  atomicshop/web.py,sha256=GLdTXgMxg1_0UQaXC4bOvARVyuFg7SPIeJdsCHV8rNE,11662
49
- atomicshop/websocket_parse.py,sha256=bkOwiXCNw5bQg1J4KOG7es5kUGysyX2NdfFFVBceSzg,16662
49
+ atomicshop/websocket_parse.py,sha256=aLHWyKqaYqEn_MRBWm2L6rIl6QPmqbVrjEXE_rBzwCw,16711
50
50
  atomicshop/a_installs/ubuntu/docker_rootless.py,sha256=9IPNtGZYjfy1_n6ZRt7gWz9KZgR6XCgevjqq02xk-o0,281
51
51
  atomicshop/a_installs/ubuntu/docker_sudo.py,sha256=JzayxeyKDtiuT4Icp2L2LyFRbx4wvpyN_bHLfZ-yX5E,281
52
52
  atomicshop/a_installs/ubuntu/elastic_search_and_kibana.py,sha256=yRB-l1zBxdiN6av-FwNkhcBlaeu4zrDPjQ0uPGgpK2I,244
@@ -127,11 +127,11 @@ atomicshop/file_io/xmls.py,sha256=zh3SuK-dNaFq2NDNhx6ivcf4GYCfGM8M10PcEwDSpxk,21
127
127
  atomicshop/mitm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
128
128
  atomicshop/mitm/config_static.py,sha256=HIzxyMEj7DZksYvJsN5VuKpB-_HSVvuR6U59ztS9gi0,7871
129
129
  atomicshop/mitm/config_toml_editor.py,sha256=2p1CMcktWRR_NW-SmyDwylu63ad5e0-w1QPMa8ZLDBw,1635
130
- atomicshop/mitm/connection_thread_worker.py,sha256=NHRa_f7k12JH9eDuGmr_-eCPRQVjO77RgCmLe9K2lWA,26073
130
+ atomicshop/mitm/connection_thread_worker.py,sha256=Of-QmuIbUO8Qd1N_BXdGQk2TnPpZd2z-Pxrj0wyq9S8,26758
131
131
  atomicshop/mitm/import_config.py,sha256=0Ij14aISTllTOiWYJpIUMOWobQqGofD6uafui5uWllE,9272
132
132
  atomicshop/mitm/initialize_engines.py,sha256=NWz0yBErSrYBn0xWkJDBcHStBJ-kcsv9VtorcSP9x5M,8258
133
133
  atomicshop/mitm/message.py,sha256=mNo4Lphr_Jo6IlNX5mPJzABpogWGkjOhwI4meAivwHw,2987
134
- atomicshop/mitm/mitm_main.py,sha256=AxmqUiDHgfzqmIF8v2GZxlEKth6_AMaYcqAxziWMG0U,23430
134
+ atomicshop/mitm/mitm_main.py,sha256=3F227Vh-F2ZGxOPE7eP4bgIZ72e3BzdUAHhWIMBbhFo,23490
135
135
  atomicshop/mitm/recs_files.py,sha256=ZAAD0twun-FtmbSniXe3XQhIlawvANNB_HxwbHj7kwI,3151
136
136
  atomicshop/mitm/shared_functions.py,sha256=0lzeyINd44sVEfFbahJxQmz6KAMWbYrW5ou3UYfItvw,1777
137
137
  atomicshop/mitm/statistic_analyzer.py,sha256=5_sAYGX2Xunzo_pS2W5WijNCwr_BlGJbbOO462y_wN4,27533
@@ -319,8 +319,8 @@ atomicshop/wrappers/socketw/ssl_base.py,sha256=kmiif84kMhBr5yjQW17p935sfjR5JKG0L
319
319
  atomicshop/wrappers/socketw/statistics_csv.py,sha256=fgMzDXI0cybwUEqAxprRmY3lqbh30KAV-jOpoFKT-m8,3395
320
320
  atomicshop/wrappers/winregw/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
321
321
  atomicshop/wrappers/winregw/winreg_network.py,sha256=zZQfps-CdODQaTUADbHAwKHr5RUg7BLafnKWBbKaLN4,8728
322
- atomicshop-2.18.1.dist-info/LICENSE.txt,sha256=lLU7EYycfYcK2NR_1gfnhnRC8b8ccOTElACYplgZN88,1094
323
- atomicshop-2.18.1.dist-info/METADATA,sha256=udb7ZbArHpKHBqBMXmBZbJw4FBWF0EVZeWc3yVZHeak,10499
324
- atomicshop-2.18.1.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
325
- atomicshop-2.18.1.dist-info/top_level.txt,sha256=EgKJB-7xcrAPeqTRF2laD_Np2gNGYkJkd4OyXqpJphA,11
326
- atomicshop-2.18.1.dist-info/RECORD,,
322
+ atomicshop-2.18.3.dist-info/LICENSE.txt,sha256=lLU7EYycfYcK2NR_1gfnhnRC8b8ccOTElACYplgZN88,1094
323
+ atomicshop-2.18.3.dist-info/METADATA,sha256=9sxUGrK_-bQdIzS6k4nNclLdMORnzGbWBI4vqP7c378,10499
324
+ atomicshop-2.18.3.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
325
+ atomicshop-2.18.3.dist-info/top_level.txt,sha256=EgKJB-7xcrAPeqTRF2laD_Np2gNGYkJkd4OyXqpJphA,11
326
+ atomicshop-2.18.3.dist-info/RECORD,,