atomicshop 2.15.11__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/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/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/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/enums.py +2 -2
- atomicshop/basics/exceptions.py +5 -1
- atomicshop/basics/list_of_classes.py +29 -0
- atomicshop/basics/multiprocesses.py +374 -50
- atomicshop/basics/strings.py +72 -3
- atomicshop/basics/threads.py +14 -0
- atomicshop/basics/tracebacks.py +13 -3
- atomicshop/certificates.py +153 -52
- atomicshop/config_init.py +11 -6
- atomicshop/console_user_response.py +7 -14
- atomicshop/consoles.py +9 -0
- atomicshop/datetimes.py +1 -1
- atomicshop/diff_check.py +3 -3
- atomicshop/dns.py +128 -3
- atomicshop/etws/_pywintrace_fix.py +17 -0
- atomicshop/etws/trace.py +40 -42
- atomicshop/etws/traces/trace_dns.py +56 -44
- atomicshop/etws/traces/trace_tcp.py +130 -0
- atomicshop/file_io/csvs.py +27 -5
- atomicshop/file_io/docxs.py +34 -17
- atomicshop/file_io/file_io.py +31 -17
- atomicshop/file_io/jsons.py +49 -0
- atomicshop/file_io/tomls.py +139 -0
- atomicshop/filesystem.py +616 -291
- atomicshop/get_process_list.py +3 -3
- 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 -80
- 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 +136 -40
- atomicshop/mitm/statistic_analyzer_helper/moving_average_helper.py +265 -83
- atomicshop/monitor/checks/dns.py +1 -1
- atomicshop/networks.py +671 -0
- atomicshop/on_exit.py +39 -9
- 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 -42
- atomicshop/process.py +24 -6
- atomicshop/process_poller/process_pool.py +0 -1
- atomicshop/process_poller/simple_process_pool.py +204 -5
- atomicshop/python_file_patcher.py +1 -1
- atomicshop/python_functions.py +27 -75
- atomicshop/speech_recognize.py +8 -0
- atomicshop/ssh_remote.py +158 -172
- atomicshop/system_resource_monitor.py +61 -47
- atomicshop/system_resources.py +8 -8
- atomicshop/tempfiles.py +1 -2
- atomicshop/urls.py +6 -0
- atomicshop/venvs.py +28 -0
- atomicshop/versioning.py +27 -0
- atomicshop/web.py +98 -27
- 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/const.py +97 -47
- atomicshop/wrappers/ctyping/etw_winapi/etw_functions.py +178 -49
- 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 +2 -2
- 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/githubw.py +537 -54
- atomicshop/wrappers/loggingw/consts.py +1 -1
- atomicshop/wrappers/loggingw/filters.py +23 -0
- atomicshop/wrappers/loggingw/formatters.py +12 -0
- atomicshop/wrappers/loggingw/handlers.py +214 -107
- atomicshop/wrappers/loggingw/loggers.py +19 -0
- atomicshop/wrappers/loggingw/loggingw.py +860 -22
- atomicshop/wrappers/loggingw/reading.py +134 -112
- atomicshop/wrappers/mongodbw/mongo_infra.py +31 -0
- atomicshop/wrappers/mongodbw/mongodbw.py +1324 -36
- 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 +37 -1
- atomicshop/wrappers/psutilw/psutil_networks.py +85 -0
- atomicshop/wrappers/pyopensslw.py +9 -2
- atomicshop/wrappers/pywin32w/cert_store.py +116 -0
- atomicshop/wrappers/pywin32w/win_event_log/fetch.py +174 -0
- atomicshop/wrappers/pywin32w/win_event_log/subscribes/process_create.py +3 -105
- atomicshop/wrappers/pywin32w/win_event_log/subscribes/process_terminate.py +3 -57
- 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 +491 -182
- 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 +11 -7
- 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 +1 -1
- 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.15.11.dist-info → atomicshop-3.10.5.dist-info}/METADATA +31 -51
- atomicshop-3.10.5.dist-info/RECORD +306 -0
- {atomicshop-2.15.11.dist-info → atomicshop-3.10.5.dist-info}/WHEEL +1 -1
- atomicshop/_basics_temp.py +0 -101
- atomicshop/a_installs/win/fibratus.py +0 -9
- atomicshop/a_installs/win/mongodb.py +0 -9
- atomicshop/a_installs/win/pycharm.py +0 -9
- 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/__pycache__/install_fibratus_windows.cpython-312.pyc +0 -0
- atomicshop/addons/mains/__pycache__/msi_unpacker.cpython-312.pyc +0 -0
- 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/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/file_types.py +0 -24
- atomicshop/mitm/config_editor.py +0 -37
- atomicshop/mitm/engines/create_module_template_example.py +0 -13
- atomicshop/mitm/initialize_mitm_server.py +0 -268
- atomicshop/pbtkmultifile_argparse.py +0 -88
- atomicshop/permissions.py +0 -151
- 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/fibratusw/install.py +0 -81
- atomicshop/wrappers/mongodbw/infrastructure.py +0 -53
- atomicshop/wrappers/mongodbw/install_mongodb.py +0 -190
- atomicshop/wrappers/msiw.py +0 -149
- atomicshop/wrappers/nodejsw/install_nodejs.py +0 -139
- atomicshop/wrappers/process_wrapper_pbtk.py +0 -16
- atomicshop/wrappers/psutilw/networks.py +0 -45
- atomicshop/wrappers/pycharmw.py +0 -81
- atomicshop/wrappers/socketw/base.py +0 -59
- atomicshop/wrappers/socketw/get_process.py +0 -107
- atomicshop/wrappers/wslw.py +0 -191
- atomicshop-2.15.11.dist-info/RECORD +0 -302
- /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 → 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 → a_mains/addons}/process_list/compile.cmd +0 -0
- /atomicshop/{addons → a_mains/addons}/process_list/compiled/Win10x64/process_list.dll +0 -0
- /atomicshop/{addons → a_mains/addons}/process_list/compiled/Win10x64/process_list.exp +0 -0
- /atomicshop/{addons → a_mains/addons}/process_list/compiled/Win10x64/process_list.lib +0 -0
- /atomicshop/{addons → a_mains/addons}/process_list/process_list.cpp +0 -0
- /atomicshop/{archiver → permissions}/__init__.py +0 -0
- /atomicshop/{wrappers/fibratusw → web_apis}/__init__.py +0 -0
- /atomicshop/wrappers/{nodejsw → pywin32w/wmis}/__init__.py +0 -0
- /atomicshop/wrappers/pywin32w/{wmi_win32process.py → wmis/win32process.py} +0 -0
- {atomicshop-2.15.11.dist-info → atomicshop-3.10.5.dist-info/licenses}/LICENSE.txt +0 -0
- {atomicshop-2.15.11.dist-info → atomicshop-3.10.5.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import datetime
|
|
2
|
+
import os
|
|
3
|
+
import multiprocessing
|
|
4
|
+
import logging
|
|
5
|
+
import zipfile
|
|
6
|
+
import shutil
|
|
7
|
+
|
|
8
|
+
from .. import filesystem, print_api
|
|
9
|
+
from .. wrappers.loggingw import consts, loggingw
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
REC_FILE_DATE_TIME_MILLISECONDS_FORMAT: str = f'{consts.DEFAULT_ROTATING_SUFFIXES_FROM_WHEN["S"]}_%f'
|
|
13
|
+
REC_FILE_DATE_TIME_FORMAT: str = f'{consts.DEFAULT_ROTATING_SUFFIXES_FROM_WHEN["S"]}'
|
|
14
|
+
REC_FILE_DATE_FORMAT: str = REC_FILE_DATE_TIME_FORMAT.split('_')[0]
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def archive(
|
|
18
|
+
directory_path: str,
|
|
19
|
+
include_root_directory: bool = True,
|
|
20
|
+
) -> str:
|
|
21
|
+
"""
|
|
22
|
+
Function archives the directory.
|
|
23
|
+
:param directory_path: string, full path to the directory.
|
|
24
|
+
:param include_root_directory: boolean, default is 'True'.
|
|
25
|
+
'True': The root directory will be included in the archive.
|
|
26
|
+
'False': The root directory will not be included in the archive.
|
|
27
|
+
True is usually the case in most archiving utilities.
|
|
28
|
+
:return: string, full path to the archived file.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
# This is commonly used and supported by most ZIP utilities.
|
|
32
|
+
compression_method = zipfile.ZIP_DEFLATED
|
|
33
|
+
|
|
34
|
+
archive_path: str = directory_path + '.zip'
|
|
35
|
+
with zipfile.ZipFile(archive_path, 'w', compression_method) as zip_object:
|
|
36
|
+
for root, _, files in os.walk(directory_path):
|
|
37
|
+
for file in files:
|
|
38
|
+
file_path = os.path.join(root, file)
|
|
39
|
+
|
|
40
|
+
# If including the root directory, use the relative path from the parent directory of the root
|
|
41
|
+
if include_root_directory:
|
|
42
|
+
arcname = os.path.relpath(file_path, os.path.dirname(directory_path))
|
|
43
|
+
else:
|
|
44
|
+
arcname = os.path.relpath(file_path, directory_path)
|
|
45
|
+
|
|
46
|
+
zip_object.write(file_path, arcname)
|
|
47
|
+
|
|
48
|
+
return archive_path
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def recs_archiver(
|
|
52
|
+
recs_directory: str,
|
|
53
|
+
logging_queue: multiprocessing.Queue,
|
|
54
|
+
logger_name: str,
|
|
55
|
+
finalize_output_queue: multiprocessing.Queue
|
|
56
|
+
) -> list | None:
|
|
57
|
+
"""
|
|
58
|
+
Find recs files in a directory for each day.
|
|
59
|
+
Each day of recordings will have separate archive.
|
|
60
|
+
|
|
61
|
+
:param recs_directory: The directory where recordings are stored.
|
|
62
|
+
:param logging_queue: The queue for logging messages.
|
|
63
|
+
:param logger_name: The name of the logger to use for logging.
|
|
64
|
+
This is the base name that '.rec_packer' will be added to it.
|
|
65
|
+
:param finalize_output_queue: output queue for results/exceptions.
|
|
66
|
+
"""
|
|
67
|
+
|
|
68
|
+
logger_name = f"{logger_name}.rec_packer"
|
|
69
|
+
|
|
70
|
+
rec_packer_logger_with_queue_handler: logging.Logger = loggingw.create_logger(
|
|
71
|
+
logger_name=logger_name,
|
|
72
|
+
add_queue_handler=True,
|
|
73
|
+
log_queue=logging_queue)
|
|
74
|
+
|
|
75
|
+
print_api.print_api(
|
|
76
|
+
'Starting recs archiver process.', color='blue',
|
|
77
|
+
logger=rec_packer_logger_with_queue_handler
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
today_date_string = datetime.datetime.now().strftime(REC_FILE_DATE_FORMAT)
|
|
81
|
+
|
|
82
|
+
# There should not be recording json files in recs root.
|
|
83
|
+
files_in_recs_root: list = filesystem.get_paths_from_directory(
|
|
84
|
+
recs_directory, get_file=True, file_name_check_pattern='*\\.json', recursive=False)
|
|
85
|
+
if files_in_recs_root:
|
|
86
|
+
raise NotImplementedError("The files in recs root directory are not implemented yet.")
|
|
87
|
+
|
|
88
|
+
# Each engine should have its own directory inside recordings. We will find all the directories inside recs folder.
|
|
89
|
+
directory_paths_in_recs: list = filesystem.get_paths_from_directory(
|
|
90
|
+
recs_directory, get_directory=True, recursive=False)
|
|
91
|
+
|
|
92
|
+
file_list_per_directory: list = list()
|
|
93
|
+
for directory_path in directory_paths_in_recs:
|
|
94
|
+
all_recs_files = filesystem.get_paths_from_directory(
|
|
95
|
+
directory_path=directory_path.path,
|
|
96
|
+
get_file=True,
|
|
97
|
+
file_name_check_pattern='*.json',
|
|
98
|
+
datetime_format=REC_FILE_DATE_FORMAT,
|
|
99
|
+
recursive=False
|
|
100
|
+
)
|
|
101
|
+
file_list_per_directory.append((directory_path, all_recs_files))
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
try:
|
|
105
|
+
archived_files: list = list()
|
|
106
|
+
for directory_path, all_recs_files in file_list_per_directory:
|
|
107
|
+
print_api.print_api(f"Archiving recs files in directory: {directory_path.path}",
|
|
108
|
+
logger=rec_packer_logger_with_queue_handler, color='blue')
|
|
109
|
+
for recs_atomic_path in all_recs_files:
|
|
110
|
+
# We don't need to archive today's files.
|
|
111
|
+
if today_date_string == recs_atomic_path.datetime_string:
|
|
112
|
+
continue
|
|
113
|
+
|
|
114
|
+
target_directory_path: str = f"{directory_path.path}{os.sep}{recs_atomic_path.datetime_string}"
|
|
115
|
+
filesystem.create_directory(target_directory_path)
|
|
116
|
+
filesystem.move_file(
|
|
117
|
+
recs_atomic_path.path, target_directory_path)
|
|
118
|
+
|
|
119
|
+
# Archive directories.
|
|
120
|
+
archive_directories: list = filesystem.get_paths_from_directory(
|
|
121
|
+
directory_path.path, get_directory=True, recursive=False)
|
|
122
|
+
|
|
123
|
+
if not archive_directories:
|
|
124
|
+
print_api.print_api(
|
|
125
|
+
f"No directories to archive in: {directory_path.path}",
|
|
126
|
+
color='blue',
|
|
127
|
+
logger=rec_packer_logger_with_queue_handler
|
|
128
|
+
)
|
|
129
|
+
else:
|
|
130
|
+
total_archived_files: int = 0
|
|
131
|
+
for archive_directory in archive_directories:
|
|
132
|
+
files_to_archive: list = filesystem.get_paths_from_directory(
|
|
133
|
+
directory_path=archive_directory.path, get_file=True, recursive=False)
|
|
134
|
+
total_archived_files += len(files_to_archive)
|
|
135
|
+
archived_file: str = archive(archive_directory.path, include_root_directory=True)
|
|
136
|
+
# Remove the original directory after archiving.
|
|
137
|
+
shutil.rmtree(archive_directory.path, ignore_errors=True)
|
|
138
|
+
archived_files.append(archived_file)
|
|
139
|
+
|
|
140
|
+
print_api.print_api(
|
|
141
|
+
f'Archived: 'f'Directories: {len(archive_directories)} | '
|
|
142
|
+
f'Total Files: {total_archived_files} | In: {directory_path.path}',
|
|
143
|
+
logger=rec_packer_logger_with_queue_handler, color='blue')
|
|
144
|
+
print_api.print_api(f'Archived files: {archived_files}', logger=rec_packer_logger_with_queue_handler)
|
|
145
|
+
|
|
146
|
+
finalize_output_queue.put(None)
|
|
147
|
+
|
|
148
|
+
print_api.print_api(
|
|
149
|
+
'Finished recs archiver process.', color='blue',
|
|
150
|
+
logger=rec_packer_logger_with_queue_handler
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
return archived_files
|
|
154
|
+
except Exception as e:
|
|
155
|
+
print_api.print_api(
|
|
156
|
+
f"Error while archiving recs files: {e}",
|
|
157
|
+
color='red',
|
|
158
|
+
logger=rec_packer_logger_with_queue_handler
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
finalize_output_queue.put(e)
|
|
162
|
+
return None
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def recs_archiver_in_process(
|
|
166
|
+
recs_directory: str,
|
|
167
|
+
logging_queue: multiprocessing.Queue,
|
|
168
|
+
logger_name: str,
|
|
169
|
+
finalize_output_queue: multiprocessing.Queue
|
|
170
|
+
) -> multiprocessing.Process:
|
|
171
|
+
"""
|
|
172
|
+
Archive recs files in a directory for each day in a separate process.
|
|
173
|
+
|
|
174
|
+
:param recs_directory: The directory where recordings are stored.
|
|
175
|
+
:param logging_queue: The queue for logging messages.
|
|
176
|
+
:param logger_name: The name of the logger to use for logging.
|
|
177
|
+
:param finalize_output_queue: output queue for results/exceptions.
|
|
178
|
+
"""
|
|
179
|
+
|
|
180
|
+
process = multiprocessing.Process(
|
|
181
|
+
target=recs_archiver, args=(recs_directory, logging_queue, logger_name, finalize_output_queue))
|
|
182
|
+
process.start()
|
|
183
|
+
return process
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import json
|
|
2
|
-
# Needed to get the function caller module.
|
|
3
1
|
import inspect
|
|
4
2
|
|
|
5
3
|
from ..wrappers.loggingw import loggingw
|
|
6
|
-
|
|
4
|
+
|
|
5
|
+
from . import config_static
|
|
7
6
|
|
|
8
7
|
|
|
9
8
|
# If the string has several dot characters (".") - return the most right string after the last dot.
|
|
@@ -33,12 +32,7 @@ def create_custom_logger():
|
|
|
33
32
|
# 'f_globals' is a dictionary of all the global variables of the calling initiated class.
|
|
34
33
|
class_name = calling_frame.f_globals['__name__']
|
|
35
34
|
# Get the logger name only.
|
|
36
|
-
|
|
35
|
+
engine_logger_part = build_module_names(class_name)[0]
|
|
36
|
+
logger_name = f'{config_static.MainConfig.LOGGER_NAME}.{engine_logger_part}'
|
|
37
37
|
|
|
38
38
|
return loggingw.get_logger_with_level(logger_name)
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
def get_json(obj):
|
|
42
|
-
""" Convert any nested object to json / dict and values to string as is """
|
|
43
|
-
|
|
44
|
-
return json.dumps(obj, default=dicts.convert_complex_object_to_dict)
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import socket
|
|
2
|
+
|
|
3
|
+
import paramiko
|
|
4
|
+
|
|
5
|
+
from .. import package_mains_processor, ssh_remote, config_init
|
|
6
|
+
from ..wrappers.socketw import process_getter
|
|
7
|
+
from ..print_api import print_api
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
PORT_TO_CMD_FILE: str = 'process_from_port'
|
|
11
|
+
TCP_PORTS_FILE: str = 'get_local_tcp_ports'
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def test_ssh_main(config: dict) -> int:
|
|
15
|
+
hosts: list = config['main']['hosts_or_ips']
|
|
16
|
+
|
|
17
|
+
for host in hosts:
|
|
18
|
+
print("-----------------------------------")
|
|
19
|
+
print_api(f"Testing cmd for host: {host}", color='blue')
|
|
20
|
+
|
|
21
|
+
if host in config['main']:
|
|
22
|
+
print("Using host-specific credentials")
|
|
23
|
+
username = config[host]['user']
|
|
24
|
+
password = config[host]['pass']
|
|
25
|
+
else:
|
|
26
|
+
print("Didn't find host-specific credential, using defaults")
|
|
27
|
+
username = config['all_hosts']['user']
|
|
28
|
+
password = config['all_hosts']['pass']
|
|
29
|
+
|
|
30
|
+
ssh_client = ssh_remote.SSHRemote(ip_address=host, username=username, password=password)
|
|
31
|
+
|
|
32
|
+
try:
|
|
33
|
+
ssh_client.connect()
|
|
34
|
+
except socket.gaierror as e:
|
|
35
|
+
if e.errno == 11001:
|
|
36
|
+
print_api(f"Couldn't resolve IP to {host}: {str(e)}\n"
|
|
37
|
+
f"Try providing IP address instead of hostname", color='red')
|
|
38
|
+
continue
|
|
39
|
+
else:
|
|
40
|
+
raise e
|
|
41
|
+
except paramiko.ssh_exception.NoValidConnectionsError as e:
|
|
42
|
+
print_api(f"Couldn't connect to {host}: {str(e)}", color='red')
|
|
43
|
+
continue
|
|
44
|
+
|
|
45
|
+
# Read the TCP ports file to string.
|
|
46
|
+
tcp_ports_package_processor: package_mains_processor.PackageMainsProcessor = package_mains_processor.PackageMainsProcessor(
|
|
47
|
+
script_file_stem=TCP_PORTS_FILE)
|
|
48
|
+
tcp_ports_script_string: str = tcp_ports_package_processor.read_script_file_to_string()
|
|
49
|
+
|
|
50
|
+
# Execute the TCP ports script remotely via SSH to get the list of open TCP ports.
|
|
51
|
+
tcp_ports_output, tcp_ports_error = ssh_client.remote_execution_python(script_string=tcp_ports_script_string)
|
|
52
|
+
if tcp_ports_error:
|
|
53
|
+
print_api(f"Error getting TCP ports from host {host}: {tcp_ports_error}", color='red')
|
|
54
|
+
continue
|
|
55
|
+
|
|
56
|
+
tcp_ports_list: list = tcp_ports_output.strip().splitlines()
|
|
57
|
+
if not tcp_ports_list:
|
|
58
|
+
print_api(f"No TCP ports found on host {host}", color='red')
|
|
59
|
+
continue
|
|
60
|
+
|
|
61
|
+
last_port: int = int(tcp_ports_list[-1])
|
|
62
|
+
|
|
63
|
+
port_to_cmd_package_processor: package_mains_processor.PackageMainsProcessor = package_mains_processor.PackageMainsProcessor(
|
|
64
|
+
script_file_stem=PORT_TO_CMD_FILE)
|
|
65
|
+
get_command_instance = process_getter.GetCommandLine(
|
|
66
|
+
client_ip=host,
|
|
67
|
+
client_port=last_port,
|
|
68
|
+
package_processor=port_to_cmd_package_processor,
|
|
69
|
+
ssh_client=ssh_client)
|
|
70
|
+
process_name = get_command_instance.get_process_name()
|
|
71
|
+
print(f"Process for port {last_port} on host {host}: {process_name}")
|
|
72
|
+
|
|
73
|
+
print("Closing SSH connection")
|
|
74
|
+
ssh_client.close()
|
|
75
|
+
|
|
76
|
+
if not process_name:
|
|
77
|
+
print_api(f"Failed to get process name for port {last_port} on host {host}", color='red')
|
|
78
|
+
continue
|
|
79
|
+
|
|
80
|
+
print_api(f"SSH test success!", color='green')
|
|
81
|
+
|
|
82
|
+
return 0
|
|
@@ -2,6 +2,7 @@ import os
|
|
|
2
2
|
import datetime
|
|
3
3
|
import json
|
|
4
4
|
from typing import Union, Literal
|
|
5
|
+
import argparse
|
|
5
6
|
|
|
6
7
|
from .statistic_analyzer_helper import analyzer_helper, moving_average_helper
|
|
7
8
|
from .. import filesystem, domains, datetimes, urls
|
|
@@ -28,9 +29,9 @@ def analyze(main_file_path: str):
|
|
|
28
29
|
summary_path: str = filesystem.check_absolute_path___add_full(config['report_file_path'], script_directory)
|
|
29
30
|
|
|
30
31
|
# Get the content from statistics files.
|
|
32
|
+
log_file_path_pattern: str = f"{config['statistic_files_path']}{os.sep}statistics.csv"
|
|
31
33
|
statistics_content: list = reading.get_all_log_files_into_list(
|
|
32
|
-
|
|
33
|
-
file_name_pattern='statistics*.csv',
|
|
34
|
+
log_file_path=log_file_path_pattern,
|
|
34
35
|
log_type='csv'
|
|
35
36
|
)
|
|
36
37
|
|
|
@@ -344,21 +345,33 @@ def analyze(main_file_path: str):
|
|
|
344
345
|
# ======================================================================================================================
|
|
345
346
|
|
|
346
347
|
|
|
347
|
-
def
|
|
348
|
-
statistics_file_directory: str,
|
|
349
|
-
|
|
350
|
-
|
|
348
|
+
def deviation_calculator_by_moving_average(
|
|
349
|
+
statistics_file_directory: str = None,
|
|
350
|
+
statistics_content: dict = None,
|
|
351
|
+
by_type: Literal['host', 'url'] = 'url',
|
|
352
|
+
moving_average_window_days: int = 5,
|
|
353
|
+
top_bottom_deviation_percentage: float = 0.25,
|
|
351
354
|
get_deviation_for_last_day_only: bool = False,
|
|
355
|
+
get_deviation_for_date: str = None,
|
|
352
356
|
summary: bool = False,
|
|
353
357
|
output_file_path: str = None,
|
|
354
|
-
output_file_type: Literal['json', 'csv'] = 'json'
|
|
358
|
+
output_file_type: Literal['json', 'csv'] = 'json',
|
|
359
|
+
convert_sizes_lists_and_ma_data_to_string: bool = False,
|
|
360
|
+
skip_total_count_less_than: int = None
|
|
355
361
|
) -> Union[list, None]:
|
|
356
362
|
"""
|
|
357
363
|
This function is the main function for the moving average calculator.
|
|
358
364
|
|
|
359
|
-
:param statistics_file_directory: string, the directory where 'statistics.csv' file resides
|
|
365
|
+
:param statistics_file_directory: string, can be either providing the directory where 'statistics.csv' file resides
|
|
366
|
+
or None. If None, the 'statistics_content' must be provided.
|
|
367
|
+
The directory where 'statistics.csv' file resides.
|
|
360
368
|
Also, all the rotated files like: statistics_2021-01-01.csv, statistics_2021-01-02.csv, etc.
|
|
361
369
|
These will be analyzed in the order of the date in the file name.
|
|
370
|
+
:param statistics_content: dict, if specified, this will be used instead of reading the files from the directory.
|
|
371
|
+
The dict should be a result of the 'atomicshop.mitm.statistic_analyzer_helper.moving_average_helper.get_all_files_content'.
|
|
372
|
+
:param by_type: string, 'host' or 'url'. The type of the deviation calculation.
|
|
373
|
+
'host' will calculate the deviation by the host name. Example: maps.google.com, yahoo.com, etc.
|
|
374
|
+
'url' will calculate the deviation by the URL. Example: maps.google.com/maps, yahoo.com/news, etc.
|
|
362
375
|
:param moving_average_window_days: integer, the moving average window days.
|
|
363
376
|
:param top_bottom_deviation_percentage: float, the top bottom deviation percentage. Example: 0.1 for 10%.
|
|
364
377
|
:param get_deviation_for_last_day_only: bool, if True, only the last day will be analyzed.
|
|
@@ -374,10 +387,20 @@ def deviation_calculator_by_moving_average_main(
|
|
|
374
387
|
Files 01 to 05 will be used for moving average and the file 06 for deviation.
|
|
375
388
|
Meaning the average calculated for 2021-01-06 will be compared to the values moving average of 2021-01-01
|
|
376
389
|
to 2021-01-05.
|
|
390
|
+
:param get_deviation_for_date: string, if specified, only the specified date will be analyzed.
|
|
391
|
+
The date must be in the format of 'YYYY-MM-DD'. Example: '2021-01-06'.
|
|
377
392
|
:param summary: bool, if True, Only the summary will be generated without all the numbers that were used
|
|
378
393
|
to calculate the averages and the moving average data.
|
|
379
394
|
:param output_file_path: string, if None, no file will be written.
|
|
380
395
|
:param output_file_type: string, the type of the output file. 'json' or 'csv'.
|
|
396
|
+
:param convert_sizes_lists_and_ma_data_to_string: bool, if True, the 'request_sizes', 'response_sizes' and 'ma_data'
|
|
397
|
+
will be converted to string. This is useful when writing to files, so the view will be more readable.
|
|
398
|
+
:param skip_total_count_less_than: integer, if specified, the deviation calculation will be skipped
|
|
399
|
+
if the total count is less than this number.
|
|
400
|
+
This means that if we have moving average window of 7 days, on the 8th day, the deviation will be calculated
|
|
401
|
+
only if the total count of the checked type
|
|
402
|
+
(request average size, response average, request count, response count)
|
|
403
|
+
is greater or equal to this number.
|
|
381
404
|
-----------------------------
|
|
382
405
|
:return: the deviation list of dicts.
|
|
383
406
|
|
|
@@ -399,11 +422,6 @@ def deviation_calculator_by_moving_average_main(
|
|
|
399
422
|
sys.exit(main())
|
|
400
423
|
"""
|
|
401
424
|
|
|
402
|
-
if output_file_type not in ['json', 'csv']:
|
|
403
|
-
raise ValueError(f'output_file_type must be "json" or "csv", not [{output_file_type}]')
|
|
404
|
-
|
|
405
|
-
statistics_file_path: str = f'{statistics_file_directory}{os.sep}{STATISTICS_FILE_NAME}'
|
|
406
|
-
|
|
407
425
|
def convert_data_value_to_string(value_key: str, list_index: int) -> None:
|
|
408
426
|
deviation_list[list_index]['data'][value_key] = json.dumps(deviation_list[list_index]['data'][value_key])
|
|
409
427
|
|
|
@@ -411,43 +429,53 @@ def deviation_calculator_by_moving_average_main(
|
|
|
411
429
|
if value_key in deviation_list[list_index]:
|
|
412
430
|
deviation_list[list_index][value_key] = json.dumps(deviation_list[list_index][value_key])
|
|
413
431
|
|
|
432
|
+
if not statistics_file_directory and not statistics_content:
|
|
433
|
+
raise ValueError('Either [statistics_file_directory] or [statistics_content] must be provided.')
|
|
434
|
+
if statistics_file_directory and statistics_content:
|
|
435
|
+
raise ValueError('Either [statistics_file_directory] or [statistics_content] must be provided, not both.')
|
|
436
|
+
|
|
437
|
+
if output_file_type not in ['json', 'csv']:
|
|
438
|
+
raise ValueError(f'output_file_type must be "json" or "csv", not [{output_file_type}]')
|
|
439
|
+
|
|
440
|
+
if by_type not in ['host', 'url']:
|
|
441
|
+
raise ValueError(f'by_type must be "host" or "url", not [{by_type}]')
|
|
442
|
+
|
|
443
|
+
if get_deviation_for_last_day_only and get_deviation_for_date:
|
|
444
|
+
raise ValueError('Either [get_deviation_for_last_day_only] or [get_deviation_for_date] can be provided, not both.')
|
|
445
|
+
|
|
446
|
+
if statistics_file_directory:
|
|
447
|
+
statistics_file_path: str | None = f'{statistics_file_directory}{os.sep}{STATISTICS_FILE_NAME}'
|
|
448
|
+
else:
|
|
449
|
+
statistics_file_path: str | None = None
|
|
450
|
+
|
|
414
451
|
deviation_list = moving_average_helper.calculate_moving_average(
|
|
415
452
|
statistics_file_path,
|
|
453
|
+
statistics_content,
|
|
454
|
+
by_type,
|
|
416
455
|
moving_average_window_days,
|
|
417
456
|
top_bottom_deviation_percentage,
|
|
418
|
-
get_deviation_for_last_day_only
|
|
457
|
+
get_deviation_for_last_day_only,
|
|
458
|
+
get_deviation_for_date,
|
|
459
|
+
skip_total_count_less_than
|
|
419
460
|
)
|
|
420
461
|
|
|
421
462
|
if deviation_list:
|
|
463
|
+
if convert_sizes_lists_and_ma_data_to_string:
|
|
464
|
+
for deviation_list_index, deviation in enumerate(deviation_list):
|
|
465
|
+
convert_data_value_to_string('request_sizes', deviation_list_index)
|
|
466
|
+
convert_data_value_to_string('response_sizes', deviation_list_index)
|
|
467
|
+
convert_value_to_string('ma_data', deviation_list_index)
|
|
468
|
+
|
|
422
469
|
if summary:
|
|
423
|
-
summary_deviation_list: list = []
|
|
424
470
|
for deviation in deviation_list:
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
summary_deviation_list.append({
|
|
433
|
-
'day': deviation['day'],
|
|
434
|
-
'host': deviation['host'],
|
|
435
|
-
'message': deviation['message'],
|
|
436
|
-
'value': deviation.get('value', None),
|
|
437
|
-
'ma_value': deviation.get('ma_value', None),
|
|
438
|
-
'deviation_percentage': deviation.get('deviation_percentage', None),
|
|
439
|
-
'total_entries_averaged': total_entries_averaged
|
|
440
|
-
})
|
|
441
|
-
|
|
442
|
-
deviation_list = summary_deviation_list
|
|
471
|
+
_ = deviation.pop('check_type')
|
|
472
|
+
_ = deviation.pop('percentage')
|
|
473
|
+
_ = deviation.pop('ma_value_checked')
|
|
474
|
+
_ = deviation.pop('deviation_type')
|
|
475
|
+
_ = deviation.pop('data')
|
|
476
|
+
_ = deviation.pop('ma_data')
|
|
443
477
|
|
|
444
478
|
if output_file_path:
|
|
445
|
-
if not summary:
|
|
446
|
-
for deviation_list_index, deviation in enumerate(deviation_list):
|
|
447
|
-
convert_data_value_to_string('request_sizes', deviation_list_index)
|
|
448
|
-
convert_data_value_to_string('response_sizes', deviation_list_index)
|
|
449
|
-
convert_value_to_string('ma_data', deviation_list_index)
|
|
450
|
-
|
|
451
479
|
print_api(f'Deviation Found, saving to file: {output_file_path}', color='blue')
|
|
452
480
|
|
|
453
481
|
if output_file_type == 'csv':
|
|
@@ -457,4 +485,72 @@ def deviation_calculator_by_moving_average_main(
|
|
|
457
485
|
|
|
458
486
|
return deviation_list
|
|
459
487
|
|
|
460
|
-
return
|
|
488
|
+
return []
|
|
489
|
+
|
|
490
|
+
|
|
491
|
+
def deviation_calculator_by_moving_average_main():
|
|
492
|
+
def parse_args():
|
|
493
|
+
description_full: str = (
|
|
494
|
+
f'Description: Calculate deviation by moving average.')
|
|
495
|
+
|
|
496
|
+
parser = argparse.ArgumentParser(
|
|
497
|
+
description=description_full)
|
|
498
|
+
|
|
499
|
+
parser.add_argument(
|
|
500
|
+
'-d', '--directory', type=str, required=True,
|
|
501
|
+
help='Provide full path to directory with statistics.csv files.')
|
|
502
|
+
parser.add_argument(
|
|
503
|
+
'-of', '--output_file', type=str, required=True, help='Provide full path to output file.')
|
|
504
|
+
parser.add_argument(
|
|
505
|
+
'-ot', '--output_type', type=str, required=True, help='Provide output type: [json] or [csv].')
|
|
506
|
+
parser.add_argument(
|
|
507
|
+
'-by', '--by_type', type=str, required=True, help='Calculate by [host] or [url].')
|
|
508
|
+
parser.add_argument(
|
|
509
|
+
'-f', '--full_details', action='store_true', required=False,
|
|
510
|
+
help='(OPTIONAL) Output full processing details instead of summary.')
|
|
511
|
+
parser.add_argument(
|
|
512
|
+
'-w', '--window', type=int, required=True, help='Moving average window in days.')
|
|
513
|
+
parser.add_argument(
|
|
514
|
+
'-p', '--percentage', type=float, required=True,
|
|
515
|
+
help='Percentage of deviation from moving average. Example: 0.1 for 10%%.')
|
|
516
|
+
parser.add_argument(
|
|
517
|
+
'-slt', '--skip_total_count_less_than', type=int, required=False,
|
|
518
|
+
help='An integer to skip the deviation calculation if the total count is less than this number.')
|
|
519
|
+
|
|
520
|
+
return parser.parse_args()
|
|
521
|
+
|
|
522
|
+
args = parse_args()
|
|
523
|
+
|
|
524
|
+
if args.output_type == 'csv' and args.full_details:
|
|
525
|
+
print_api("Full details output is not supported for csv files.", color='red')
|
|
526
|
+
return 1
|
|
527
|
+
|
|
528
|
+
if not os.path.isdir(args.directory):
|
|
529
|
+
print_api(f"Directory does not exist: {args.directory}", color='red')
|
|
530
|
+
return 1
|
|
531
|
+
|
|
532
|
+
if not filesystem.get_paths_from_directory(
|
|
533
|
+
directory_path=args.directory, get_file=True, simple_list=True, file_name_check_pattern='*statistics*.csv'):
|
|
534
|
+
print_api(f"No statistics files found in: {args.directory}", color='red')
|
|
535
|
+
return 1
|
|
536
|
+
|
|
537
|
+
if args.full_details:
|
|
538
|
+
summary = False
|
|
539
|
+
convert_sizes_lists_and_ma_data_to_string = True
|
|
540
|
+
else:
|
|
541
|
+
summary = True
|
|
542
|
+
convert_sizes_lists_and_ma_data_to_string = False
|
|
543
|
+
|
|
544
|
+
_ = deviation_calculator_by_moving_average(
|
|
545
|
+
statistics_file_directory=args.directory,
|
|
546
|
+
by_type=args.by_type,
|
|
547
|
+
moving_average_window_days=args.window,
|
|
548
|
+
top_bottom_deviation_percentage=args.percentage,
|
|
549
|
+
summary=summary,
|
|
550
|
+
output_file_path=args.output_file,
|
|
551
|
+
output_file_type=args.output_type,
|
|
552
|
+
convert_sizes_lists_and_ma_data_to_string=convert_sizes_lists_and_ma_data_to_string,
|
|
553
|
+
skip_total_count_less_than=args.skip_total_count_less_than
|
|
554
|
+
)
|
|
555
|
+
|
|
556
|
+
return 0
|