Skip to content

Commit a4c6dd9

Browse files
Made many refactoring changes, fixed bugs and improved code
[__init__.py] Added a library check to make sure its only imported Removal of config_data to Config.py (Created it as well) [_dev.py] [color_print()] Added new color cyan and new option to not print but input (also returns values) Changed inputs to color_print(is_input=True) Changed some messages to make them look better Changed how the logic of getting the file changes work, now its WAY more accurate and better and faster [Config.py] Added new file, this is for config data gain, [Ref: __init__.py] [Flag.py, Logicytics.py, packet_sniffer.py] Changed config to the CONFIG global var from __init__.py [Get.py] Changed list_of_files() logic to now only exclude files starting with '_' and any extensions and files passed down (rather than hardcoded files like Logicytics.py) Refactored the class and function to be more efficient as well as fixed some bugs [Logicytics.py] Added exclusion to get files to accommodate the new changes [Ref: Get.py] Mitigated potential bugs in __threaded method with ThreadPoolExecutor, added a try-except Mitigated potential bugs in backup if the path doesn't exist Made the subprocess opening for execute_new_window more safe by mitigating a bug if python doesn't exist in PATH, now it takes python PATH from sys.executable [packet_sniffer.py] Improved error logging messages Made method __get_port_info() safer by making the port_type optional defaulting to 'sport', also added validation to only allow 'sport' and 'dport' Added a retry timer in the code, thus script maxes execution at 30sec (based on max_retry_time) Made Sniff() init once only. [vulnscan.py] Improved Time bottleneck by only reading readable files that aren't part of UNREADABLE_EXTENSIONS list, thus now it will read/parse more than scan, which improves time and reduces issues Renamed some methods to be protected members Improved _is_sensitive by using sparse matrices Fixed bug where if result is empty, it crashes due to append of a variable that doesn't exist Remade the ThreadPoolExecutor logic for getting the files by improving its speed and efficiency Signed-off-by: Shahm Najeeb <[email protected]>
1 parent ec07aed commit a4c6dd9

File tree

10 files changed

+298
-228
lines changed

10 files changed

+298
-228
lines changed

.idea/csv-editor.xml

Lines changed: 0 additions & 16 deletions
This file was deleted.

CODE/Logicytics.py

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,22 @@
11
from __future__ import annotations
22

3-
import configparser
43
import os
54
import shutil
65
import subprocess
6+
import sys
77
import zipfile
88
from concurrent.futures import ThreadPoolExecutor, as_completed
99
from datetime import datetime
1010

1111
import psutil
1212
from prettytable import PrettyTable
1313

14-
from logicytics import Log, Execute, Check, Get, FileManagement, Flag, DEBUG, DELETE_LOGS
14+
from logicytics import Log, Execute, Check, Get, FileManagement, Flag, DEBUG, DELETE_LOGS, CONFIG
1515

1616
# Initialization
1717
log = Log({"log_level": DEBUG, "delete_log": DELETE_LOGS})
1818
ACTION, SUB_ACTION = None, None
19-
config = configparser.ConfigParser()
20-
config.read("config.ini")
21-
MAX_WORKERS = config.getint("Settings", "max_workers", fallback=min(32, (os.cpu_count() or 1) + 4))
19+
MAX_WORKERS = CONFIG.getint("Settings", "max_workers", fallback=min(32, (os.cpu_count() or 1) + 4))
2220
log.debug(f"MAX_WORKERS: {MAX_WORKERS}")
2321

2422

@@ -67,7 +65,8 @@ def __generate_execution_list(self) -> list[str]:
6765
- Logs the final execution list for debugging purposes
6866
- Warns users about potential long execution times for certain actions
6967
"""
70-
execution_list = Get.list_of_files(".", extensions=(".py", ".exe", ".ps1", ".bat"))
68+
execution_list = Get.list_of_files(".", only_extensions=(".py", ".exe", ".ps1", ".bat"),
69+
exclude_files=["Logicytics.py"])
7170
files_to_remove = {
7271
"sensitive_data_miner.py",
7372
"dir_list.py",
@@ -100,9 +99,8 @@ def __generate_execution_list(self) -> list[str]:
10099

101100
elif ACTION == "modded":
102101
# Add all files in MODS to execution list
103-
execution_list = Get.list_of_files("../MODS",
104-
extensions=(".py", ".exe", ".ps1", ".bat"),
105-
append_file_list=execution_list)
102+
execution_list = Get.list_of_files("../MODS", only_extensions=(".py", ".exe", ".ps1", ".bat"),
103+
append_file_list=execution_list, exclude_files=["Logicytics.py"])
106104

107105
elif ACTION == "depth":
108106
log.warning(
@@ -169,11 +167,14 @@ def __threaded(self):
169167

170168
for future in as_completed(futures):
171169
script = futures[future]
172-
result, error = future.result()
173-
if error:
174-
log.error(f"Failed to execute {script}")
175-
else:
176-
log.debug(f"Completed {script}")
170+
try:
171+
result, error = future.result()
172+
if error:
173+
log.error(f"Failed to execute {script}: {error}")
174+
else:
175+
log.debug(f"Completed {script}")
176+
except Exception as e:
177+
log.error(f"Thread crashed while executing {script}: {e}")
177178

178179
def __default(self):
179180
"""Executes scripts sequentially."""
@@ -246,6 +247,10 @@ def backup(directory: str, name: str):
246247
Returns:
247248
None
248249
"""
250+
if not os.path.exists(directory):
251+
log.critical(f"Directory {directory} does not exist!")
252+
return
253+
249254
# Check if backup exists, delete it if so
250255
if os.path.exists(f"../ACCESS/BACKUP/{name}.zip"):
251256
os.remove(f"../ACCESS/BACKUP/{name}.zip")
@@ -308,7 +313,7 @@ def execute_new_window(file_path: str):
308313
"""
309314
sr_current_dir = os.path.dirname(os.path.abspath(__file__))
310315
sr_script_path = os.path.join(sr_current_dir, file_path)
311-
sr_process = subprocess.Popen(["cmd.exe", "/c", "start", "python", sr_script_path])
316+
sr_process = subprocess.Popen(["cmd.exe", "/c", "start", sys.executable, sr_script_path])
312317
sr_process.wait()
313318
exit(0)
314319

@@ -507,6 +512,7 @@ def Logicytics():
507512
except KeyboardInterrupt:
508513
log.warning("Shutting down Logicytics utility with force causes many files to remain where they shouldn't")
509514
log.warning("Please don't force shut Logicytics again - As we don't have a cleanup function yet.")
515+
# TODO v3.4.2 -> Cleanup function
510516
exit(0)
511517
else:
512518
log.error("This script cannot be imported!")

CODE/_dev.py

Lines changed: 41 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from __future__ import annotations
22

3+
import os
34
import re
45
import subprocess
56

@@ -8,16 +9,20 @@
89
from logicytics import log, Get, FileManagement, CURRENT_FILES, VERSION
910

1011

11-
def color_print(text, color="reset"):
12+
def color_print(text, color="reset", is_input=False) -> None | str:
1213
colors = {
1314
"reset": "\033[0m",
1415
"red": "\033[31m",
1516
"green": "\033[32m",
1617
"yellow": "\033[33m",
18+
"cyan": "\033[36m",
1719
}
1820

1921
color_code = colors.get(color.lower(), colors["reset"])
20-
print(f"{color_code}{text}{colors['reset']}")
22+
if is_input:
23+
return input(f"{color_code}{text}{colors['reset']}")
24+
else:
25+
print(f"{color_code}{text}{colors['reset']}")
2126

2227

2328
def _update_ini_file(filename: str, new_data: list | str, key: str) -> None:
@@ -31,14 +36,16 @@ def _update_ini_file(filename: str, new_data: list | str, key: str) -> None:
3136
None
3237
"""
3338
try:
34-
config = configobj.ConfigObj(filename, encoding='utf-8', write_empty_values=True)
39+
config = configobj.ConfigObj(filename, encoding="utf-8", write_empty_values=True)
40+
3541
if key == "files":
3642
config["System Settings"][key] = ", ".join(new_data)
3743
elif key == "version":
3844
config["System Settings"][key] = new_data
3945
else:
4046
color_print(f"[!] Invalid key: {key}", "yellow")
4147
return
48+
4249
config.write()
4350
except FileNotFoundError:
4451
color_print("[x] INI file not found", "red")
@@ -69,7 +76,7 @@ def _prompt_user(question: str, file_to_open: str = None, special: bool = False)
6976
- Provides optional file opening and reminder messaging
7077
"""
7178
try:
72-
answer = input(f"\033[36m[?] {question} (y)es or (n)o:- \033[0m")
79+
answer = color_print(f"[?] {question} (y)es or (n)o:- ", "cyan", is_input=True)
7380
if not (answer.lower() == "yes" or answer.lower() == "y"):
7481
if file_to_open:
7582
subprocess.run(["start", file_to_open], shell=True)
@@ -91,11 +98,11 @@ def _perform_checks() -> bool:
9198
bool: True if all checks are confirmed by the user, False otherwise.
9299
"""
93100
checks = [
94-
("Have you read the required contributing guidelines?", "../CONTRIBUTING.md"),
95-
("Have you made files you don't want to be run start with '_'?", "."),
96-
("Have you added the file to CODE dir?", "."),
97-
("Have you added docstrings and comments?", "../CONTRIBUTING.md"),
98-
("Is each file containing around 1 main feature?", "../CONTRIBUTING.md"),
101+
("[-] Have you read the required contributing guidelines?", "..\\CONTRIBUTING.md"),
102+
("[-] Have you made files you don't want to be run start with '_'?", "."),
103+
("[-] Have you added the file to CODE dir?", "."),
104+
("[-] Have you added docstrings and comments?", "..\\CONTRIBUTING.md"),
105+
("[-] Is each file containing around 1 main feature?", "..\\CONTRIBUTING.md"),
99106
]
100107

101108
for question, file_to_open in checks:
@@ -109,48 +116,49 @@ def _handle_file_operations() -> None:
109116
Handles file operations and logging for added, removed, and normal files.
110117
"""
111118
EXCLUDE_FILES = ["logicytics\\User_History.json.gz", "logicytics\\User_History.json"]
112-
files = Get.list_of_files(".", True, exclude_files=EXCLUDE_FILES)
119+
files = Get.list_of_files(".", exclude_files=EXCLUDE_FILES)
113120
added_files, removed_files, normal_files = [], [], []
114121
clean_files_list = [file.replace('"', '') for file in CURRENT_FILES]
115122

116-
for f in files:
117-
clean_f = f.replace('"', '')
118-
if clean_f in clean_files_list and clean_f not in EXCLUDE_FILES:
119-
normal_files.append(clean_f)
120-
elif clean_f not in EXCLUDE_FILES:
121-
added_files.append(clean_f)
122-
123-
for f in clean_files_list:
124-
clean_f = f.replace('"', '')
125-
if clean_f not in files and clean_f not in EXCLUDE_FILES:
126-
removed_files.append(clean_f)
127-
128-
for file in added_files:
129-
color_print(f"+ {file}", "green")
130-
for file in removed_files:
131-
color_print(f"- {file}", "red")
132-
for file in normal_files:
133-
print(f"* {file}")
134-
135-
if not _prompt_user("Does the list above include your added files?"):
123+
files_set = set(os.path.abspath(f) for f in files)
124+
clean_files_set = set(os.path.abspath(f) for f in clean_files_list)
125+
126+
for file in files_set:
127+
if file in clean_files_set and file not in EXCLUDE_FILES:
128+
normal_files.append(file)
129+
elif file not in clean_files_set and file not in EXCLUDE_FILES:
130+
added_files.append(file)
131+
132+
for file in clean_files_set:
133+
if file not in files_set and file not in EXCLUDE_FILES:
134+
removed_files.append(file)
135+
136+
print("\n".join([f"\033[92m+ {file}\033[0m" for file in added_files])) # Green +
137+
print("\n".join([f"\033[91m- {file}\033[0m" for file in removed_files])) # Red -
138+
print("\n".join([f"* {file}" for file in normal_files]))
139+
140+
if not _prompt_user("[-] Does the list above include your added files?"):
136141
color_print("[x] Something went wrong! Please contact support.", "red")
137142
return
138143

139144
max_attempts = 10
140145
attempts = 0
141146
_update_ini_file("config.ini", files, "files")
147+
142148
while True:
143-
version = input(f"\033[36m[?] Enter the new version of the project (Old version is {VERSION}): \033[0m")
149+
version = color_print(f"[?] Enter the new version of the project (Old version is {VERSION}): ", "cyan",
150+
is_input=True)
144151
if attempts >= max_attempts:
145152
color_print("[x] Maximum attempts reached. Please run the script again.", "red")
146153
exit()
147-
if re.match(r'^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$', version):
154+
if re.match(r"^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$", version):
148155
_update_ini_file("config.ini", version, "version")
149156
break
150157
else:
151158
color_print("[!] Please enter a valid version number (e.g., 1.2.3)", "yellow")
152159
attempts += 1
153160
color_print(f"[!] {max_attempts - attempts} attempts remaining", "yellow")
161+
154162
color_print("\n[-] Great Job! Please tick the box in the GitHub PR request for completing steps in --dev", "green")
155163

156164

@@ -188,4 +196,4 @@ def dev_checks() -> None:
188196
if __name__ == "__main__":
189197
dev_checks()
190198
# Wait for the user to press Enter to exit the program
191-
input("\nPress Enter to exit the program... ")
199+
input("\n[*] Press Enter to exit the program... ")

CODE/logicytics/Config.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import configparser
2+
import os
3+
4+
5+
def __config_data() -> tuple[str, str, list[str], bool, str]:
6+
"""
7+
Retrieves configuration data from the 'config.ini' file.
8+
9+
If the configuration file is not found in any of these locations,
10+
the program exits with an error message.
11+
12+
Returns:
13+
tuple[str, str, list[str], bool]: A tuple containing:
14+
- Log level (str): Either "DEBUG" or "INFO"
15+
- Version (str): System version from configuration
16+
- Files (list[str]): List of files specified in configuration
17+
- Delete old logs (bool): Flag indicating whether to delete old log files
18+
- CONFIG itself
19+
20+
Raises:
21+
SystemExit: If the 'config.ini' file cannot be found in any of the attempted locations
22+
"""
23+
24+
def _config_path() -> str:
25+
configs_path = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "config.ini")
26+
27+
if os.path.exists(configs_path):
28+
return configs_path
29+
else:
30+
print("The config.ini file is not found in the expected location.")
31+
exit(1)
32+
33+
config = configparser.ConfigParser()
34+
path = _config_path()
35+
config.read(path)
36+
37+
log_using_debug = config.getboolean("Settings", "log_using_debug")
38+
delete_old_logs = config.getboolean("Settings", "delete_old_logs")
39+
version = config.get("System Settings", "version")
40+
files = config.get("System Settings", "files").split(", ")
41+
42+
log_using_debug = "DEBUG" if log_using_debug else "INFO"
43+
44+
return log_using_debug, version, files, delete_old_logs, config
45+
46+
47+
# Check if the script is being run directly, if not, set up the library
48+
if __name__ == '__main__':
49+
exit("This is a library, Please import rather than directly run.")
50+
DEBUG, VERSION, CURRENT_FILES, DELETE_LOGS, CONFIG = __config_data()

0 commit comments

Comments
 (0)