atomicshop 2.16.45__py3-none-any.whl → 2.16.48__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.16.45'
4
+ __version__ = '2.16.48'
atomicshop/diff_check.py CHANGED
@@ -54,9 +54,9 @@ class DiffChecker:
54
54
  function input for that object. So, not always you know what your object type during class initialization.
55
55
  :param check_object_display_name: string, name of the object to display in the message.
56
56
  If not specified, the provided 'check_object' will be displayed.
57
- :param aggregation: boolean, if True, the object will be aggregated with other objects in the list of objects.
58
- Meaning, that the object will be checked against the existing objects in the list, and if it is not
59
- in the list, it will be added to the list. If it is in the list, it will be ignored.
57
+ #:param aggregation: boolean, if True, the object will be aggregated with other objects in the list of objects.
58
+ # Meaning, that the object will be checked against the existing objects in the list, and if it is not
59
+ # in the list, it will be added to the list. If it is in the list, it will be ignored.
60
60
  :param input_file_path: string, full file path for storing input file for current state of objects,
61
61
  to check later if this state isn't updated. If this variable is left empty, all the content will be saved
62
62
  in memory and input file will not be used.
@@ -127,13 +127,7 @@ def thread_worker_main(
127
127
  network_logger.info(f'Protocol upgraded to Websocket')
128
128
 
129
129
  def parse_websocket(raw_bytes):
130
- is_deflated = websocket_parse.is_frame_deflated(raw_bytes)
131
- request_decoded = websocket_frame_parser.parse_frame_bytes(raw_bytes)
132
-
133
- return {
134
- 'is_deflated': is_deflated,
135
- 'frame': request_decoded
136
- }
130
+ return websocket_frame_parser.parse_frame_bytes(raw_bytes)
137
131
 
138
132
  def finish_thread():
139
133
  # At this stage there could be several times that the same socket was used to the service server - we need to
@@ -149,6 +143,111 @@ def thread_worker_main(
149
143
 
150
144
  network_logger.info("Thread Finished. Will continue listening on the Main thread")
151
145
 
146
+ def process_client_raw_data_request() -> bool:
147
+ """
148
+ Process the client raw data request.
149
+
150
+ :return: True if the socket should be closed, False if not.
151
+ """
152
+
153
+ # If the message is empty, then the connection was closed already by the other side,
154
+ # so we can close the socket as well.
155
+ # If the received message from the client is not empty, then continue.
156
+ if not client_received_raw_data:
157
+ return True
158
+
159
+ # Putting the received message to the aggregating message class.
160
+ client_message.request_raw_bytes = client_received_raw_data
161
+
162
+ parse_http()
163
+ if protocol != '':
164
+ client_message.protocol = protocol
165
+
166
+ # Parse websocket frames only if it is not the first protocol upgrade request.
167
+ if protocol == 'Websocket' and cycle_count != 0:
168
+ client_message.request_raw_decoded = parse_websocket(client_message.request_raw_bytes)
169
+
170
+ # Custom parser, should parse HTTP body or the whole message if not HTTP.
171
+ parser_instance = parser(client_message)
172
+ parser_instance.parse()
173
+
174
+ # Converting body parsed to string on logging, since there is no strict rule for the parameter
175
+ # to be string.
176
+ parser_instance.logger.info(f"{str(client_message.request_body_parsed)[0: 100]}...")
177
+
178
+ return False
179
+
180
+ def create_responder_response():
181
+ # Since we're in response mode, we'll record the request anyway, after the responder did its job.
182
+ client_message.info = "In Server Response Mode"
183
+
184
+ # Re-initiate the 'client_message.response_list_of_raw_bytes' list, since we'll be appending
185
+ # new entries for empty list.
186
+ client_message.response_list_of_raw_bytes = list()
187
+
188
+ # If it's the first cycle and the protocol is Websocket, then we'll create the HTTP Handshake
189
+ # response automatically.
190
+ if protocol == 'Websocket' and cycle_count == 0:
191
+ client_message.response_list_of_raw_bytes.append(
192
+ websocket_parse.create_byte_http_response(client_message.request_raw_bytes))
193
+ # Creating response for parsed message and printing
194
+ responder.create_response(client_message)
195
+
196
+ # Output first 100 characters of all the responses in the list.
197
+ for response_raw_bytes_single in client_message.response_list_of_raw_bytes:
198
+ responder.logger.info(f"{response_raw_bytes_single[0: 100]}...")
199
+
200
+ def create_client_socket():
201
+ # If we're on localhost, then use external services list in order to resolve the domain:
202
+ # config['tcp']['forwarding_dns_service_ipv4_list___only_for_localhost']
203
+ if client_message.client_ip in base.THIS_DEVICE_IP_LIST:
204
+ service_client_instance = socket_client.SocketClient(
205
+ service_name=client_message.server_name, service_port=client_message.destination_port,
206
+ tls=is_tls,
207
+ dns_servers_list=(
208
+ config_static.TCPServer.forwarding_dns_service_ipv4_list___only_for_localhost),
209
+ logger=network_logger
210
+ )
211
+ # If we're not on localhost, then connect to domain directly.
212
+ else:
213
+ service_client_instance = socket_client.SocketClient(
214
+ service_name=client_message.server_name, service_port=client_message.destination_port,
215
+ tls=is_tls, logger=network_logger)
216
+
217
+ return service_client_instance
218
+
219
+ def process_received_response_from_service_client():
220
+ if client_message.error is not None:
221
+ statistics_error_list.append(client_message.error)
222
+
223
+ # Since we need a list for raw bytes, we'll add the 'response_raw_bytes' to our list object.
224
+ # But we need to re-initiate it first.
225
+ client_message.response_list_of_raw_bytes = list()
226
+ # If there was error during send or receive from the service and response was None,
227
+ # It means that there was no response at all because of the error.
228
+ if client_message.error and response_raw_bytes is None:
229
+ client_message.response_list_of_raw_bytes.append(None)
230
+ # If there was no error, but response came empty, it means that the service has closed the
231
+ # socket after it received the request, without sending any data.
232
+ elif client_message.error is None and response_raw_bytes is None:
233
+ client_message.response_list_of_raw_bytes.append("")
234
+ else:
235
+ client_message.response_list_of_raw_bytes.append(response_raw_bytes)
236
+
237
+ client_message.response_list_of_raw_decoded = list()
238
+ # Make HTTP Response parsing only if there was response at all.
239
+ if response_raw_bytes:
240
+ response_raw_decoded, is_http_response, response_parsing_error = (
241
+ HTTPResponseParse(response_raw_bytes).parse())
242
+
243
+ if is_http_response:
244
+ client_message.response_list_of_raw_decoded.append(response_raw_decoded)
245
+ elif protocol == 'Websocket' and cycle_count != 0:
246
+ response_decoded = parse_websocket(response_raw_bytes)
247
+ client_message.response_list_of_raw_decoded.append(response_decoded)
248
+ else:
249
+ client_message.response_list_of_raw_decoded.append(None)
250
+
152
251
  # Building client message object before the loop only for any exception to occurs, since we write it to
153
252
  # recording file in its current state.
154
253
  client_message: ClientMessage = ClientMessage()
@@ -197,6 +296,7 @@ def thread_worker_main(
197
296
  network_logger.info(f"Thread Created - Client [{client_ip}:{source_port}] | "
198
297
  f"Destination service: [{server_name}:{destination_port}]")
199
298
 
299
+ end_socket: bool = False
200
300
  service_client = None
201
301
  # Loop while received message is not empty, if so, close socket, since other side already closed.
202
302
  # noinspection PyTypeChecker
@@ -223,79 +323,34 @@ def thread_worker_main(
223
323
  # Getting current time of message received from client.
224
324
  client_message.request_time_received = datetime.now()
225
325
 
226
- network_logger.info(f"Initializing Receiver on cycle: {str(cycle_count+1)}")
227
- # Getting message from the client over the socket using specific class.
228
- client_received_raw_data = receiver.Receiver(
229
- ssl_socket=client_socket, logger=network_logger).receive()
230
-
231
- # If the message is empty, then the connection was closed already by the other side,
232
- # so we can close the socket as well.
233
- # If the received message from the client is not empty, then continue.
234
- if client_received_raw_data:
235
- # Putting the received message to the aggregating message class.
236
- client_message.request_raw_bytes = client_received_raw_data
237
-
238
- parse_http()
239
- if protocol != '':
240
- client_message.protocol = protocol
326
+ # Peek if there is some data in the socket.
327
+ # This is needed to check if the client just connects without sending data, if so we need to try and
328
+ # receive data from the server and send it to the client.
329
+ # We will do it only on the first cycle, after that the connection should work as usual.
330
+ # Sometimes the client will execute connection without sending data, just for the server to send response.
331
+ is_socket_ready: bool = True
332
+ if cycle_count == 0:
333
+ is_socket_ready = receiver.is_socket_ready_for_read(client_socket)
241
334
 
242
- # Parse websocket frames only if it is not the first protocol upgrade request.
243
- if protocol == 'Websocket' and cycle_count != 0:
244
- client_message.request_raw_decoded = parse_websocket(client_message.request_raw_bytes)
335
+ if is_socket_ready:
336
+ network_logger.info(f"Initializing Receiver on cycle: {str(cycle_count+1)}")
337
+ # Getting message from the client over the socket using specific class.
338
+ client_received_raw_data = receiver.Receiver(
339
+ ssl_socket=client_socket, logger=network_logger).receive()
245
340
 
246
- # Custom parser, should parse HTTP body or the whole message if not HTTP.
247
- parser_instance = parser(client_message)
248
- parser_instance.parse()
249
-
250
- # Converting body parsed to string on logging, since there is no strict rule for the parameter
251
- # to be string.
252
- parser_instance.logger.info(f"{str(client_message.request_body_parsed)[0: 100]}...")
341
+ end_socket = process_client_raw_data_request()
253
342
 
343
+ if not end_socket:
254
344
  # If we're in response mode, execute responder.
255
345
  response_raw_bytes = None
256
346
  if config_static.TCPServer.server_response_mode:
257
- # Since we're in response mode, we'll record the request anyway, after the responder did its job.
258
- client_message.info = "In Server Response Mode"
259
-
260
- # Re-initiate the 'client_message.response_list_of_raw_bytes' list, since we'll be appending
261
- # new entries for empty list.
262
- client_message.response_list_of_raw_bytes = list()
263
-
264
- # If it's the first cycle and the protocol is Websocket, then we'll create the HTTP Handshake
265
- # response automatically.
266
- if protocol == 'Websocket' and cycle_count == 0:
267
- client_message.response_list_of_raw_bytes.append(
268
- websocket_parse.create_byte_http_response(client_message.request_raw_bytes))
269
- # Creating response for parsed message and printing
270
- responder.create_response(client_message)
271
-
272
- # Output first 100 characters of all the responses in the list.
273
- for response_raw_bytes in client_message.response_list_of_raw_bytes:
274
- if response_raw_bytes:
275
- responder.logger.info(f"{response_raw_bytes[0: 100]}...")
276
- else:
277
- responder.logger.info(f"Response empty...")
347
+ create_responder_response()
278
348
  # Else, we're not in response mode, then execute client connect and record section.
279
349
  else:
280
350
  # If "service_client" object is not defined, we'll define it.
281
- # If it's defined, then it means there's still active "ssl_socket" with connection to the service
282
- # domain.
351
+ # If it's defined, then there's still active "ssl_socket" with connection to the service domain.
283
352
  if not service_client:
284
- # If we're on localhost, then use external services list in order to resolve the domain:
285
- # config['tcp']['forwarding_dns_service_ipv4_list___only_for_localhost']
286
- if client_message.client_ip in base.THIS_DEVICE_IP_LIST:
287
- service_client = socket_client.SocketClient(
288
- service_name=client_message.server_name, service_port=client_message.destination_port,
289
- tls=is_tls,
290
- dns_servers_list=(
291
- config_static.TCPServer.forwarding_dns_service_ipv4_list___only_for_localhost),
292
- logger=network_logger
293
- )
294
- # If we're not on localhost, then connect to domain directly.
295
- else:
296
- service_client = socket_client.SocketClient(
297
- service_name=client_message.server_name, service_port=client_message.destination_port,
298
- tls=is_tls, logger=network_logger)
353
+ service_client = create_client_socket()
299
354
 
300
355
  # Sending current client message and receiving a response.
301
356
  # If there was an error it will be passed to "client_message" object class and if not, "None" will
@@ -303,40 +358,9 @@ def thread_worker_main(
303
358
  # If there was connection error or socket close, then "ssl_socket" of the "service_client"
304
359
  # will be empty.
305
360
  response_raw_bytes, client_message.error, client_message.server_ip, service_ssl_socket = (
306
- service_client.send_receive_to_service(client_message.request_raw_bytes))
307
-
308
- if client_message.error is not None:
309
- statistics_error_list.append(client_message.error)
310
-
311
- # Since we need a list for raw bytes, we'll add the 'response_raw_bytes' to our list object.
312
- # But we need to re-initiate it first.
313
- client_message.response_list_of_raw_bytes = list()
314
- # If there was error during send or receive from the service and response was None,
315
- # It means that there was no response at all because of the error.
316
- if client_message.error and response_raw_bytes is None:
317
- client_message.response_list_of_raw_bytes.append(None)
318
- # If there was no error, but response came empty, it means that the service has closed the
319
- # socket after it received the request, without sending any data.
320
- elif client_message.error is None and response_raw_bytes is None:
321
- client_message.response_list_of_raw_bytes.append("")
322
- else:
323
- client_message.response_list_of_raw_bytes.append(response_raw_bytes)
324
-
325
- client_message.response_list_of_raw_decoded = list()
326
- # Make HTTP Response parsing only if there was response at all.
327
- if response_raw_bytes:
328
- response_raw_decoded, is_http_response, response_parsing_error = (
329
- HTTPResponseParse(response_raw_bytes).parse())
330
-
331
- if is_http_response:
332
- client_message.response_list_of_raw_decoded.append(response_raw_decoded)
333
- elif protocol == 'Websocket' and cycle_count != 0:
334
- response_decoded = parse_websocket(response_raw_bytes)
335
- client_message.response_list_of_raw_decoded.append(response_decoded)
336
- else:
337
- client_message.response_list_of_raw_decoded.append(None)
338
-
361
+ service_client.send_receive_to_service(client_message.request_raw_bytes, (not is_socket_ready)))
339
362
 
363
+ process_received_response_from_service_client()
340
364
 
341
365
  # So if the socket was closed and there was an error we can break the loop
342
366
  if not service_ssl_socket:
@@ -344,8 +368,8 @@ def thread_worker_main(
344
368
  recorded = True
345
369
  break
346
370
 
347
- # If there is a response, then send it.
348
- if response_raw_bytes:
371
+ # If there is a response(s), then send it.
372
+ if client_message.response_list_of_raw_bytes:
349
373
  # Sending response/s to client no matter if in record mode or not.
350
374
  network_logger.info(
351
375
  f"Sending messages to client: {len(client_message.response_list_of_raw_bytes)}")
@@ -368,7 +392,10 @@ def thread_worker_main(
368
392
 
369
393
  record_and_statistics_write()
370
394
  recorded = True
371
- else:
395
+
396
+ # If the message is empty, then the connection was closed already by the other side, also if there will
397
+ # be empty response from the server, so we can close the socket as well and exceptions will be raised.
398
+ if end_socket:
372
399
  # If it's the first cycle we will record the message from the client if it came empty.
373
400
  if cycle_count == 0:
374
401
  record_and_statistics_write()
@@ -376,6 +403,7 @@ def thread_worker_main(
376
403
  # In other cases, we'll just break the loop, since empty message means that the other side closed the
377
404
  # connection.
378
405
  recorded = True
406
+
379
407
  break
380
408
 
381
409
  finish_thread()
@@ -5,12 +5,9 @@ from pathlib import Path
5
5
  from .. import filesystem
6
6
  from ..file_io import tomls
7
7
  from ..basics.classes import import_first_class_name_from_file_path
8
- from ..wrappers.loggingw import loggingw
9
8
  from .engines.__reference_general import parser___reference_general, responder___reference_general, \
10
9
  recorder___reference_general
11
10
 
12
- from . import config_static
13
-
14
11
 
15
12
  class ModuleCategory:
16
13
  def __init__(self, script_directory: str):
@@ -1,7 +1,6 @@
1
1
  import datetime
2
2
  import os
3
3
  import multiprocessing
4
- from pathlib import Path
5
4
 
6
5
  from ..archiver import zips
7
6
  from .. import filesystem
@@ -1,8 +1,6 @@
1
- import json
2
1
  import inspect
3
2
 
4
3
  from ..wrappers.loggingw import loggingw
5
- from ..basics import dicts
6
4
 
7
5
  from . import config_static
8
6
 
File without changes
File without changes
@@ -0,0 +1,42 @@
1
+ import os
2
+
3
+ import google.generativeai as genai
4
+
5
+
6
+ class GoogleLLM:
7
+ def __init__(
8
+ self,
9
+ llm_api_key: str
10
+ ) -> None:
11
+ self.genai = genai
12
+
13
+ os.environ["API_KEY"] = llm_api_key
14
+ genai.configure(api_key=os.environ["API_KEY"])
15
+
16
+ def get_current_models(self) -> list[str]:
17
+ """ Function to get the current models available in the Gemini API """
18
+ result_list: list[str] = []
19
+ for model in self.genai.list_models():
20
+ result_list.append(model.name)
21
+
22
+ return result_list
23
+
24
+ def get_answer_online(
25
+ self,
26
+ search_query: str,
27
+ additional_llm_instructions: str,
28
+ number_of_top_links: int = 2,
29
+ number_of_characters_per_link: int = 15000,
30
+ temperature: float = 0,
31
+ max_output_tokens: int = 4096
32
+ ):
33
+ """
34
+ Function to get the answer to a question by searching Google Custom Console API and processing the content using Gemini API.
35
+ :param search_query:
36
+ :param additional_llm_instructions:
37
+ :param number_of_top_links:
38
+ :param number_of_characters_per_link:
39
+ :param temperature:
40
+ :param max_output_tokens:
41
+ :return:
42
+ """
@@ -129,15 +129,15 @@ class WebsocketFrameParser:
129
129
  def process_frame(current_frame):
130
130
  if current_frame.opcode == Opcode.TEXT:
131
131
  message = current_frame.data.decode('utf-8', errors='replace')
132
- return message
132
+ return message, 'TEXT'
133
133
  elif current_frame.opcode == Opcode.BINARY:
134
- return current_frame.data
134
+ return current_frame.data, 'BINARY'
135
135
  elif current_frame.opcode == Opcode.CLOSE:
136
- print("Received close frame")
136
+ return None, 'CLOSE'
137
137
  elif current_frame.opcode == Opcode.PING:
138
- print("Received ping")
138
+ return None, 'PING'
139
139
  elif current_frame.opcode == Opcode.PONG:
140
- print("Received pong")
140
+ return None, 'PONG'
141
141
  else:
142
142
  raise WebsocketParseWrongOpcode("Received unknown frame with opcode:", current_frame.opcode)
143
143
 
@@ -152,12 +152,19 @@ class WebsocketFrameParser:
152
152
 
153
153
  # Parse and process frames
154
154
  frame = parse_frame(masked, deflated)
155
- result = process_frame(frame)
155
+ parsed_frame, frame_opcode = process_frame(frame)
156
156
 
157
157
  # This is basically not needed since we restart the 'reader = StreamReader()' each function execution.
158
158
  # # After processing, reset the reader's buffer
159
159
  # reader.buffer = b''
160
160
 
161
+ result: dict = {
162
+ 'is_deflated': deflated,
163
+ 'is_masked': masked,
164
+ 'frame': parsed_frame,
165
+ 'opcode': frame_opcode
166
+ }
167
+
161
168
  return result
162
169
 
163
170
 
@@ -40,8 +40,7 @@ def install_fibratus(
40
40
  exclude_string='slim')
41
41
 
42
42
  # Install the MSI file
43
- msiw.install_msi(
44
- msi_path=fibratus_setup_file_path, exit_on_error=True, as_admin=True)
43
+ msiw.install_msi(msi_path=fibratus_setup_file_path)
45
44
 
46
45
  count = 0
47
46
  while count != WAIT_SECONDS_FOR_EXECUTABLE_TO_APPEAR_AFTER_INSTALLATION:
@@ -1,6 +1,7 @@
1
1
  import logging
2
2
  import socket
3
3
  import ssl
4
+ import select
4
5
  from pathlib import Path
5
6
 
6
7
  from ...print_api import print_api
@@ -20,6 +21,24 @@ def peek_first_bytes(client_socket, bytes_amount: int = 1) -> bytes:
20
21
  return client_socket.recv(bytes_amount, socket.MSG_PEEK)
21
22
 
22
23
 
24
+ def is_socket_ready_for_read(client_socket, timeout: int = 0) -> bool:
25
+ """
26
+ Check if socket is ready for read.
27
+
28
+ :param client_socket: Socket object.
29
+ :param timeout: Timeout in seconds. The default is no timeout.
30
+
31
+ :return: True if socket is ready for read, False otherwise.
32
+ """
33
+
34
+ # Use select to check if the socket is ready for reading.
35
+ # 'readable' returns a list of sockets that are ready for reading.
36
+ # Since we use only one socket, it will return a list with one element if the socket is ready for reading,
37
+ # or an empty list if the socket is not ready for reading.
38
+ readable, _, _ = select.select([client_socket], [], [], timeout)
39
+ return bool(readable)
40
+
41
+
23
42
  class Receiver:
24
43
  """ Receiver Class is responsible for receiving the message from socket and populate the message class """
25
44
  def __init__(
@@ -6,7 +6,7 @@ from ...print_api import print_api
6
6
  from ..loggingw import loggingw
7
7
  from ...basics import tracebacks
8
8
 
9
- from . import base, ssl_base
9
+ from . import base
10
10
 
11
11
 
12
12
  class Sender:
@@ -254,15 +254,13 @@ class SNIHandler:
254
254
 
255
255
  # Try on general settings in the SNI function.
256
256
  try:
257
- # Check if SNI was passed.
258
- if self.sni_received_parameters.destination_name:
259
- service_name_from_sni = self.sni_received_parameters.destination_name
260
- # If no SNI was passed.
261
- else:
257
+ # Check if SNI was passed. If no SNI was passed.
258
+ if not self.sni_received_parameters.destination_name:
262
259
  # If DNS server is enabled we'll get the domain from dns server.
263
260
  if self.domain_from_dns_server:
264
- service_name_from_sni = self.domain_from_dns_server
265
- message = f"SNI Handler: No SNI was passed, using domain from DNS Server: {service_name_from_sni}"
261
+ self.sni_received_parameters.destination_name = self.domain_from_dns_server
262
+ message = \
263
+ f"SNI Handler: No SNI was passed, using domain from DNS Server: {self.domain_from_dns_server}"
266
264
  print_api(message, **(print_kwargs or {}))
267
265
  # If DNS server is disabled, the domain from dns server will be empty.
268
266
  else:
@@ -271,7 +269,7 @@ class SNIHandler:
271
269
  print_api(message, **(print_kwargs or {}))
272
270
 
273
271
  # Setting "server_hostname" as a domain.
274
- self.sni_received_parameters.ssl_socket.server_hostname = service_name_from_sni
272
+ self.sni_received_parameters.ssl_socket.server_hostname = self.sni_received_parameters.destination_name
275
273
  message = \
276
274
  f"SNI Handler: port {self.sni_received_parameters.ssl_socket.getsockname()[1]}: " \
277
275
  f"Incoming connection for [{self.sni_received_parameters.ssl_socket.server_hostname}]"
@@ -163,7 +163,7 @@ class SocketClient:
163
163
  error_string: str = f"Socket Client Connect: {destination}: {exception_type}"
164
164
 
165
165
  if exception_type in ['ConnectionRefusedError', 'ConnectionAbortedError', 'ConnectionResetError',
166
- 'ssl.SSLError', 'TimeoutError']:
166
+ 'TimeoutError'] or 'ssl' in exception_type.lower():
167
167
  error_message: str = f"{error_string}: {exception_error}"
168
168
  print_api(error_message, logger=self.logger, logger_method='error')
169
169
  return None, error_message
@@ -192,7 +192,18 @@ class SocketClient:
192
192
  self.logger.info(f"Closed socket to service server [{self.service_name}:{self.service_port}]")
193
193
 
194
194
  # noinspection PyUnusedLocal
195
- def send_receive_to_service(self, request_bytes: bytearray):
195
+ def send_receive_to_service(
196
+ self,
197
+ request_bytes: Union[bytearray, bytes],
198
+ skip_send: bool = False
199
+ ):
200
+ """
201
+ Function to send data to service server and receive response.
202
+
203
+ :param request_bytes: The data that will be sent to the service server.
204
+ :param skip_send: If True, the data will not be sent to the service server. After the connection is established,
205
+ the function will wait for the response only.
206
+ """
196
207
  # Define variables
197
208
  function_service_data = None
198
209
  error_message = None
@@ -214,18 +225,22 @@ class SocketClient:
214
225
  self.logger.info(
215
226
  f"[{self.service_name}] resolves to ip: [{self.connection_ip}]. Pulled IP from the socket.")
216
227
 
217
- # Send the data received from the client to the service over socket
218
- error_on_send: str = Sender(
219
- ssl_socket=self.socket_instance, class_message=request_bytes, logger=self.logger).send()
228
+ # noinspection PyTypeChecker
229
+ error_on_send: str = None
230
+ if not skip_send:
231
+ # Send the data received from the client to the service over socket
232
+ error_on_send = Sender(
233
+ ssl_socket=self.socket_instance, class_message=request_bytes, logger=self.logger).send()
220
234
 
221
- # If the socket disconnected on data send
222
- if error_on_send:
223
- error_message = f"Service socket closed on data send: {error_on_send}"
235
+ # If the socket disconnected on data send
236
+ if error_on_send:
237
+ error_message = f"Service socket closed on data send: {error_on_send}"
238
+
239
+ # We'll close the socket and nullify the object
240
+ self.close_socket()
224
241
 
225
- # We'll close the socket and nullify the object
226
- self.close_socket()
227
242
  # Else if send was successful
228
- else:
243
+ if not error_on_send:
229
244
  function_service_data = Receiver(
230
245
  ssl_socket=self.socket_instance, logger=self.logger).receive()
231
246
 
@@ -49,7 +49,7 @@ def is_sysmon_running():
49
49
  """
50
50
 
51
51
  process_list: list = process.get_running_processes_by_cmdline_pattern(
52
- pattern=SYSMON_FILE_NAME, first=True, process_name_case_insensitive=True)
52
+ pattern=SYSMON_FILE_NAME, first=True, cmdline_case_insensitive=True)
53
53
 
54
54
  if process_list:
55
55
  return True
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: atomicshop
3
- Version: 2.16.45
3
+ Version: 2.16.48
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=fBF5eT1cIzArZVWu2launQIsr0jJhGhMkV0tYXx0zf4,124
1
+ atomicshop/__init__.py,sha256=g4si8ZVmv-cmrXDPNTeEfgvWGFAXNNlfF5E-_j8xNMo,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
@@ -9,7 +9,7 @@ atomicshop/config_init.py,sha256=50kD2lXP8sgwPekcmAbfADcY46YvXkF-6XIdA7W_638,250
9
9
  atomicshop/console_output.py,sha256=AOSJjrRryE97PAGtgDL03IBtWSi02aNol8noDnW3k6M,4667
10
10
  atomicshop/console_user_response.py,sha256=31HIy9QGXa7f-GVR8MzJauQ79E_ZqAeagF3Ks4GGdDU,3234
11
11
  atomicshop/datetimes.py,sha256=IQZ66lmta-ZqxYbyHzm_9eugbJFSilXK1e0kfMgoXGg,18371
12
- atomicshop/diff_check.py,sha256=Q9RCqRa-jEgo7Fujx08_JTuZ6qcgttMI6aNYB6zN9Ik,27173
12
+ atomicshop/diff_check.py,sha256=vxTDccVbGZHEge6Ja9_ArLWwslOUgIoJAdYPylh4cZg,27176
13
13
  atomicshop/dns.py,sha256=5Gimq_WY2arqg7BeGmR7P--fGfnH0Dsh8lrOt_H0jRY,6817
14
14
  atomicshop/domains.py,sha256=Rxu6JhhMqFZRcoFs69IoEd1PtYca0lMCG6F1AomP7z4,3197
15
15
  atomicshop/emails.py,sha256=I0KyODQpIMEsNRi9YWSOL8EUPBiWyon3HRdIuSj3AEU,1410
@@ -45,7 +45,7 @@ atomicshop/urls.py,sha256=aJ0NGS9qqaKeqjkkWBs80jaBBg6MYBiPuLIyPGxscVc,1557
45
45
  atomicshop/uuids.py,sha256=JSQdm3ZTJiwPQ1gYe6kU0TKS_7suwVrHc8JZDGYlydM,2214
46
46
  atomicshop/virtualization.py,sha256=LPP4vjE0Vr10R6DA4lqhfX_WaNdDGRAZUW0Am6VeGco,494
47
47
  atomicshop/web.py,sha256=GLdTXgMxg1_0UQaXC4bOvARVyuFg7SPIeJdsCHV8rNE,11662
48
- atomicshop/websocket_parse.py,sha256=chqR3NSuW5Ndtclzj-46jCuQbyTh6umm1PBKvSkDzXw,16456
48
+ atomicshop/websocket_parse.py,sha256=bkOwiXCNw5bQg1J4KOG7es5kUGysyX2NdfFFVBceSzg,16662
49
49
  atomicshop/a_installs/ubuntu/docker_rootless.py,sha256=9IPNtGZYjfy1_n6ZRt7gWz9KZgR6XCgevjqq02xk-o0,281
50
50
  atomicshop/a_installs/ubuntu/docker_sudo.py,sha256=JzayxeyKDtiuT4Icp2L2LyFRbx4wvpyN_bHLfZ-yX5E,281
51
51
  atomicshop/a_installs/ubuntu/elastic_search_and_kibana.py,sha256=yRB-l1zBxdiN6av-FwNkhcBlaeu4zrDPjQ0uPGgpK2I,244
@@ -126,13 +126,13 @@ atomicshop/file_io/xmls.py,sha256=zh3SuK-dNaFq2NDNhx6ivcf4GYCfGM8M10PcEwDSpxk,21
126
126
  atomicshop/mitm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
127
127
  atomicshop/mitm/config_static.py,sha256=ROAtbibSWSsF3BraUbhu-QO3MPIFqYY5KUKgsQbiSkk,7813
128
128
  atomicshop/mitm/config_toml_editor.py,sha256=2p1CMcktWRR_NW-SmyDwylu63ad5e0-w1QPMa8ZLDBw,1635
129
- atomicshop/mitm/connection_thread_worker.py,sha256=J2fYJZS1IuibvvNmeIsm4hkJMxokQFbBk9xwMGjT7YE,19958
129
+ atomicshop/mitm/connection_thread_worker.py,sha256=vfFClzwDfaoT4zHCOfky4DnEDoSonp9N1MCj62dS9Nk,20451
130
130
  atomicshop/mitm/import_config.py,sha256=0Ij14aISTllTOiWYJpIUMOWobQqGofD6uafui5uWllE,9272
131
- atomicshop/mitm/initialize_engines.py,sha256=VyJE8QnzlgD3QbX5inz5o6rC3zQ3is9CeTL7-B10g1w,8292
131
+ atomicshop/mitm/initialize_engines.py,sha256=Naseof9JGY7oxDz9ueOyW7-KYTu7QDlFxv2ABqq9DD4,8219
132
132
  atomicshop/mitm/message.py,sha256=URR5JKSuAT8XmGIkyprEjlPW2GW4ef_gfUz_GgcFseE,2184
133
133
  atomicshop/mitm/mitm_main.py,sha256=5c-9oxBiLueTbZr4Dyd4EEOorEUix5vSWxX9p5O1fBs,23375
134
- atomicshop/mitm/recs_files.py,sha256=mMyO1kPB-VkS_pbWCDhZHKdbWzlPbYSout61QuzHOao,3077
135
- atomicshop/mitm/shared_functions.py,sha256=l6oEyv4ug5D_03V3QLADYoocbcL2Ml_dYVW2WKM21l4,1818
134
+ atomicshop/mitm/recs_files.py,sha256=gzFuTonqcXkMvhpOj1Nwse3E8umFGrKN2H5AleMjJ3w,3051
135
+ atomicshop/mitm/shared_functions.py,sha256=0lzeyINd44sVEfFbahJxQmz6KAMWbYrW5ou3UYfItvw,1777
136
136
  atomicshop/mitm/statistic_analyzer.py,sha256=5_sAYGX2Xunzo_pS2W5WijNCwr_BlGJbbOO462y_wN4,27533
137
137
  atomicshop/mitm/engines/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
138
138
  atomicshop/mitm/engines/create_module_template.py,sha256=tRjVSm1sD6FzML71Qbuwvita0qsusdFGm8NZLsZ-XMs,4853
@@ -175,6 +175,9 @@ atomicshop/startup/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuF
175
175
  atomicshop/startup/win/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
176
176
  atomicshop/startup/win/startup_folder.py,sha256=2RZEyF-Mf8eWPlt_-OaoGKKnMs6YhELEzJZ376EI0E0,1891
177
177
  atomicshop/startup/win/task_scheduler.py,sha256=qALe-8sfthYxsdCViH2r8OsH3x-WauDqteg5RzElPdk,4348
178
+ atomicshop/web_apis/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
179
+ atomicshop/web_apis/google_custom_search.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
180
+ atomicshop/web_apis/google_llm.py,sha256=WVLqyfZHFIGEncxdBvrHCv2FbvQw40z75uMGzq9lxB4,1291
178
181
  atomicshop/wrappers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
179
182
  atomicshop/wrappers/_process_wrapper_curl.py,sha256=XkZZXYl7D0Q6UfdWqy-18AvpU0yVp9i2BVD2qRcXlkk,841
180
183
  atomicshop/wrappers/_process_wrapper_tar.py,sha256=WUMZFKNrlG4nJP9tWZ51W7BR1j_pIjsjgyAStmWjRGs,655
@@ -189,7 +192,7 @@ atomicshop/wrappers/olefilew.py,sha256=biD5m58rogifCYmYhJBrAFb9O_Bn_spLek_9HofLe
189
192
  atomicshop/wrappers/pipw.py,sha256=mu4jnHkSaYNfpBiLZKMZxEX_E2LqW5BVthMZkblPB_c,1317
190
193
  atomicshop/wrappers/process_wrapper_pbtk.py,sha256=ycPmBRnv627RWks6N8OhxJQe8Gu3h3Vwj-4HswPOw0k,599
191
194
  atomicshop/wrappers/pyopensslw.py,sha256=OBWxA6EJ2vU_Qlf4M8m6ilcG3hyYB4yB0EsXUf7NhEU,6804
192
- atomicshop/wrappers/sysmonw.py,sha256=MFF8ts0gHbXn2_QeH196UncOUtm4MnM2cQBzTOnfrnk,5351
195
+ atomicshop/wrappers/sysmonw.py,sha256=CdawuWuy_uUi3ALCm6lKP7pSyKeTk1MXyzOaTMbBSO8,5346
193
196
  atomicshop/wrappers/ubuntu_terminal.py,sha256=3UJaje_Ke5G9xEyj3b37XZ_KjR_FSSnb4gupdCyI-jE,11965
194
197
  atomicshop/wrappers/wslw.py,sha256=2Z7X0j5M2hoRZjbHfm_vqwNXZeptsdkNCdhdcM_S9vo,6998
195
198
  atomicshop/wrappers/certauthw/certauth.py,sha256=hKedW0DOWlEigSNm8wu4SqHkCQsGJ1tJfH7s4nr3Bk0,12223
@@ -246,7 +249,7 @@ atomicshop/wrappers/factw/rest/router.py,sha256=fdGok5ESBxcZHIBgM93l4yTPRGoeooQN
246
249
  atomicshop/wrappers/factw/rest/statistics.py,sha256=vznwzKP1gEF7uXz3HsuV66BU9wrp73N_eFqpFpye9Qw,653
247
250
  atomicshop/wrappers/factw/rest/status.py,sha256=4O3xS1poafwyUiLDkhyx4oMMe4PBwABuRPpOMnMKgIU,641
248
251
  atomicshop/wrappers/fibratusw/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
249
- atomicshop/wrappers/fibratusw/install.py,sha256=PLVymDe0HuOvU0r2lje8BkQAgtiOWEeRO7n-1zKuL7A,3287
252
+ atomicshop/wrappers/fibratusw/install.py,sha256=GnaAAqcXRhovxZ3x5uB9RAXTMCh5xd5k1niCKTzh4Z0,3242
250
253
  atomicshop/wrappers/loggingw/consts.py,sha256=JWiUJEydjhwatBxtIJsGTmDUSTLbmIRidtR6qRLMaIY,1608
251
254
  atomicshop/wrappers/loggingw/filters.py,sha256=48UVhJHemCS0agXmQP8dHvAHM8r9DFphJ1TNEBP3Dlg,3545
252
255
  atomicshop/wrappers/loggingw/formatters.py,sha256=ZY12IokVY1G_Wzn2Zlv9qjK-e8CtIK6yUgUfPHvH2BU,5802
@@ -305,18 +308,18 @@ atomicshop/wrappers/socketw/creator.py,sha256=3_OraDkw2DAWZfoSdY3svCGMOIxpjLEEY7
305
308
  atomicshop/wrappers/socketw/dns_server.py,sha256=RklzINNuoMQn4PGGQEI5hiAldprbVwwvikY6u9X-jTY,49067
306
309
  atomicshop/wrappers/socketw/exception_wrapper.py,sha256=B-X5SHLSUIWToihH2MKnOB1F4A81_X0DpLLfnYKYbEc,7067
307
310
  atomicshop/wrappers/socketw/get_process.py,sha256=aJC-_qFUv3NgWCSUzDI72E4z8_-VTZE9NVZ0CwUoNlM,5698
308
- atomicshop/wrappers/socketw/receiver.py,sha256=XVvWOoeCo3vA0O5p19ryi-hcDIyx382WNG7WzMNVeYk,9322
309
- atomicshop/wrappers/socketw/sender.py,sha256=vjgU1TaADJjaYiZOkLzfxcdCbmkvjhEhVjSV5mmIbw8,4969
310
- atomicshop/wrappers/socketw/sni.py,sha256=J1kPnQ77XwKN1pO5aOI1c_VfhuivCm95OOaQxMpPuZ0,17627
311
- atomicshop/wrappers/socketw/socket_client.py,sha256=zDX7M3KfUOn0tXR92gZ119HVFgA8N_0ppQxfxVqNvKc,19867
311
+ atomicshop/wrappers/socketw/receiver.py,sha256=-QtKK0T_lmoAIypTYaIKOD3pgB1npWGPxcVEN37y_gk,10060
312
+ atomicshop/wrappers/socketw/sender.py,sha256=gwSzF51QD5paeeFav6fpbQpO8KgBO5lNztHYQyN5id0,4959
313
+ atomicshop/wrappers/socketw/sni.py,sha256=Nc8WMZZR21o5GXILQLVWbf7OzNPXAfE8trJY153e9Qk,17591
314
+ atomicshop/wrappers/socketw/socket_client.py,sha256=9_VXXo8r4upP5v0Rhzx7dJIblM23_0Ggh2PfktYj-fE,20489
312
315
  atomicshop/wrappers/socketw/socket_server_tester.py,sha256=Qobmh4XV8ZxLUaw-eW4ESKAbeSLecCKn2OWFzMhadk0,6420
313
316
  atomicshop/wrappers/socketw/socket_wrapper.py,sha256=WtylpezgIIBuz-A6PfM0hO1sm9Exd4j3qhDXcFc74-E,35567
314
317
  atomicshop/wrappers/socketw/ssl_base.py,sha256=kmiif84kMhBr5yjQW17p935sfjR5JKG0LxIwBA4iVvU,2275
315
318
  atomicshop/wrappers/socketw/statistics_csv.py,sha256=SDYI1cN0oaapvPeLxSXiJrelTy6xbZl-bopR0jAjVGE,3149
316
319
  atomicshop/wrappers/winregw/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
317
320
  atomicshop/wrappers/winregw/winreg_network.py,sha256=zZQfps-CdODQaTUADbHAwKHr5RUg7BLafnKWBbKaLN4,8728
318
- atomicshop-2.16.45.dist-info/LICENSE.txt,sha256=lLU7EYycfYcK2NR_1gfnhnRC8b8ccOTElACYplgZN88,1094
319
- atomicshop-2.16.45.dist-info/METADATA,sha256=E-QukR4G1Pts-0XCHJeKddzx3V2jaC6C5eLog6UU0Kw,10500
320
- atomicshop-2.16.45.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
321
- atomicshop-2.16.45.dist-info/top_level.txt,sha256=EgKJB-7xcrAPeqTRF2laD_Np2gNGYkJkd4OyXqpJphA,11
322
- atomicshop-2.16.45.dist-info/RECORD,,
321
+ atomicshop-2.16.48.dist-info/LICENSE.txt,sha256=lLU7EYycfYcK2NR_1gfnhnRC8b8ccOTElACYplgZN88,1094
322
+ atomicshop-2.16.48.dist-info/METADATA,sha256=zxLRU6GxTBO675CZCx48ARUCy2CYk9CTkD-0jhyE3AQ,10500
323
+ atomicshop-2.16.48.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
324
+ atomicshop-2.16.48.dist-info/top_level.txt,sha256=EgKJB-7xcrAPeqTRF2laD_Np2gNGYkJkd4OyXqpJphA,11
325
+ atomicshop-2.16.48.dist-info/RECORD,,