atomicshop 2.11.47__py3-none-any.whl → 3.10.5__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.
- atomicshop/__init__.py +1 -1
- atomicshop/{addons/mains → a_mains}/FACT/update_extract.py +3 -2
- atomicshop/a_mains/addons/process_list/compile.cmd +7 -0
- atomicshop/a_mains/addons/process_list/compiled/Win10x64/process_list.dll +0 -0
- atomicshop/a_mains/addons/process_list/compiled/Win10x64/process_list.exp +0 -0
- atomicshop/a_mains/addons/process_list/compiled/Win10x64/process_list.lib +0 -0
- atomicshop/{addons → a_mains/addons}/process_list/process_list.cpp +8 -1
- atomicshop/a_mains/dns_gateway_setting.py +11 -0
- atomicshop/a_mains/get_local_tcp_ports.py +85 -0
- atomicshop/a_mains/github_wrapper.py +11 -0
- atomicshop/a_mains/install_ca_certificate.py +172 -0
- atomicshop/{addons/mains → a_mains}/msi_unpacker.py +3 -1
- atomicshop/a_mains/process_from_port.py +119 -0
- atomicshop/a_mains/set_default_dns_gateway.py +90 -0
- atomicshop/a_mains/update_config_toml.py +38 -0
- atomicshop/appointment_management.py +5 -3
- atomicshop/basics/ansi_escape_codes.py +3 -1
- atomicshop/basics/argparse_template.py +2 -0
- atomicshop/basics/booleans.py +27 -30
- atomicshop/basics/bytes_arrays.py +43 -0
- atomicshop/basics/classes.py +149 -1
- atomicshop/basics/dicts.py +12 -0
- atomicshop/basics/enums.py +2 -2
- atomicshop/basics/exceptions.py +5 -1
- atomicshop/basics/list_of_classes.py +29 -0
- atomicshop/basics/list_of_dicts.py +69 -5
- atomicshop/basics/lists.py +14 -0
- atomicshop/basics/multiprocesses.py +374 -50
- atomicshop/basics/package_module.py +10 -0
- atomicshop/basics/strings.py +160 -7
- atomicshop/basics/threads.py +14 -0
- atomicshop/basics/tracebacks.py +13 -4
- atomicshop/certificates.py +153 -52
- atomicshop/config_init.py +12 -7
- atomicshop/console_user_response.py +7 -14
- atomicshop/consoles.py +9 -0
- atomicshop/datetimes.py +98 -0
- atomicshop/diff_check.py +340 -40
- atomicshop/dns.py +128 -12
- atomicshop/etws/_pywintrace_fix.py +17 -0
- atomicshop/etws/const.py +38 -0
- atomicshop/etws/providers.py +21 -0
- atomicshop/etws/sessions.py +43 -0
- atomicshop/etws/trace.py +168 -0
- atomicshop/etws/traces/trace_dns.py +162 -0
- atomicshop/etws/traces/trace_sysmon_process_creation.py +126 -0
- atomicshop/etws/traces/trace_tcp.py +130 -0
- atomicshop/file_io/csvs.py +222 -24
- atomicshop/file_io/docxs.py +35 -18
- atomicshop/file_io/file_io.py +35 -19
- atomicshop/file_io/jsons.py +49 -0
- atomicshop/file_io/tomls.py +139 -0
- atomicshop/filesystem.py +864 -293
- atomicshop/get_process_list.py +133 -0
- atomicshop/{process_name_cmd.py → get_process_name_cmd_dll.py} +52 -19
- atomicshop/http_parse.py +149 -93
- atomicshop/ip_addresses.py +6 -1
- atomicshop/mitm/centered_settings.py +132 -0
- atomicshop/mitm/config_static.py +207 -0
- atomicshop/mitm/config_toml_editor.py +55 -0
- atomicshop/mitm/connection_thread_worker.py +875 -357
- atomicshop/mitm/engines/__parent/parser___parent.py +4 -17
- atomicshop/mitm/engines/__parent/recorder___parent.py +108 -51
- atomicshop/mitm/engines/__parent/requester___parent.py +116 -0
- atomicshop/mitm/engines/__parent/responder___parent.py +75 -114
- atomicshop/mitm/engines/__reference_general/parser___reference_general.py +10 -7
- atomicshop/mitm/engines/__reference_general/recorder___reference_general.py +5 -5
- atomicshop/mitm/engines/__reference_general/requester___reference_general.py +47 -0
- atomicshop/mitm/engines/__reference_general/responder___reference_general.py +95 -13
- atomicshop/mitm/engines/create_module_template.py +58 -14
- atomicshop/mitm/import_config.py +359 -139
- atomicshop/mitm/initialize_engines.py +160 -74
- atomicshop/mitm/message.py +64 -23
- atomicshop/mitm/mitm_main.py +892 -0
- atomicshop/mitm/recs_files.py +183 -0
- atomicshop/mitm/shared_functions.py +4 -10
- atomicshop/mitm/ssh_tester.py +82 -0
- atomicshop/mitm/statistic_analyzer.py +257 -166
- atomicshop/mitm/statistic_analyzer_helper/analyzer_helper.py +136 -0
- atomicshop/mitm/statistic_analyzer_helper/moving_average_helper.py +525 -0
- atomicshop/monitor/change_monitor.py +96 -120
- atomicshop/monitor/checks/dns.py +139 -70
- atomicshop/monitor/checks/file.py +77 -0
- atomicshop/monitor/checks/network.py +81 -77
- atomicshop/monitor/checks/process_running.py +33 -34
- atomicshop/monitor/checks/url.py +94 -0
- atomicshop/networks.py +671 -0
- atomicshop/on_exit.py +205 -0
- atomicshop/package_mains_processor.py +84 -0
- atomicshop/permissions/permissions.py +22 -0
- atomicshop/permissions/ubuntu_permissions.py +239 -0
- atomicshop/permissions/win_permissions.py +33 -0
- atomicshop/print_api.py +24 -41
- atomicshop/process.py +63 -17
- atomicshop/process_poller/__init__.py +0 -0
- atomicshop/process_poller/pollers/__init__.py +0 -0
- atomicshop/process_poller/pollers/psutil_pywin32wmi_dll.py +95 -0
- atomicshop/process_poller/process_pool.py +207 -0
- atomicshop/process_poller/simple_process_pool.py +311 -0
- atomicshop/process_poller/tracer_base.py +45 -0
- atomicshop/process_poller/tracers/__init__.py +0 -0
- atomicshop/process_poller/tracers/event_log.py +46 -0
- atomicshop/process_poller/tracers/sysmon_etw.py +68 -0
- atomicshop/python_file_patcher.py +1 -1
- atomicshop/python_functions.py +27 -75
- atomicshop/question_answer_engine.py +2 -2
- atomicshop/scheduling.py +24 -5
- atomicshop/sound.py +4 -2
- atomicshop/speech_recognize.py +8 -0
- atomicshop/ssh_remote.py +158 -172
- atomicshop/startup/__init__.py +0 -0
- atomicshop/startup/win/__init__.py +0 -0
- atomicshop/startup/win/startup_folder.py +53 -0
- atomicshop/startup/win/task_scheduler.py +119 -0
- atomicshop/system_resource_monitor.py +61 -46
- atomicshop/system_resources.py +8 -8
- atomicshop/tempfiles.py +1 -2
- atomicshop/timer.py +30 -11
- atomicshop/urls.py +41 -0
- atomicshop/venvs.py +28 -0
- atomicshop/versioning.py +27 -0
- atomicshop/web.py +110 -25
- atomicshop/web_apis/__init__.py +0 -0
- atomicshop/web_apis/google_custom_search.py +44 -0
- atomicshop/web_apis/google_llm.py +188 -0
- atomicshop/websocket_parse.py +450 -0
- atomicshop/wrappers/certauthw/certauth.py +1 -0
- atomicshop/wrappers/cryptographyw.py +29 -8
- atomicshop/wrappers/ctyping/etw_winapi/__init__.py +0 -0
- atomicshop/wrappers/ctyping/etw_winapi/const.py +335 -0
- atomicshop/wrappers/ctyping/etw_winapi/etw_functions.py +393 -0
- atomicshop/wrappers/ctyping/file_details_winapi.py +67 -0
- atomicshop/wrappers/ctyping/msi_windows_installer/cabs.py +2 -1
- atomicshop/wrappers/ctyping/msi_windows_installer/extract_msi_main.py +13 -9
- atomicshop/wrappers/ctyping/msi_windows_installer/tables.py +35 -0
- atomicshop/wrappers/ctyping/setup_device.py +466 -0
- atomicshop/wrappers/ctyping/win_console.py +39 -0
- atomicshop/wrappers/dockerw/dockerw.py +113 -2
- atomicshop/wrappers/elasticsearchw/config_basic.py +0 -12
- atomicshop/wrappers/elasticsearchw/elastic_infra.py +75 -0
- atomicshop/wrappers/elasticsearchw/elasticsearchw.py +2 -20
- atomicshop/wrappers/factw/get_file_data.py +12 -5
- atomicshop/wrappers/factw/install/install_after_restart.py +89 -5
- atomicshop/wrappers/factw/install/pre_install_and_install_before_restart.py +20 -14
- atomicshop/wrappers/factw/postgresql/firmware.py +4 -6
- atomicshop/wrappers/githubw.py +583 -51
- atomicshop/wrappers/loggingw/consts.py +49 -0
- atomicshop/wrappers/loggingw/filters.py +102 -0
- atomicshop/wrappers/loggingw/formatters.py +58 -71
- atomicshop/wrappers/loggingw/handlers.py +459 -40
- atomicshop/wrappers/loggingw/loggers.py +19 -0
- atomicshop/wrappers/loggingw/loggingw.py +1010 -178
- atomicshop/wrappers/loggingw/reading.py +344 -19
- atomicshop/wrappers/mongodbw/__init__.py +0 -0
- atomicshop/wrappers/mongodbw/mongo_infra.py +31 -0
- atomicshop/wrappers/mongodbw/mongodbw.py +1432 -0
- atomicshop/wrappers/netshw.py +271 -0
- atomicshop/wrappers/playwrightw/engine.py +34 -19
- atomicshop/wrappers/playwrightw/infra.py +5 -0
- atomicshop/wrappers/playwrightw/javascript.py +7 -3
- atomicshop/wrappers/playwrightw/keyboard.py +14 -0
- atomicshop/wrappers/playwrightw/scenarios.py +172 -5
- atomicshop/wrappers/playwrightw/waits.py +9 -7
- atomicshop/wrappers/powershell_networking.py +80 -0
- atomicshop/wrappers/psutilw/processes.py +81 -0
- atomicshop/wrappers/psutilw/psutil_networks.py +85 -0
- atomicshop/wrappers/psutilw/psutilw.py +9 -0
- atomicshop/wrappers/pyopensslw.py +9 -2
- atomicshop/wrappers/pywin32w/__init__.py +0 -0
- atomicshop/wrappers/pywin32w/cert_store.py +116 -0
- atomicshop/wrappers/pywin32w/console.py +34 -0
- atomicshop/wrappers/pywin32w/win_event_log/__init__.py +0 -0
- atomicshop/wrappers/pywin32w/win_event_log/fetch.py +174 -0
- atomicshop/wrappers/pywin32w/win_event_log/subscribe.py +212 -0
- atomicshop/wrappers/pywin32w/win_event_log/subscribes/__init__.py +0 -0
- atomicshop/wrappers/pywin32w/win_event_log/subscribes/process_create.py +57 -0
- atomicshop/wrappers/pywin32w/win_event_log/subscribes/process_terminate.py +49 -0
- atomicshop/wrappers/pywin32w/win_event_log/subscribes/schannel_logging.py +97 -0
- atomicshop/wrappers/pywin32w/winshell.py +19 -0
- atomicshop/wrappers/pywin32w/wmis/__init__.py +0 -0
- atomicshop/wrappers/pywin32w/wmis/msft_netipaddress.py +113 -0
- atomicshop/wrappers/pywin32w/wmis/win32_networkadapterconfiguration.py +259 -0
- atomicshop/wrappers/pywin32w/wmis/win32networkadapter.py +112 -0
- atomicshop/wrappers/pywin32w/wmis/wmi_helpers.py +236 -0
- atomicshop/wrappers/socketw/accepter.py +21 -7
- atomicshop/wrappers/socketw/certificator.py +216 -150
- atomicshop/wrappers/socketw/creator.py +190 -50
- atomicshop/wrappers/socketw/dns_server.py +500 -173
- atomicshop/wrappers/socketw/exception_wrapper.py +45 -52
- atomicshop/wrappers/socketw/process_getter.py +86 -0
- atomicshop/wrappers/socketw/receiver.py +144 -102
- atomicshop/wrappers/socketw/sender.py +65 -35
- atomicshop/wrappers/socketw/sni.py +334 -165
- atomicshop/wrappers/socketw/socket_base.py +134 -0
- atomicshop/wrappers/socketw/socket_client.py +137 -95
- atomicshop/wrappers/socketw/socket_server_tester.py +14 -9
- atomicshop/wrappers/socketw/socket_wrapper.py +717 -116
- atomicshop/wrappers/socketw/ssl_base.py +15 -14
- atomicshop/wrappers/socketw/statistics_csv.py +148 -17
- atomicshop/wrappers/sysmonw.py +157 -0
- atomicshop/wrappers/ubuntu_terminal.py +65 -26
- atomicshop/wrappers/win_auditw.py +189 -0
- atomicshop/wrappers/winregw/__init__.py +0 -0
- atomicshop/wrappers/winregw/winreg_installed_software.py +58 -0
- atomicshop/wrappers/winregw/winreg_network.py +232 -0
- {atomicshop-2.11.47.dist-info → atomicshop-3.10.5.dist-info}/METADATA +31 -49
- atomicshop-3.10.5.dist-info/RECORD +306 -0
- {atomicshop-2.11.47.dist-info → atomicshop-3.10.5.dist-info}/WHEEL +1 -1
- atomicshop/_basics_temp.py +0 -101
- atomicshop/addons/a_setup_scripts/install_psycopg2_ubuntu.sh +0 -3
- atomicshop/addons/a_setup_scripts/install_pywintrace_0.3.cmd +0 -2
- atomicshop/addons/mains/install_docker_rootless_ubuntu.py +0 -11
- atomicshop/addons/mains/install_docker_ubuntu_main_sudo.py +0 -11
- atomicshop/addons/mains/install_elastic_search_and_kibana_ubuntu.py +0 -10
- atomicshop/addons/mains/install_wsl_ubuntu_lts_admin.py +0 -9
- atomicshop/addons/package_setup/CreateWheel.cmd +0 -7
- atomicshop/addons/package_setup/Setup in Edit mode.cmd +0 -6
- atomicshop/addons/package_setup/Setup.cmd +0 -7
- atomicshop/addons/process_list/compile.cmd +0 -2
- atomicshop/addons/process_list/compiled/Win10x64/process_list.dll +0 -0
- atomicshop/addons/process_list/compiled/Win10x64/process_list.exp +0 -0
- atomicshop/addons/process_list/compiled/Win10x64/process_list.lib +0 -0
- atomicshop/archiver/_search_in_zip.py +0 -189
- atomicshop/archiver/archiver.py +0 -34
- atomicshop/archiver/search_in_archive.py +0 -250
- atomicshop/archiver/sevenz_app_w.py +0 -86
- atomicshop/archiver/sevenzs.py +0 -44
- atomicshop/archiver/zips.py +0 -293
- atomicshop/etw/dns_trace.py +0 -118
- atomicshop/etw/etw.py +0 -61
- atomicshop/file_types.py +0 -24
- atomicshop/mitm/engines/create_module_template_example.py +0 -13
- atomicshop/mitm/initialize_mitm_server.py +0 -240
- atomicshop/monitor/checks/hash.py +0 -44
- atomicshop/monitor/checks/hash_checks/file.py +0 -55
- atomicshop/monitor/checks/hash_checks/url.py +0 -62
- atomicshop/pbtkmultifile_argparse.py +0 -88
- atomicshop/permissions.py +0 -110
- atomicshop/process_poller.py +0 -237
- atomicshop/script_as_string_processor.py +0 -38
- atomicshop/ssh_scripts/process_from_ipv4.py +0 -37
- atomicshop/ssh_scripts/process_from_port.py +0 -27
- atomicshop/wrappers/_process_wrapper_curl.py +0 -27
- atomicshop/wrappers/_process_wrapper_tar.py +0 -21
- atomicshop/wrappers/dockerw/install_docker.py +0 -209
- atomicshop/wrappers/elasticsearchw/infrastructure.py +0 -265
- atomicshop/wrappers/elasticsearchw/install_elastic.py +0 -232
- atomicshop/wrappers/ffmpegw.py +0 -125
- atomicshop/wrappers/loggingw/checks.py +0 -20
- atomicshop/wrappers/nodejsw/install_nodejs.py +0 -139
- atomicshop/wrappers/process_wrapper_pbtk.py +0 -16
- atomicshop/wrappers/socketw/base.py +0 -59
- atomicshop/wrappers/socketw/get_process.py +0 -107
- atomicshop/wrappers/wslw.py +0 -191
- atomicshop-2.11.47.dist-info/RECORD +0 -251
- /atomicshop/{addons/mains → a_mains}/FACT/factw_fact_extractor_docker_image_main_sudo.py +0 -0
- /atomicshop/{addons → a_mains/addons}/PlayWrightCodegen.cmd +0 -0
- /atomicshop/{addons → a_mains/addons}/ScriptExecution.cmd +0 -0
- /atomicshop/{addons/mains → a_mains/addons}/inits/init_to_import_all_modules.py +0 -0
- /atomicshop/{addons → a_mains/addons}/process_list/ReadMe.txt +0 -0
- /atomicshop/{addons/mains → a_mains}/search_for_hyperlinks_in_docx.py +0 -0
- /atomicshop/{archiver → etws}/__init__.py +0 -0
- /atomicshop/{etw → etws/traces}/__init__.py +0 -0
- /atomicshop/{monitor/checks/hash_checks → mitm/statistic_analyzer_helper}/__init__.py +0 -0
- /atomicshop/{wrappers/nodejsw → permissions}/__init__.py +0 -0
- /atomicshop/wrappers/pywin32w/{wmi_win32process.py → wmis/win32process.py} +0 -0
- {atomicshop-2.11.47.dist-info → atomicshop-3.10.5.dist-info/licenses}/LICENSE.txt +0 -0
- {atomicshop-2.11.47.dist-info → atomicshop-3.10.5.dist-info}/top_level.txt +0 -0
atomicshop/basics/booleans.py
CHANGED
|
@@ -1,38 +1,35 @@
|
|
|
1
|
-
def
|
|
1
|
+
def is_only_1_true_in_list(
|
|
2
|
+
booleans_list_of_tuples: list[tuple],
|
|
3
|
+
raise_if_all_false: bool = True
|
|
4
|
+
) -> None:
|
|
2
5
|
"""
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
:param boolean1: tuple, (value, string name of the setting you want to print to the user to be aware of).
|
|
9
|
-
:param boolean2: tuple, (value, string name of the setting you want to print to the user to be aware of).
|
|
10
|
-
:param boolean3: tuple, (value, string name of the setting you want to print to the user to be aware of).
|
|
11
|
-
:return:
|
|
6
|
+
Check if only one boolean can be 'True' from a list of booleans
|
|
7
|
+
:param booleans_list_of_tuples: list of tuples, Structure:
|
|
8
|
+
[(value, string name of the setting you want to print to the user to be aware of), ...]
|
|
9
|
+
:param raise_if_all_false: bool, If True, exception will be raised if all booleans are False.
|
|
10
|
+
:return: None
|
|
12
11
|
"""
|
|
13
12
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
check_if_2_booleans_are_true(boolean1, boolean3)
|
|
17
|
-
check_if_2_booleans_are_true(boolean2, boolean3)
|
|
13
|
+
# Filter to get all the `True` conditions and their associated names
|
|
14
|
+
true_conditions = [name for value, name in booleans_list_of_tuples if value]
|
|
18
15
|
|
|
16
|
+
# Count the number of True values
|
|
17
|
+
true_count = len(true_conditions)
|
|
19
18
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
f"{boolean2[1]}={boolean2[0]}\n"
|
|
35
|
-
raise ValueError(message)
|
|
19
|
+
if true_count == 1:
|
|
20
|
+
# Only one value is True, which is acceptable
|
|
21
|
+
# print(f"Only one condition is True: {true_conditions[0]}.")
|
|
22
|
+
pass
|
|
23
|
+
elif true_count > 1:
|
|
24
|
+
# More than one value is True, raise an exception
|
|
25
|
+
raise ValueError(f"Multiple conditions are True: {', '.join(true_conditions)}.")
|
|
26
|
+
elif true_count == 0 and raise_if_all_false:
|
|
27
|
+
# None of the values are True, and the user does not want to ignore this case
|
|
28
|
+
raise ValueError("No conditions are True, and raise_if_all_false is set to True.")
|
|
29
|
+
else:
|
|
30
|
+
# If no True values and no_raise_if_all_false is True, just pass silently
|
|
31
|
+
# print("No conditions are True (but raise_if_all_false is set to False).")
|
|
32
|
+
pass
|
|
36
33
|
|
|
37
34
|
|
|
38
35
|
def convert_string_to_bool(string: str) -> bool:
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
from typing import Union
|
|
2
|
+
import string
|
|
3
|
+
|
|
4
|
+
|
|
1
5
|
def get_single_byte_from_byte_string(byte_string, index: int):
|
|
2
6
|
"""
|
|
3
7
|
Function extracts single byte as byte from byte string object.
|
|
@@ -53,6 +57,30 @@ def convert_sequence_of_bytes_to_sequence_of_strings(byte_sequence: bytes) -> li
|
|
|
53
57
|
return result
|
|
54
58
|
|
|
55
59
|
|
|
60
|
+
def convert_sequence_of_bytes_to_exact_string(
|
|
61
|
+
byte_sequence: bytes,
|
|
62
|
+
add_space_between_bytes: bool = False,
|
|
63
|
+
) -> str:
|
|
64
|
+
"""
|
|
65
|
+
Convert sequence of bytes to exact string.
|
|
66
|
+
Example: b'\xc0\x00' -> 'c000'
|
|
67
|
+
|
|
68
|
+
:param byte_sequence: bytes, sequence of bytes.
|
|
69
|
+
:param add_space_between_bytes: bool, add space between bytes.
|
|
70
|
+
Example: b'\xc0\x00' -> 'c0 00'
|
|
71
|
+
:return: string.
|
|
72
|
+
"""
|
|
73
|
+
|
|
74
|
+
# Convert to hex string and format
|
|
75
|
+
byte_list: list = []
|
|
76
|
+
for byte in byte_sequence:
|
|
77
|
+
byte_list.append(f'{byte:02x}')
|
|
78
|
+
|
|
79
|
+
result = ''.join(byte_list)
|
|
80
|
+
|
|
81
|
+
return result
|
|
82
|
+
|
|
83
|
+
|
|
56
84
|
def find_position(target: bytes, file_path: str = None, file_bytes: bytes = None, chunk_size: int = None, starting_position: int = 0) -> int:
|
|
57
85
|
"""
|
|
58
86
|
Find position of the target bytes string in the file.
|
|
@@ -155,3 +183,18 @@ def read_bytes_from_position(
|
|
|
155
183
|
# Read the specified number of bytes.
|
|
156
184
|
data = file.read(num_bytes)
|
|
157
185
|
return data
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
def convert_bytes_to_printable_string_only(
|
|
189
|
+
byte_sequence: Union[bytes, bytearray],
|
|
190
|
+
non_printable_character: str = '.'
|
|
191
|
+
) -> str:
|
|
192
|
+
"""
|
|
193
|
+
Convert bytes to printable string. If byte is not printable, replace it with 'non_printable_character'.
|
|
194
|
+
:param byte_sequence: bytes or bytearray, sequence of bytes.
|
|
195
|
+
:param non_printable_character: string, character to replace non-printable characters.
|
|
196
|
+
:return:
|
|
197
|
+
"""
|
|
198
|
+
|
|
199
|
+
printable = set(string.printable)
|
|
200
|
+
return ''.join(chr(byte) if chr(byte) in printable else non_printable_character for byte in byte_sequence)
|
atomicshop/basics/classes.py
CHANGED
|
@@ -1,12 +1,160 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import sys
|
|
3
3
|
import ast
|
|
4
|
-
import importlib
|
|
5
4
|
from pathlib import Path
|
|
5
|
+
import pkgutil
|
|
6
|
+
import importlib
|
|
7
|
+
import inspect
|
|
6
8
|
|
|
7
9
|
from ..file_io.file_io import read_file
|
|
8
10
|
|
|
9
11
|
|
|
12
|
+
"""
|
|
13
|
+
Using logger in the class only once during the import of the module.
|
|
14
|
+
|
|
15
|
+
class ParserParent:
|
|
16
|
+
# Initializing the logger in the "class variable" section will leave the instance of the logger initiated
|
|
17
|
+
# and the rest of the instances of the class will use the same logger.
|
|
18
|
+
# It is not in the "__init__" section, so it's not going to be initiated again.
|
|
19
|
+
# The name of the logger using "__name__" variable, which is the full name of the module package.
|
|
20
|
+
# Example: classes.parsers.parser_1_reference_general
|
|
21
|
+
|
|
22
|
+
# The code outside the functions will be executed during import of the module. When initializing a class
|
|
23
|
+
# in the script these lines will not be called again, only the "init" function.
|
|
24
|
+
logger = create_custom_logger()
|
|
25
|
+
|
|
26
|
+
def __init__(self, class_client_message: ClientMessage):
|
|
27
|
+
self.class_client_message: ClientMessage = class_client_message
|
|
28
|
+
|
|
29
|
+
# Usage: self.logger.info("Message")
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
"""
|
|
34
|
+
Using Base class for easier interfacing on subclasses.
|
|
35
|
+
|
|
36
|
+
recognition/recognition_base.py:
|
|
37
|
+
from abc import abstractmethod
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class Recognizer:
|
|
41
|
+
@abstractmethod
|
|
42
|
+
def recognize_vendor(self, file_path: str) -> str:
|
|
43
|
+
pass
|
|
44
|
+
|
|
45
|
+
@abstractmethod
|
|
46
|
+
def recognize_family(self, bytes_list: list[str]]) -> str:
|
|
47
|
+
pass
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
recognition/super_vendor.py:
|
|
51
|
+
from .recognition_base import Recognizer
|
|
52
|
+
|
|
53
|
+
class SupervendorRecognizer(Recognizer):
|
|
54
|
+
def recognize_vendor(self, file_path: str) -> str:
|
|
55
|
+
classification_string: str = <Some logic to classify the SuperVendor>
|
|
56
|
+
return classification_string
|
|
57
|
+
|
|
58
|
+
def recognize_family(self, bytes_list: list[str]]) -> str:
|
|
59
|
+
family_classification_string: str = <Some logic to classify the family of the SuperVendor>
|
|
60
|
+
return family_classification_string
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
main_script.py:
|
|
64
|
+
from . import recognition
|
|
65
|
+
from .recognition.recognition_base import Recognizer
|
|
66
|
+
|
|
67
|
+
# Get the list of all the recognizers in the recognition package.
|
|
68
|
+
recognizers_list: list = classes.get_list_of_classes_in_module(
|
|
69
|
+
imported_package=recognition, imported_base_class=Recognizer)
|
|
70
|
+
|
|
71
|
+
# Get the list of all the vendors from the file.
|
|
72
|
+
vendors_list: list = list()
|
|
73
|
+
for recognizer in recognizers_list:
|
|
74
|
+
recognizer_instance = recognizer()
|
|
75
|
+
vendor_name: str = recognizer_instance.recognize_vendor(file_object=file_path)
|
|
76
|
+
if vendor_name:
|
|
77
|
+
vendors_list.append((vendor_name, recognizer_instance))
|
|
78
|
+
|
|
79
|
+
# Get the families of the vendors.
|
|
80
|
+
for vendor_name, recognizer_instance in vendors_list:
|
|
81
|
+
family_name: str = recognizer_instance.recognize_family(bytes_list=file_bytes_list)
|
|
82
|
+
print(f"Vendor: {vendor_name}, Family: {family_name}")
|
|
83
|
+
"""
|
|
84
|
+
|
|
85
|
+
def get_list_of_classes_in_module(
|
|
86
|
+
imported_package,
|
|
87
|
+
imported_base_class
|
|
88
|
+
) -> list:
|
|
89
|
+
"""
|
|
90
|
+
Function that returns a list of classes that are subclasses of the imported_base_class from the imported_package.
|
|
91
|
+
|
|
92
|
+
Example:
|
|
93
|
+
# Package structure:
|
|
94
|
+
# unpackers
|
|
95
|
+
# ├── __init__.py
|
|
96
|
+
# ├── unpacker_base.py
|
|
97
|
+
# ├── unpacker_1.py
|
|
98
|
+
# ├── unpacker_2.py
|
|
99
|
+
# ├── unpacker_3.py
|
|
100
|
+
# └── ... (other unpacker modules)
|
|
101
|
+
|
|
102
|
+
# unpacker_base.py:
|
|
103
|
+
from abc import abstractmethod
|
|
104
|
+
class Unpacker:
|
|
105
|
+
@abstractmethod
|
|
106
|
+
def unpack(self, file_path):
|
|
107
|
+
pass
|
|
108
|
+
|
|
109
|
+
# unpacker_1.py:
|
|
110
|
+
from unpackers.unpacker_base import Unpacker
|
|
111
|
+
class Unpacker1(Unpacker):
|
|
112
|
+
def unpack(self, file_path):
|
|
113
|
+
print(f"Unpacking file with Unpacker1: {file_path}")
|
|
114
|
+
|
|
115
|
+
# main_script.py:
|
|
116
|
+
# Import the base class
|
|
117
|
+
from unpackers.unpacker_base import Unpacker
|
|
118
|
+
# Import the package
|
|
119
|
+
import unpackers
|
|
120
|
+
# Get the list of classes
|
|
121
|
+
unpacker_classes = get_list_of_classes_in_module(imported_package=unpackers, imported_base_class=Unpacker)
|
|
122
|
+
|
|
123
|
+
# Initialize the classes
|
|
124
|
+
for unpacker_class in unpacker_classes:
|
|
125
|
+
unpacker_instance = unpacker_class()
|
|
126
|
+
unpacker_instance.unpack("file_path")
|
|
127
|
+
----------------------------
|
|
128
|
+
# You can also initialize the list of classes dynamically and after that execute methods.
|
|
129
|
+
# Example:
|
|
130
|
+
unpacker_classes = get_list_of_classes_in_module(imported_package=unpackers, imported_base_class=Unpacker)
|
|
131
|
+
|
|
132
|
+
instance_list: list = []
|
|
133
|
+
for unpacker_class in unpacker_classes:
|
|
134
|
+
instance_list.append(unpacker_class())
|
|
135
|
+
|
|
136
|
+
for instance in instance_list:
|
|
137
|
+
instance.unpack("file_path")
|
|
138
|
+
|
|
139
|
+
:param imported_package:
|
|
140
|
+
:param imported_base_class:
|
|
141
|
+
:return:
|
|
142
|
+
"""
|
|
143
|
+
unpacker_classes = []
|
|
144
|
+
|
|
145
|
+
# Iterate over all modules in the 'imported_package' package
|
|
146
|
+
for loader, module_name, is_pkg in pkgutil.iter_modules(imported_package.__path__):
|
|
147
|
+
# Import the module
|
|
148
|
+
module = importlib.import_module(f"{imported_package.__name__}.{module_name}")
|
|
149
|
+
|
|
150
|
+
# Inspect module members to find Unpacker subclasses
|
|
151
|
+
for name, obj in inspect.getmembers(module, inspect.isclass):
|
|
152
|
+
if issubclass(obj, imported_base_class) and obj is not imported_base_class:
|
|
153
|
+
unpacker_classes.append(obj)
|
|
154
|
+
|
|
155
|
+
return unpacker_classes
|
|
156
|
+
|
|
157
|
+
|
|
10
158
|
def create_empty_class():
|
|
11
159
|
"""
|
|
12
160
|
Function creates empty class, you can add parameters to it dynamically.
|
atomicshop/basics/dicts.py
CHANGED
|
@@ -24,6 +24,18 @@ def get_first_key_and_value_dict(input_dict: dict) -> dict:
|
|
|
24
24
|
return {first_key: input_dict[first_key]}
|
|
25
25
|
|
|
26
26
|
|
|
27
|
+
def get_last_added_key_value(input_dict: dict) -> dict:
|
|
28
|
+
"""
|
|
29
|
+
The function will return the last added key and value in a dictionary.
|
|
30
|
+
|
|
31
|
+
:param input_dict: dict, the dictionary to get the last added key and value.
|
|
32
|
+
:return: dict, the last added key and value in the dictionary.
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
last_key = list(input_dict.keys())[-1]
|
|
36
|
+
return {last_key: input_dict[last_key]}
|
|
37
|
+
|
|
38
|
+
|
|
27
39
|
def remove_keys(input_dict: dict, key_list: list) -> None:
|
|
28
40
|
"""
|
|
29
41
|
The function will remove a key from dictionary without raising an exception if it doesn't exist.
|
atomicshop/basics/enums.py
CHANGED
|
@@ -32,10 +32,10 @@ def __comparison_usage_example(
|
|
|
32
32
|
main folder.
|
|
33
33
|
|
|
34
34
|
Usage:
|
|
35
|
-
from atomicshop.filesystem import
|
|
35
|
+
from atomicshop.filesystem import get_paths_from_directory, ComparisonOperator
|
|
36
36
|
|
|
37
37
|
# Get full paths of all the 'engine_config.ini' files.
|
|
38
|
-
engine_config_path_list =
|
|
38
|
+
engine_config_path_list = get_paths_from_directory(
|
|
39
39
|
directory_fullpath=some_directory_path,
|
|
40
40
|
file_name_check_tuple=(config_file_name, ComparisonOperator.EQ))
|
|
41
41
|
"""
|
atomicshop/basics/exceptions.py
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
# v1.0.3 - 28.03.2023 17:20
|
|
2
1
|
import sys
|
|
3
2
|
|
|
4
3
|
from .threads import current_thread_id
|
|
@@ -15,3 +14,8 @@ def print_exception() -> None:
|
|
|
15
14
|
exc_type, exc_value, exc_traceback = sys.exc_info()
|
|
16
15
|
|
|
17
16
|
print(f"{error_log_prefix} Thread {thread_id}: * Details: {exc_type}, {exc_value}")
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def get_exception_type_string(exception: Exception) -> str:
|
|
20
|
+
""" Get exception type string """
|
|
21
|
+
return type(exception).__name__
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
from operator import attrgetter
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def sort_by_attributes(
|
|
5
|
+
list_instance: list,
|
|
6
|
+
attribute_list: list,
|
|
7
|
+
reverse: bool = False,
|
|
8
|
+
case_insensitive: bool = False
|
|
9
|
+
):
|
|
10
|
+
"""
|
|
11
|
+
Sort a list of objects by their attributes.
|
|
12
|
+
|
|
13
|
+
:param list_instance: list of objects.
|
|
14
|
+
:param attribute_list: list of attributes (strings). The sorting will be done by the attributes in the list.
|
|
15
|
+
In the appearing order in the list.
|
|
16
|
+
:param reverse: bool, sort in reverse order.
|
|
17
|
+
:param case_insensitive: bool, sorting will be case-insensitive.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
for attribute in attribute_list:
|
|
21
|
+
if case_insensitive:
|
|
22
|
+
list_instance = sorted(
|
|
23
|
+
list_instance, key=lambda obj: getattr(obj, attribute).lower(), reverse=reverse
|
|
24
|
+
)
|
|
25
|
+
else:
|
|
26
|
+
list_instance = sorted(
|
|
27
|
+
list_instance, key=attrgetter(attribute), reverse=reverse
|
|
28
|
+
)
|
|
29
|
+
return list_instance
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from operator import itemgetter
|
|
2
|
-
|
|
2
|
+
import json
|
|
3
3
|
|
|
4
4
|
from . import dicts, strings
|
|
5
5
|
|
|
@@ -100,7 +100,13 @@ def merge_to_dict(list_of_dicts: list) -> dict:
|
|
|
100
100
|
return result_dict
|
|
101
101
|
|
|
102
102
|
|
|
103
|
-
def is_value_exist_in_key(
|
|
103
|
+
def is_value_exist_in_key(
|
|
104
|
+
list_of_dicts: list,
|
|
105
|
+
key: str,
|
|
106
|
+
value_to_match: str,
|
|
107
|
+
value_case_insensitive: bool = False,
|
|
108
|
+
prefix_suffix: bool = False
|
|
109
|
+
) -> bool:
|
|
104
110
|
"""
|
|
105
111
|
The function will check if a value exists in a key in a list of dicts.
|
|
106
112
|
|
|
@@ -113,6 +119,7 @@ def is_value_exist_in_key(list_of_dicts: list, key: str, value_to_match: str, pr
|
|
|
113
119
|
:param key: str, the key to check in each entry (dict) in the list.
|
|
114
120
|
:param value_to_match: str, the value to find in the key.
|
|
115
121
|
This values is a pattern, so it can be a part of the value and can contain wildcards as "*" character.
|
|
122
|
+
:param value_case_insensitive: bool, if True the value will be matched case insensitive.
|
|
116
123
|
:param prefix_suffix: bool, related to how pattern of 'value_to_find' is matched against the value in the key.
|
|
117
124
|
Check the 'strings.match_pattern_against_string' function for more information.
|
|
118
125
|
:return: bool, True if the value exists in the key in any entry in the list of dicts, False if not.
|
|
@@ -121,7 +128,9 @@ def is_value_exist_in_key(list_of_dicts: list, key: str, value_to_match: str, pr
|
|
|
121
128
|
for dictionary in list_of_dicts:
|
|
122
129
|
try:
|
|
123
130
|
# if value_to_find in dictionary.get(key, None):
|
|
124
|
-
if strings.match_pattern_against_string(
|
|
131
|
+
if strings.match_pattern_against_string(
|
|
132
|
+
value_to_match, dictionary.get(key, None), case_insensitive=value_case_insensitive,
|
|
133
|
+
prefix_suffix=prefix_suffix):
|
|
125
134
|
return True
|
|
126
135
|
# If the key is not present in the dict 'TypeError' will be raised, since 'None' doesn't have the 'in' operator.
|
|
127
136
|
except TypeError:
|
|
@@ -141,7 +150,7 @@ def convert_to_set(list_of_dicts, sort_keys: bool = False) -> set:
|
|
|
141
150
|
:return: set.
|
|
142
151
|
"""
|
|
143
152
|
|
|
144
|
-
return set(dumps(x, sort_keys=sort_keys) for x in list_of_dicts)
|
|
153
|
+
return set(json.dumps(x, sort_keys=sort_keys) for x in list_of_dicts)
|
|
145
154
|
|
|
146
155
|
|
|
147
156
|
def convert_from_set(set_object: set) -> list:
|
|
@@ -152,4 +161,59 @@ def convert_from_set(set_object: set) -> list:
|
|
|
152
161
|
:return: list of dicts.
|
|
153
162
|
"""
|
|
154
163
|
|
|
155
|
-
return [loads(x) for x in set_object]
|
|
164
|
+
return [json.loads(x) for x in set_object]
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def summarize_entries(list_instance: list, list_of_keys_to_remove: list = None) -> list:
|
|
168
|
+
"""
|
|
169
|
+
The function will summarize entries in a list of dicts.
|
|
170
|
+
|
|
171
|
+
:param list_instance: list of dicts, the entries to summarize.
|
|
172
|
+
:param list_of_keys_to_remove: list, the keys to remove from each entry before summarizing.
|
|
173
|
+
:return: list, of the summarized entries, each entry without the keys in 'list_of_keys_to_remove',
|
|
174
|
+
including the count of the entry.
|
|
175
|
+
|
|
176
|
+
--------------------------------------
|
|
177
|
+
|
|
178
|
+
Example:
|
|
179
|
+
list_instance = [
|
|
180
|
+
{'time': '2021-08-01 00:00:00', 'name': 'name1', 'cmdline': 'cmdline1', 'domain': 'domain1'},
|
|
181
|
+
{'time': '2021-08-01 00:00:00', 'name': 'name2', 'cmdline': 'cmdline2', 'domain': 'domain2'},
|
|
182
|
+
{'time': '2021-08-01 00:00:00', 'name': 'name1', 'cmdline': 'cmdline1', 'domain': 'domain1'}
|
|
183
|
+
]
|
|
184
|
+
|
|
185
|
+
list_of_keys_to_remove = ['time', 'cmdline']
|
|
186
|
+
|
|
187
|
+
summarize_entries(list_instance, list_of_keys_to_remove)
|
|
188
|
+
|
|
189
|
+
Output:
|
|
190
|
+
[
|
|
191
|
+
{'name': 'name1', 'domain': 'domain1', 'count': 2},
|
|
192
|
+
{'name': 'name2', 'domain': 'domain2', 'count': 1}
|
|
193
|
+
]
|
|
194
|
+
"""
|
|
195
|
+
|
|
196
|
+
summed_entries: dict = dict()
|
|
197
|
+
for entry in list_instance:
|
|
198
|
+
# Copy the entry to new dict, since we're going to remove a key.
|
|
199
|
+
line_copied = entry.copy()
|
|
200
|
+
|
|
201
|
+
# Remove the keys in the 'list_of_keys_to_remove'.
|
|
202
|
+
if list_of_keys_to_remove:
|
|
203
|
+
for key in list_of_keys_to_remove:
|
|
204
|
+
_ = line_copied.pop(key, None)
|
|
205
|
+
|
|
206
|
+
line_json_string = json.dumps(line_copied)
|
|
207
|
+
if line_json_string not in summed_entries:
|
|
208
|
+
summed_entries[line_json_string] = 1
|
|
209
|
+
else:
|
|
210
|
+
summed_entries[line_json_string] += 1
|
|
211
|
+
|
|
212
|
+
result_list: list = []
|
|
213
|
+
for json_string_record, count in summed_entries.items():
|
|
214
|
+
record = json.loads(json_string_record)
|
|
215
|
+
result_list.append(
|
|
216
|
+
{**record, 'count': count}
|
|
217
|
+
)
|
|
218
|
+
|
|
219
|
+
return result_list
|
atomicshop/basics/lists.py
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import copy
|
|
2
|
+
|
|
3
|
+
|
|
1
4
|
def remove_duplicates(list_instance: list):
|
|
2
5
|
# One of the fastest methods.
|
|
3
6
|
seen = set()
|
|
@@ -109,3 +112,14 @@ def get_the_most_frequent_element_from_list(list_instance: list[str]) -> str:
|
|
|
109
112
|
"""
|
|
110
113
|
|
|
111
114
|
return max(set(list_instance), key=list_instance.count)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def copy_list_of_mutable_objects(list_instance: list) -> list:
|
|
118
|
+
"""
|
|
119
|
+
This function will copy the list of mutable objects. Meaning that all the mutable objects inside will be copied
|
|
120
|
+
as well.
|
|
121
|
+
:param list_instance: list.
|
|
122
|
+
:return: list.
|
|
123
|
+
"""
|
|
124
|
+
|
|
125
|
+
return copy.deepcopy(list_instance)
|