atomicshop 2.16.43__py3-none-any.whl → 2.16.44__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.43'
4
+ __version__ = '2.16.44'
@@ -75,7 +75,7 @@ def search_for_hyperlink_in_files(directory_path: str, hyperlink: str, relative_
75
75
 
76
76
  # Get all the docx files in the specified directory.
77
77
  files = filesystem.get_paths_from_directory(
78
- directory_path, get_file=True, file_name_check_pattern="*\.docx",
78
+ directory_path, get_file=True, file_name_check_pattern="*.docx",
79
79
  add_relative_directory=True, relative_file_name_as_directory=True)
80
80
 
81
81
  found_in_files: list = list()
@@ -1,18 +1,256 @@
1
- from typing import Union
1
+ from typing import Union, Generator
2
2
  import logging
3
3
 
4
4
  from websockets.server import ServerProtocol
5
5
  from websockets.client import ClientProtocol
6
- from websockets.extensions.permessage_deflate import ServerPerMessageDeflateFactory, ClientPerMessageDeflateFactory
6
+ from websockets.extensions.permessage_deflate import PerMessageDeflate, ServerPerMessageDeflateFactory, ClientPerMessageDeflateFactory
7
7
  from websockets.http11 import Request, Response
8
- from websockets.frames import Frame, Opcode, Close
8
+ from websockets.frames import Frame, Opcode
9
9
  from websockets.uri import parse_uri
10
10
  from websockets.exceptions import InvalidHeaderValue
11
11
  from websockets.protocol import OPEN
12
+ from websockets.streams import StreamReader
13
+ from websockets.exceptions import ProtocolError, PayloadTooBig
12
14
 
13
15
 
14
- class WebsocketRequestParse:
16
+ class WebsocketParseWrongOpcode(Exception):
17
+ pass
18
+
19
+
20
+ def create_byte_http_response(
21
+ byte_http_request: Union[bytes, bytearray],
22
+ enable_logging: bool = False
23
+ ) -> bytes:
24
+ """
25
+ Create a byte HTTP response from a byte HTTP request.
26
+
27
+ Parameters:
28
+ - byte_http_request (bytes, bytearray): The byte HTTP request.
29
+ - enable_logging (bool): Whether to enable logging.
30
+
31
+ Returns:
32
+ - bytes: The byte HTTP response.
33
+ """
34
+
35
+ # Set up extensions
36
+ permessage_deflate_factory = ServerPerMessageDeflateFactory()
37
+
38
+ # Create the protocol instance
39
+ protocol = ServerProtocol(
40
+ extensions=[permessage_deflate_factory],
41
+ )
42
+ # At this state the protocol.state is State.CONNECTING
43
+
44
+ if enable_logging:
45
+ logging.basicConfig(level=logging.DEBUG)
46
+ protocol.logger.setLevel(logging.DEBUG)
47
+
48
+
49
+ protocol.receive_data(byte_http_request)
50
+ events = protocol.events_received()
51
+ event = events[0]
52
+ if isinstance(event, Request):
53
+ # Accept the handshake.
54
+ # After the response is sent, it means the handshake was successful, the protocol.state is State.OPEN
55
+ # Only after this state we can parse frames.
56
+ response = protocol.accept(event)
57
+ return response.serialize()
58
+ else:
59
+ raise ValueError("The event is not a Request object.")
60
+
61
+
62
+ def parse_frame_bytes(data_bytes: bytes):
63
+ # Define the read_exact function
64
+ def read_exact(n: int) -> Generator[None, None, bytes]:
65
+ return reader.read_exact(n)
66
+
67
+ # Helper function to run generator-based coroutines
68
+ def run_coroutine(coroutine):
69
+ try:
70
+ while True:
71
+ next(coroutine)
72
+ except StopIteration as e:
73
+ return e.value
74
+ except Exception as e:
75
+ raise e # Re-raise exceptions to be handled by the caller
76
+
77
+ # Function to parse frames
78
+ def parse_frame(mask: bool):
79
+ try:
80
+ # Use Frame.parse to parse the frame
81
+ frame_parser = Frame.parse(
82
+ read_exact,
83
+ mask=mask, # Client frames are masked
84
+ max_size=None,
85
+ extensions=[permessage_deflate], # Include the extension unconditionally
86
+ )
87
+ current_frame = run_coroutine(frame_parser)
88
+ except EOFError as e:
89
+ # Not enough data to parse a complete frame
90
+ raise e
91
+ except (ProtocolError, PayloadTooBig) as e:
92
+ print("Error parsing frame:", e)
93
+ raise e
94
+ except Exception as e:
95
+ print("Error parsing frame:", e)
96
+ raise e
97
+ return current_frame
98
+
99
+ def process_frame(current_frame):
100
+ if current_frame.opcode == Opcode.TEXT:
101
+ message = current_frame.data.decode('utf-8', errors='replace')
102
+ return message
103
+ elif current_frame.opcode == Opcode.BINARY:
104
+ return current_frame.data
105
+ elif current_frame.opcode == Opcode.CLOSE:
106
+ print("Received close frame")
107
+ elif current_frame.opcode == Opcode.PING:
108
+ print("Received ping")
109
+ elif current_frame.opcode == Opcode.PONG:
110
+ print("Received pong")
111
+ else:
112
+ raise WebsocketParseWrongOpcode("Received unknown frame with opcode:", current_frame.opcode)
113
+
114
+ # Create the StreamReader instance
115
+ reader = StreamReader()
116
+
117
+ # Instantiate the permessage-deflate extension
118
+ permessage_deflate = PerMessageDeflate(
119
+ remote_no_context_takeover=False,
120
+ local_no_context_takeover=False,
121
+ remote_max_window_bits=15,
122
+ local_max_window_bits=15,
123
+ )
124
+
125
+ masked = is_frame_masked(data_bytes)
126
+
127
+ # Feed the data into the reader
128
+ reader.feed_data(data_bytes)
129
+
130
+ # Parse and process frames
131
+ frame = parse_frame(masked)
132
+ result = process_frame(frame)
133
+ return result
134
+
135
+
136
+ def create_websocket_frame(
137
+ data: Union[str, bytes, bytearray],
138
+ deflate: bool = False,
139
+ mask: bool = False,
140
+ opcode: int = None
141
+ ) -> bytes:
142
+ """
143
+ Create a WebSocket frame with the given data, optionally applying
144
+ permessage-deflate compression and masking.
145
+
146
+ Parameters:
147
+ - data (str, bytes, bytearray): The payload data.
148
+ If str, it will be encoded to bytes using UTF-8.
149
+ - deflate (bool): Whether to apply permessage-deflate compression.
150
+ - mask (bool): Whether to apply masking to the frame.
151
+ - opcode (int): The opcode of the frame. If not provided, it will be
152
+ determined based on the type of data.
153
+ Example:
154
+ from websockets.frames import Opcode
155
+ Opcode.TEXT, Opcode.BINARY, Opcode.CLOSE, Opcode.PING, Opcode.PONG.
156
+
157
+ Returns:
158
+ - bytes: The serialized WebSocket frame ready to be sent.
159
+ """
160
+
161
+ # Determine the opcode if not provided
162
+ if opcode is None:
163
+ if isinstance(data, str):
164
+ opcode = Opcode.TEXT
165
+ elif isinstance(data, (bytes, bytearray)):
166
+ opcode = Opcode.BINARY
167
+ else:
168
+ raise TypeError("Data must be of type str, bytes, or bytearray.")
169
+ else:
170
+ if not isinstance(opcode, int):
171
+ raise TypeError("Opcode must be an integer.")
172
+ if not isinstance(data, (str, bytes, bytearray)):
173
+ raise TypeError("Data must be of type str, bytes, or bytearray.")
174
+
175
+ # Encode string data if necessary
176
+ if isinstance(data, str):
177
+ payload = data.encode('utf-8')
178
+ else:
179
+ payload = bytes(data)
180
+
181
+ # Create the Frame instance
182
+ frame = Frame(opcode=opcode, data=payload)
183
+
184
+ # Set up extensions if deflate is True
185
+ extensions = []
186
+ if deflate:
187
+ permessage_deflate = PerMessageDeflate(
188
+ remote_no_context_takeover=False,
189
+ local_no_context_takeover=False,
190
+ remote_max_window_bits=15,
191
+ local_max_window_bits=15,
192
+ )
193
+ extensions.append(permessage_deflate)
194
+
195
+ # Serialize the frame with the specified options
196
+ try:
197
+ frame_bytes = frame.serialize(
198
+ mask=mask,
199
+ extensions=extensions,
200
+ )
201
+ except Exception as e:
202
+ raise RuntimeError(f"Error serializing frame: {e}")
203
+
204
+ return frame_bytes
205
+
206
+
207
+ def is_frame_masked(frame_bytes):
208
+ """
209
+ Determine whether a WebSocket frame is masked.
210
+
211
+ Parameters:
212
+ - frame_bytes (bytes): The raw bytes of the WebSocket frame.
213
+
214
+ Returns:
215
+ - bool: True if the frame is masked, False otherwise.
216
+ """
217
+ if len(frame_bytes) < 2:
218
+ raise ValueError("Frame is too short to determine masking.")
219
+
220
+ # The second byte of the frame header contains the MASK bit
221
+ second_byte = frame_bytes[1]
222
+
223
+ # The MASK bit is the most significant bit (MSB) of the second byte
224
+ mask_bit = (second_byte & 0x80) != 0 # 0x80 is 1000 0000 in binary
225
+
226
+ return mask_bit
227
+
228
+
229
+ def is_frame_deflated(frame_bytes):
230
+ """
231
+ Determine whether a WebSocket frame is deflated (compressed).
232
+
233
+ Parameters:
234
+ - frame_bytes (bytes): The raw bytes of the WebSocket frame.
235
+
236
+ Returns:
237
+ - bool: True if the frame is deflated (compressed), False otherwise.
238
+ """
239
+ if len(frame_bytes) < 1:
240
+ raise ValueError("Frame is too short to determine deflation status.")
241
+
242
+ # The first byte of the frame header contains the RSV1 bit
243
+ first_byte = frame_bytes[0]
244
+
245
+ # The RSV1 bit is the second most significant bit (bit 6)
246
+ rsv1 = (first_byte & 0x40) != 0 # 0x40 is 0100 0000 in binary
247
+
248
+ return rsv1
249
+
250
+
251
+ class _WebsocketRequestParse:
15
252
  """
253
+ THIS IS ONLY FOR THE REFERENCE IT IS NOT CURRENTLY USED OR SHOULD BE USED.
16
254
  Parse the websocket request and return the data
17
255
  """
18
256
  def __init__(
@@ -85,8 +323,9 @@ class WebsocketRequestParse:
85
323
  """
86
324
 
87
325
 
88
- class WebsocketResponseParse:
326
+ class _WebsocketResponseParse:
89
327
  """
328
+ THIS IS ONLY FOR THE REFERENCE IT IS NOT CURRENTLY USED OR SHOULD BE USED.
90
329
  Parse the websocket response and return the data
91
330
  """
92
331
  def __init__(
@@ -1,10 +1,35 @@
1
1
  from typing import Union, Literal
2
2
  from pathlib import Path
3
3
 
4
- from .... import process, filesystem
4
+ from .... import process, print_api
5
5
  from .. import config_install
6
6
 
7
7
 
8
+ PLUGIN_LIST: list = [
9
+ 'qemu_exec',
10
+ 'binwalk',
11
+ 'users_and_passwords',
12
+ 'kernel_config',
13
+ 'cve_lookup',
14
+ 'crypto_hints',
15
+ 'input_vectors',
16
+ 'cwe_checker',
17
+ 'linter',
18
+ 'ip_and_uri_finder',
19
+ 'device_tree',
20
+ 'file_system_metadata',
21
+ 'ipc',
22
+ 'software_components',
23
+ 'architecture_detection',
24
+ 'known_vulnerabilities'
25
+ ]
26
+
27
+
28
+ INSTALLING_STRINGS: list = ['Installing', 'plugin']
29
+ FINISHED_INSTALLING_STRINGS: list = ['Finished installing', 'plugin']
30
+ LOG_FINISHED_STRING: str = 'installation complete'
31
+
32
+
8
33
  def install_after_restart(
9
34
  installation_directory: str,
10
35
  install_type: Union[
@@ -12,8 +37,12 @@ def install_after_restart(
12
37
  Literal['backend', 'frontend', 'db']] = None,
13
38
  log_level: Union[
14
39
  None,
15
- Literal['DEBUG', 'INFO', 'WARNING', 'ERROR']] = None
16
- ):
40
+ Literal['DEBUG', 'INFO', 'WARNING', 'ERROR']] = None,
41
+ log_file: Union[
42
+ None,
43
+ str] = None,
44
+ analyze_log: bool = False
45
+ ) -> int:
17
46
  """
18
47
  This function will continue the installation the FACT_core after the restart of the computer.
19
48
 
@@ -28,7 +57,10 @@ def install_after_restart(
28
57
  :param log_level: string, the log level to use for the installation.
29
58
  The same as using the '--log-level' parameter in the 'install.py' script.
30
59
  The default is 'INFO' in the 'install.py' script.
31
- :return:
60
+ :param log_file: string, the log file to use for the installation.
61
+ The same as using the '--log-file' parameter in the 'install.py' script.
62
+ :param analyze_log: bool, if True, the log file will be analyzed for plugin installation errors.
63
+ :return: int, 0 if the installation was successful, otherwise 1.
32
64
  """
33
65
 
34
66
  install_command: str = 'python3 "' + str(Path(installation_directory, config_install.INSTALL_FILE_PATH)) + '"'
@@ -37,10 +69,51 @@ def install_after_restart(
37
69
  install_command = install_command + ' --' + install_type
38
70
 
39
71
  if log_level:
40
- install_command = install_command + ' --log-level ' + log_level
72
+ install_command = install_command + ' --log_level ' + log_level
73
+
74
+ if log_file:
75
+ install_command = install_command + ' --log_file "' + log_file + '"'
41
76
 
42
77
  # Install the FACT_core repo.
43
78
  process.execute_with_live_output(cmd=install_command, verbose=True)
79
+
80
+ # Analyze the log file for errors.
81
+ if analyze_log and (install_type == 'backend' or install_type is None):
82
+ if not log_file:
83
+ log_file = str(Path.cwd() / config_install.INSTALL_LOG_FILE_NAME)
84
+
85
+ return analyze_log_file(log_file=log_file)
86
+
44
87
  # Remove the FACT_core installation log.
45
88
  # working_directory_path: str = filesystem.get_working_directory()
46
89
  # filesystem.remove_file(str(Path(working_directory_path, config_install.INSTALL_LOG_FILE_NAME)))
90
+
91
+ return 0
92
+
93
+
94
+ def analyze_log_file(log_file: str):
95
+ """
96
+ This function will analyze the log file for plugin installation errors.
97
+ :param log_file:
98
+ :return:
99
+ """
100
+
101
+ with open(log_file, 'r') as file:
102
+ log_content: str = file.read()
103
+
104
+ for plugin in PLUGIN_LIST:
105
+ if f'{FINISHED_INSTALLING_STRINGS[0]} {plugin} {FINISHED_INSTALLING_STRINGS[1]}' not in log_content:
106
+ message = (f'Error: [{plugin}] installation failed.\n'
107
+ f'Check the log file: {log_file}\n'
108
+ f'Exiting...')
109
+ print_api.print_api(message, color='red')
110
+ return 1
111
+
112
+ if LOG_FINISHED_STRING not in log_content:
113
+ message = (f'Error: Installation failed.\n'
114
+ f'Check the log file: {log_file}\n'
115
+ f'Exiting...')
116
+ print_api.print_api(message, color='red')
117
+ return 1
118
+
119
+ return 0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: atomicshop
3
- Version: 2.16.43
3
+ Version: 2.16.44
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=eN5mJMelXPzsx3RapgUonBJKKZKyH4jUURpdEWoMogA,124
1
+ atomicshop/__init__.py,sha256=cTkolJcyCusHq9bBDXgphXYHAv5YCLiWysUXbZegGZc,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
@@ -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=Ykva7XI_t-f4H_z0mKxLuyQ04LxZBblHZN_PbYB9idY,6968
48
+ atomicshop/websocket_parse.py,sha256=PygRqEFnqEcPx3PNRtJoZcKN-mXvT_zighzTJR_B-Tc,14934
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
@@ -117,7 +117,7 @@ atomicshop/etws/traces/trace_dns.py,sha256=WvOZm7KNdP4r6ofkZhUGi9WjtYlkV3mUp_yxi
117
117
  atomicshop/etws/traces/trace_sysmon_process_creation.py,sha256=OM-bkK38uYMwWLZKNOTDa0Xdk3sO6sqsxoMUIiPvm5g,4656
118
118
  atomicshop/file_io/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
119
119
  atomicshop/file_io/csvs.py,sha256=jBdm3_z5cMyvxLxJnGcybUAptHAbyL0r0tlLqY0sdTQ,9327
120
- atomicshop/file_io/docxs.py,sha256=ffJhnmM_WyD8mCoq2dGdpfahdIrGTPy96QVlH5EWjeI,5754
120
+ atomicshop/file_io/docxs.py,sha256=3ctQ9JiGx8K8EYeKWiuraLtqhilW1qk1cZX9lHv0usk,5753
121
121
  atomicshop/file_io/file_io.py,sha256=5Kl0P6vF4GQVdwew1lzHLb-db9qiMvDjTgccbi5P-zk,7167
122
122
  atomicshop/file_io/jsons.py,sha256=q9ZU8slBKnHLrtn3TnbK1qxrRpj5ZvCm6AlsFzoANjo,5303
123
123
  atomicshop/file_io/tomls.py,sha256=ol8EvQPf9sryTmZUf1v55BYSUQ6ml7HVVBHpNKbsIlA,9768
@@ -229,7 +229,7 @@ atomicshop/wrappers/factw/fact_extractor/__init__.py,sha256=47DEQpj8HBSa-_TImW-5
229
229
  atomicshop/wrappers/factw/fact_extractor/docker_image.py,sha256=2FyYjnw8gxFNwISQ83OwH-iGivkFi6EAluyCZ0loHEQ,2501
230
230
  atomicshop/wrappers/factw/fact_extractor/get_extractor.py,sha256=2mfOAftHIlCcGt1s7MWdq7DsDCuI6wX3MtvcEZ4SK-0,756
231
231
  atomicshop/wrappers/factw/install/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
232
- atomicshop/wrappers/factw/install/install_after_restart.py,sha256=zsghES-pyCNiGU2Yix_fFBiDEOWfQ0dtbmyVeZozgL8,2012
232
+ atomicshop/wrappers/factw/install/install_after_restart.py,sha256=cr8E9BAEdpJXJ1VdyXr85byU0PvE3tPV0uPALQOmiKg,4318
233
233
  atomicshop/wrappers/factw/install/pre_install_and_install_before_restart.py,sha256=GFsO9MTH0czKoxkiPJtjalilUwsmFLBCcx9Znv37S4M,5945
234
234
  atomicshop/wrappers/factw/postgresql/__init__.py,sha256=xMBn2d3Exo23IPP2F_9-SXmOlhFbwWDgS9KwozSTjA0,162
235
235
  atomicshop/wrappers/factw/postgresql/analysis.py,sha256=2Rxzy2jyq3zEKIo53z8VkjuslKE_i5mq2ZpmJAvyd6U,716
@@ -315,8 +315,8 @@ atomicshop/wrappers/socketw/ssl_base.py,sha256=kmiif84kMhBr5yjQW17p935sfjR5JKG0L
315
315
  atomicshop/wrappers/socketw/statistics_csv.py,sha256=w1AH-zf4mBuT4euf28UKij9ihM-b1BRU9Qfby0QDdqI,2957
316
316
  atomicshop/wrappers/winregw/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
317
317
  atomicshop/wrappers/winregw/winreg_network.py,sha256=ChnVG8ZecKJ-DMF8nUHRiifWJq2M4slEwKat6FBfPfE,8685
318
- atomicshop-2.16.43.dist-info/LICENSE.txt,sha256=lLU7EYycfYcK2NR_1gfnhnRC8b8ccOTElACYplgZN88,1094
319
- atomicshop-2.16.43.dist-info/METADATA,sha256=QVoeyIJQUE341VUy8UhCrEqSabPP8SLi8qUJjyi6f98,10500
320
- atomicshop-2.16.43.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
321
- atomicshop-2.16.43.dist-info/top_level.txt,sha256=EgKJB-7xcrAPeqTRF2laD_Np2gNGYkJkd4OyXqpJphA,11
322
- atomicshop-2.16.43.dist-info/RECORD,,
318
+ atomicshop-2.16.44.dist-info/LICENSE.txt,sha256=lLU7EYycfYcK2NR_1gfnhnRC8b8ccOTElACYplgZN88,1094
319
+ atomicshop-2.16.44.dist-info/METADATA,sha256=yeA-HD5CtX5FhTCrJG9ylhYHECkHvJL_ai4gaOnilY4,10500
320
+ atomicshop-2.16.44.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
321
+ atomicshop-2.16.44.dist-info/top_level.txt,sha256=EgKJB-7xcrAPeqTRF2laD_Np2gNGYkJkd4OyXqpJphA,11
322
+ atomicshop-2.16.44.dist-info/RECORD,,