-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathSecure_Pass_Pro.pyw
More file actions
215 lines (192 loc) Β· 9.69 KB
/
Copy pathSecure_Pass_Pro.pyw
File metadata and controls
215 lines (192 loc) Β· 9.69 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Secure Pass Pro v4.0 β Cryptographically secure password generator
Author: Maxim Melnikov
ΠΠ°ΠΏΡΡΠΊ (Windows): double-click Secure_Pass_Pro.pyw
ΠΠ°ΠΏΡΡΠΊ (Linux/macOS): python3 Secure_Pass_Pro.pyw
"""
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# STEP 0 β bootstrap: must work before ANY local import
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
import sys
import os
import traceback
# Fix working directory & sys.path so local packages are always found
# (critical when launched by double-click β CWD is often wrong)
_HERE = os.path.dirname(os.path.abspath(__file__))
os.chdir(_HERE) # make CWD = project root
for _p in (_HERE, os.path.dirname(_HERE)):
if _p not in sys.path:
sys.path.insert(0, _p)
# ββ Early error reporter (works before tkinter/customtkinter) ββββ
def _fatal(title: str, message: str, exc: BaseException = None) -> None:
"""Show an error dialog and exit. Works even if the app never started."""
import tkinter as _tk
from tkinter import messagebox as _mb
_root = _tk.Tk()
_root.withdraw()
_root.attributes("-topmost", True)
full_msg = message
if exc:
full_msg += f"\n\n{type(exc).__name__}: {exc}"
full_msg += f"\n\n{traceback.format_exc()}"
_mb.showerror(title, full_msg)
_root.destroy()
sys.exit(1)
# ββ Verify Python version ββββββββββββββββββββββββββββββββββββββ
if sys.version_info < (3, 8):
_fatal("Python version error",
f"Secure Pass Pro requires Python 3.8+.\n"
f"Current: {sys.version}\n\n"
f"Interpreter: {sys.executable}")
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# STEP 1 β logger (safe fallback so crashes are always logged)
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
try:
from utils.logger import get_logger, log_crash_report, setup_logging as _setup_logging
_setup_logging() # configure root Β«sppΒ» logger once at startup
# Initialise ConfigManager (scans SECUREPASS_* env vars)
from core.config_manager import ConfigManager as _CM
_CM.instance() # singleton created here, env vars cached
# Hide all sensitive data directories immediately (Windows)
try:
from utils.paths import hide_all_app_dirs as _hide_dirs
_hide_dirs()
except Exception:
pass
logger = get_logger("launcher")
except Exception as _log_err: # noqa: BLE001
# stdlib fallback β keeps the rest of the code working
import logging as _logging
_logging.basicConfig(
level=_logging.DEBUG,
filename=os.path.join(_HERE, "startup_error.log"),
filemode="w",
format="%(asctime)s %(levelname)s %(name)s: %(message)s",
)
logger = _logging.getLogger("launcher")
logger.error("Could not import utils.logger: %s", _log_err)
def log_crash_report(exc, ctx=None): # type: ignore[override]
logger.exception("CRASH: %s | context=%s", exc, ctx)
_fatal(
"Import error",
"Could not load utils.logger.\n\n"
f"Project folder:\n {_HERE}\n\n"
f"Python:\n {sys.executable}\n\n"
"Make sure you are running this file from the Secure Pass Pro folder "
"and that all dependencies are installed.\n\n"
f"Error: {_log_err}",
_log_err,
)
logger.info("Launcher started | Python %s | cwd=%s", sys.version, _HERE)
logger.info("sys.executable = %s", sys.executable)
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# STEP 2 β optional modules (non-fatal if missing)
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
try:
from security.antidebug import init_anti_debug
init_anti_debug()
logger.debug("Anti-debug initialized")
except ImportError:
logger.warning("Anti-debug module not available")
except Exception as _e: # noqa: BLE001
logger.error("Anti-debug init error: %s", _e)
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# STEP 3 β check critical dependencies before importing the GUI
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
def _check_deps() -> None:
import importlib.util
missing = []
for mod, pkg in [
("customtkinter", "customtkinter"),
("PIL", "Pillow"),
("cryptography", "cryptography"),
]:
if importlib.util.find_spec(mod) is None:
missing.append(pkg)
if missing:
_fatal(
"Missing dependencies",
"The following packages are not installed:\n\n"
+ "".join(f" β’ {p}\n" for p in missing)
+ "\nRun in a terminal:\n\n"
f" pip install {' '.join(missing)}\n\n"
f"(Python: {sys.executable})",
)
_check_deps()
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# STEP 4 β load config (lang / theme)
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
import json
_CONFIG_DIR = os.path.join(_HERE, ".securepass")
_CONFIG_FILE = os.path.join(_CONFIG_DIR, "config.json")
def _load_config():
try:
os.makedirs(_CONFIG_DIR, exist_ok=True)
except (OSError, PermissionError):
pass
lang, theme = "RU", "dark"
try:
if os.path.exists(_CONFIG_FILE):
with open(_CONFIG_FILE, "r", encoding="utf-8") as _f:
_cfg = json.load(_f)
if _cfg.get("LANG") in ("RU", "EN", "UA"):
lang = _cfg["LANG"]
if _cfg.get("THEME") == "Light":
theme = "light"
elif _cfg.get("THEME") == "Dark":
theme = "dark"
except (json.JSONDecodeError, OSError, PermissionError, KeyError, ValueError) as _e:
logger.warning("Config load error: %s", _e)
return lang, theme
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# STEP 5 β main application
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
if __name__ == "__main__":
try:
import customtkinter as ctk
from gui.main_window import SecurePassPro
from security.master import MasterPassword
from core.app_settings import AppSettings as _AS
_s = _AS.instance()
startup_lang = _s.language
startup_theme = _s.theme
logger.info("Config loaded: lang=%s theme=%s", startup_lang, startup_theme)
# Apply appearance before any window is created
try:
ctk.set_appearance_mode(startup_theme)
ctk.set_default_color_theme("blue")
except (ValueError, AttributeError, RuntimeError) as _e:
logger.error("Appearance mode error: %s", _e)
# Master-password prompt
try:
if not MasterPassword.prompt_on_startup(startup_lang, startup_theme):
logger.info("Closed at master-password screen")
sys.exit(0)
except (ImportError, AttributeError, RuntimeError, OSError) as _e:
logger.error("Master password error: %s", _e)
_fatal("Master password error",
"Could not open the master password dialog.", _e)
# Main window
try:
import tkinter as tk
app = SecurePassPro()
logger.info("Application started")
app.mainloop()
except (RuntimeError, OSError, tk.TclError, AttributeError) as _e:
logger.critical("Runtime error: %s", _e)
log_crash_report(_e, {"stage": "main"})
_fatal("Runtime error", "The application encountered a fatal error.", _e)
except SystemExit:
raise # honour sys.exit() calls
except Exception as _e: # noqa: BLE001 β true catch-all
logger.critical("Unhandled exception: %s", _e, exc_info=True)
log_crash_report(_e, {"stage": "startup"})
_fatal(
"Fatal startup error",
"Secure Pass Pro failed to start.\n\n"
f"Project folder:\n {_HERE}\n\n"
f"Python:\n {sys.executable}",
_e,
)