Генерация безопасных паролей.py 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731
  1. import tkinter as tk
  2. from tkinter import messagebox, scrolledtext, ttk
  3. import string
  4. import random
  5. import sqlite3
  6. from datetime import datetime
  7. import json
  8. import os
  9. class PasswordGenerator:
  10. def __init__(self):
  11. self.root = tk.Tk()
  12. self.root.title("Генератор надежных паролей PRO")
  13. self.root.geometry("750x700")
  14. # Инициализация базы данных ДО создания интерфейса
  15. self.init_database()
  16. self.setup_ui()
  17. # Переменные для настроек
  18. self.current_password = ""
  19. self.history_limit = 15
  20. self.config_file = "config.json"
  21. self.load_config()
  22. def setup_ui(self):
  23. # Создание стилей
  24. style = ttk.Style()
  25. style.configure('Custom.TButton', font=('Arial', 10, 'bold'))
  26. style.configure('Title.TLabel', font=('Arial', 16, 'bold'))
  27. # Главный контейнер
  28. main_frame = ttk.Frame(self.root, padding="20")
  29. main_frame.pack(fill=tk.BOTH, expand=True)
  30. # Заголовок
  31. title_label = ttk.Label(main_frame, text="🔐 ГЕНЕРАТОР НАДЕЖНЫХ ПАРОЛЕЙ",
  32. style='Title.TLabel')
  33. title_label.pack(pady=(0, 20))
  34. # Фрейм настроек
  35. settings_frame = ttk.LabelFrame(main_frame, text="Настройки генерации", padding="15")
  36. settings_frame.pack(fill=tk.X, pady=(0, 15))
  37. # Длина пароля
  38. length_frame = ttk.Frame(settings_frame)
  39. length_frame.pack(fill=tk.X, pady=5)
  40. self.length_label = ttk.Label(length_frame, text="Длина пароля:", width=15)
  41. self.length_label.pack(side=tk.LEFT)
  42. self.length_var = tk.IntVar(value=16)
  43. self.length_slider = ttk.Scale(length_frame, from_=8, to=32,
  44. variable=self.length_var, orient=tk.HORIZONTAL)
  45. self.length_slider.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=10)
  46. self.length_display = ttk.Label(length_frame, textvariable=self.length_var, width=3)
  47. self.length_display.pack(side=tk.LEFT)
  48. # Чекбоксы для символов
  49. self.letters_var = tk.BooleanVar(value=True)
  50. self.digits_var = tk.BooleanVar(value=True)
  51. self.punctuation_var = tk.BooleanVar(value=True)
  52. self.exclude_similar = tk.BooleanVar(value=True)
  53. self.exclude_ambiguous = tk.BooleanVar(value=False)
  54. checks_frame = ttk.Frame(settings_frame)
  55. checks_frame.pack(fill=tk.X, pady=10)
  56. ttk.Checkbutton(checks_frame, text="Буквы (A-Z, a-z)",
  57. variable=self.letters_var).pack(side=tk.LEFT, padx=10)
  58. ttk.Checkbutton(checks_frame, text="Цифры (0-9)",
  59. variable=self.digits_var).pack(side=tk.LEFT, padx=10)
  60. ttk.Checkbutton(checks_frame, text="Спецсимволы (!@#$%)",
  61. variable=self.punctuation_var).pack(side=tk.LEFT, padx=10)
  62. advanced_frame = ttk.Frame(settings_frame)
  63. advanced_frame.pack(fill=tk.X, pady=5)
  64. ttk.Checkbutton(advanced_frame, text="Исключить похожие символы (i, l, 1, L, o, 0, O)",
  65. variable=self.exclude_similar).pack(side=tk.LEFT, padx=10)
  66. ttk.Checkbutton(advanced_frame, text="Исключить неоднозначные символы ({[]}<>\\|)",
  67. variable=self.exclude_ambiguous).pack(side=tk.LEFT, padx=10)
  68. # Кнопка генерации
  69. self.generate_btn = ttk.Button(main_frame, text="⚡ СГЕНЕРИРОВАТЬ ПАРОЛЬ",
  70. command=self.generate_password,
  71. style='Custom.TButton')
  72. self.generate_btn.pack(pady=10)
  73. # Отображение пароля
  74. result_frame = ttk.LabelFrame(main_frame, text="Сгенерированный пароль", padding="15")
  75. result_frame.pack(fill=tk.X, pady=(0, 15))
  76. self.password_var = tk.StringVar()
  77. self.password_entry = ttk.Entry(result_frame, textvariable=self.password_var,
  78. font=('Courier', 14), justify='center')
  79. self.password_entry.pack(fill=tk.X)
  80. # Кнопки действий с паролем
  81. action_frame = ttk.Frame(main_frame)
  82. action_frame.pack(pady=(0, 15))
  83. ttk.Button(action_frame, text="📋 Копировать",
  84. command=self.copy_to_clipboard).pack(side=tk.LEFT, padx=5)
  85. ttk.Button(action_frame, text="💾 Сохранить",
  86. command=self.save_password).pack(side=tk.LEFT, padx=5)
  87. ttk.Button(action_frame, text="🔄 Новый",
  88. command=self.generate_password).pack(side=tk.LEFT, padx=5)
  89. ttk.Button(action_frame, text="🔍 Проверить надежность",
  90. command=self.check_strength).pack(side=tk.LEFT, padx=5)
  91. # История паролей
  92. history_frame = ttk.LabelFrame(main_frame, text="История паролей", padding="15")
  93. history_frame.pack(fill=tk.BOTH, expand=True, pady=(0, 15))
  94. # Панель инструментов истории
  95. history_toolbar = ttk.Frame(history_frame)
  96. history_toolbar.pack(fill=tk.X, pady=(0, 10))
  97. ttk.Button(history_toolbar, text="🔄 Обновить",
  98. command=self.load_history).pack(side=tk.LEFT, padx=2)
  99. ttk.Button(history_toolbar, text="🗑️ Очистить",
  100. command=self.clear_history_confirm).pack(side=tk.LEFT, padx=2)
  101. ttk.Button(history_toolbar, text="📤 Экспорт",
  102. command=self.export_history).pack(side=tk.LEFT, padx=2)
  103. ttk.Button(history_toolbar, text="📊 Статистика",
  104. command=self.show_statistics).pack(side=tk.LEFT, padx=2)
  105. # Таблица истории
  106. columns = ('id', 'password', 'strength', 'timestamp')
  107. self.history_tree = ttk.Treeview(history_frame, columns=columns, show='headings', height=8)
  108. self.history_tree.heading('id', text='ID')
  109. self.history_tree.heading('password', text='Пароль')
  110. self.history_tree.heading('strength', text='Надежность')
  111. self.history_tree.heading('timestamp', text='Время создания')
  112. self.history_tree.column('id', width=50, anchor='center')
  113. self.history_tree.column('password', width=200)
  114. self.history_tree.column('strength', width=100, anchor='center')
  115. self.history_tree.column('timestamp', width=150)
  116. scrollbar = ttk.Scrollbar(history_frame, orient=tk.VERTICAL, command=self.history_tree.yview)
  117. self.history_tree.configure(yscrollcommand=scrollbar.set)
  118. self.history_tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
  119. scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
  120. # Привязка событий
  121. self.history_tree.bind('<Double-Button-1>', self.on_history_select)
  122. # Статус бар
  123. self.status_bar = ttk.Label(main_frame, text="Готов к работе", relief=tk.SUNKEN)
  124. self.status_bar.pack(side=tk.BOTTOM, fill=tk.X)
  125. # Меню
  126. self.create_menu()
  127. def create_menu(self):
  128. menubar = tk.Menu(self.root)
  129. self.root.config(menu=menubar)
  130. # Меню Файл
  131. file_menu = tk.Menu(menubar, tearoff=0)
  132. menubar.add_cascade(label="Файл", menu=file_menu)
  133. file_menu.add_command(label="Сохранить настройки", command=self.save_config)
  134. file_menu.add_command(label="Загрузить настройки", command=self.load_config)
  135. file_menu.add_separator()
  136. file_menu.add_command(label="Экспорт всех паролей", command=self.export_all_passwords)
  137. file_menu.add_separator()
  138. file_menu.add_command(label="Выход", command=self.root.quit)
  139. # Меню Настройки
  140. settings_menu = tk.Menu(menubar, tearoff=0)
  141. menubar.add_cascade(label="Настройки", menu=settings_menu)
  142. settings_menu.add_command(label="Ограничение истории",
  143. command=self.set_history_limit)
  144. settings_menu.add_command(label="Сбросить настройки",
  145. command=self.reset_settings)
  146. # Меню Справка
  147. help_menu = tk.Menu(menubar, tearoff=0)
  148. menubar.add_cascade(label="Справка", menu=help_menu)
  149. help_menu.add_command(label="О программе", command=self.show_about)
  150. help_menu.add_command(label="Рекомендации", command=self.show_tips)
  151. def init_database(self):
  152. try:
  153. conn = sqlite3.connect('passwords.db')
  154. cursor = conn.cursor()
  155. # Проверяем существование таблицы
  156. cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='passwords'")
  157. table_exists = cursor.fetchone()
  158. if table_exists:
  159. # Проверяем структуру существующей таблицы
  160. cursor.execute("PRAGMA table_info(passwords)")
  161. columns = cursor.fetchall()
  162. column_names = [col[1] for col in columns]
  163. # Если таблица создавалась по старому коду, пересоздаем её
  164. if 'generated_password' in column_names:
  165. # Сохраняем старые данные
  166. cursor.execute("SELECT generated_password, timestamp FROM passwords")
  167. old_data = cursor.fetchall()
  168. # Удаляем старую таблицу
  169. cursor.execute("DROP TABLE passwords")
  170. # Создаем новую таблицу
  171. cursor.execute('''
  172. CREATE TABLE passwords (
  173. id INTEGER PRIMARY KEY AUTOINCREMENT,
  174. password TEXT NOT NULL,
  175. strength TEXT,
  176. timestamp DATETIME DEFAULT CURRENT_TIMESTAMP
  177. )
  178. ''')
  179. # Восстанавливаем данные
  180. for data in old_data:
  181. password = data[0]
  182. timestamp = data[1]
  183. strength = self.calculate_strength(password)
  184. cursor.execute('''
  185. INSERT INTO passwords (password, strength, timestamp)
  186. VALUES (?, ?, ?)
  187. ''', (password, strength, timestamp))
  188. elif 'password' not in column_names:
  189. # Таблица существует, но нет колонки password - добавляем
  190. cursor.execute('''
  191. ALTER TABLE passwords ADD COLUMN password TEXT
  192. ''')
  193. else:
  194. # Создаем новую таблицу
  195. cursor.execute('''
  196. CREATE TABLE passwords (
  197. id INTEGER PRIMARY KEY AUTOINCREMENT,
  198. password TEXT NOT NULL,
  199. strength TEXT,
  200. timestamp DATETIME DEFAULT CURRENT_TIMESTAMP
  201. )
  202. ''')
  203. conn.commit()
  204. conn.close()
  205. except Exception as e:
  206. messagebox.showerror("Ошибка", f"Ошибка инициализации БД: {str(e)}")
  207. def generate_password(self):
  208. try:
  209. length = self.length_var.get()
  210. selected_chars = ''
  211. if self.letters_var.get():
  212. letters = string.ascii_letters
  213. if self.exclude_similar.get():
  214. letters = letters.replace('i', '').replace('l', '').replace('I', '').replace('L', '')
  215. letters = letters.replace('o', '').replace('O', '')
  216. selected_chars += letters
  217. if self.digits_var.get():
  218. digits = string.digits
  219. if self.exclude_similar.get():
  220. digits = digits.replace('0', '').replace('1', '')
  221. selected_chars += digits
  222. if self.punctuation_var.get():
  223. punctuation = string.punctuation
  224. if self.exclude_ambiguous.get():
  225. ambiguous = '{}[]()<>\\|`~'
  226. for char in ambiguous:
  227. punctuation = punctuation.replace(char, '')
  228. selected_chars += punctuation
  229. if not selected_chars:
  230. messagebox.showwarning("Предупреждение",
  231. "Выберите хотя бы один тип символов!")
  232. return
  233. # Гарантируем хотя бы по одному символу каждого выбранного типа
  234. password_chars = []
  235. if self.letters_var.get():
  236. letters = string.ascii_letters
  237. if self.exclude_similar.get():
  238. letters = letters.replace('i', '').replace('l', '').replace('I', '').replace('L', '')
  239. letters = letters.replace('o', '').replace('O', '')
  240. password_chars.append(random.choice(letters))
  241. length -= 1
  242. if self.digits_var.get():
  243. digits = string.digits
  244. if self.exclude_similar.get():
  245. digits = digits.replace('0', '').replace('1', '')
  246. password_chars.append(random.choice(digits))
  247. length -= 1
  248. if self.punctuation_var.get():
  249. punctuation = string.punctuation
  250. if self.exclude_ambiguous.get():
  251. ambiguous = '{}[]()<>\\|`~'
  252. for char in ambiguous:
  253. punctuation = punctuation.replace(char, '')
  254. password_chars.append(random.choice(punctuation))
  255. length -= 1
  256. # Добавляем остальные случайные символы
  257. for _ in range(max(0, length)):
  258. password_chars.append(random.choice(selected_chars))
  259. # Перемешиваем символы
  260. random.shuffle(password_chars)
  261. password = ''.join(password_chars)
  262. self.current_password = password
  263. self.password_var.set(password)
  264. # Определяем цвет в зависимости от надежности
  265. strength = self.calculate_strength(password)
  266. color = self.get_strength_color(strength)
  267. self.password_entry.config(foreground=color)
  268. self.status_bar.config(text=f"Пароль сгенерирован | Надежность: {strength}")
  269. except Exception as e:
  270. messagebox.showerror("Ошибка", f"Произошла ошибка: {str(e)}")
  271. def calculate_strength(self, password):
  272. score = 0
  273. # Длина
  274. if len(password) >= 20:
  275. score += 3
  276. elif len(password) >= 16:
  277. score += 2
  278. elif len(password) >= 12:
  279. score += 1
  280. # Разнообразие символов
  281. has_upper = any(c.isupper() for c in password)
  282. has_lower = any(c.islower() for c in password)
  283. has_digit = any(c.isdigit() for c in password)
  284. has_special = any(c in string.punctuation for c in password)
  285. types_count = sum([has_upper, has_lower, has_digit, has_special])
  286. score += types_count
  287. # Сложность
  288. if len(set(password)) / len(password) > 0.7:
  289. score += 1
  290. if score >= 6:
  291. return "Очень надежный"
  292. elif score >= 4:
  293. return "Надежный"
  294. elif score >= 2:
  295. return "Средний"
  296. else:
  297. return "Слабый"
  298. def get_strength_color(self, strength):
  299. colors = {
  300. "Очень надежный": "green",
  301. "Надежный": "blue",
  302. "Средний": "orange",
  303. "Слабый": "red"
  304. }
  305. return colors.get(strength, "black")
  306. def copy_to_clipboard(self):
  307. if self.current_password:
  308. self.root.clipboard_clear()
  309. self.root.clipboard_append(self.current_password)
  310. self.status_bar.config(text="Пароль скопирован в буфер обмена")
  311. messagebox.showinfo("Успех", "Пароль скопирован в буфер обмена!")
  312. else:
  313. messagebox.showwarning("Предупреждение", "Сначала сгенерируйте пароль!")
  314. def save_password(self):
  315. if not self.current_password:
  316. messagebox.showwarning("Предупреждение", "Сначала сгенерируйте пароль!")
  317. return
  318. try:
  319. conn = sqlite3.connect('passwords.db')
  320. cursor = conn.cursor()
  321. strength = self.calculate_strength(self.current_password)
  322. cursor.execute('''
  323. INSERT INTO passwords (password, strength, timestamp)
  324. VALUES (?, ?, ?)
  325. ''', (self.current_password, strength, datetime.now().strftime('%Y-%m-%d %H:%M:%S')))
  326. conn.commit()
  327. conn.close()
  328. self.load_history()
  329. self.status_bar.config(text="Пароль сохранен в базу данных")
  330. messagebox.showinfo("Успех", "Пароль успешно сохранен!")
  331. except Exception as e:
  332. messagebox.showerror("Ошибка", f"Не удалось сохранить пароль: {str(e)}")
  333. def load_history(self):
  334. try:
  335. # Очищаем дерево
  336. for item in self.history_tree.get_children():
  337. self.history_tree.delete(item)
  338. conn = sqlite3.connect('passwords.db')
  339. cursor = conn.cursor()
  340. cursor.execute('''
  341. SELECT id, password, strength, timestamp
  342. FROM passwords
  343. ORDER BY id DESC
  344. LIMIT ?
  345. ''', (self.history_limit,))
  346. records = cursor.fetchall()
  347. for record in records:
  348. # Маскируем пароль для отображения
  349. masked_password = self.mask_password(record[1])
  350. self.history_tree.insert('', 'end', values=(
  351. record[0], masked_password, record[2], record[3]
  352. ))
  353. conn.close()
  354. self.status_bar.config(text=f"Загружено {len(records)} записей")
  355. except Exception as e:
  356. messagebox.showerror("Ошибка", f"Не удалось загрузить историю: {str(e)}")
  357. def mask_password(self, password):
  358. if not password:
  359. return "****"
  360. if len(password) <= 4:
  361. return "****"
  362. return password[:2] + "*" * (len(password) - 4) + password[-2:]
  363. def on_history_select(self, event):
  364. selection = self.history_tree.selection()
  365. if selection:
  366. item = self.history_tree.item(selection[0])
  367. item_id = item['values'][0]
  368. conn = sqlite3.connect('passwords.db')
  369. cursor = conn.cursor()
  370. cursor.execute('SELECT password FROM passwords WHERE id = ?', (item_id,))
  371. result = cursor.fetchone()
  372. conn.close()
  373. if result:
  374. password = result[0]
  375. self.current_password = password
  376. self.password_var.set(password)
  377. self.status_bar.config(text=f"Выбран пароль ID: {item_id}")
  378. def clear_history_confirm(self):
  379. if messagebox.askyesno("Подтверждение",
  380. "Вы уверены, что хотите очистить всю историю паролей?"):
  381. self.clear_history()
  382. def clear_history(self):
  383. try:
  384. conn = sqlite3.connect('passwords.db')
  385. cursor = conn.cursor()
  386. cursor.execute("DELETE FROM passwords")
  387. conn.commit()
  388. conn.close()
  389. self.load_history()
  390. messagebox.showinfo("Успех", "История паролей очищена!")
  391. except Exception as e:
  392. messagebox.showerror("Ошибка", f"Не удалось очистить историю: {str(e)}")
  393. def check_strength(self):
  394. if not self.current_password:
  395. messagebox.showwarning("Предупреждение", "Сначала сгенерируйте пароль!")
  396. return
  397. strength = self.calculate_strength(self.current_password)
  398. color = self.get_strength_color(strength)
  399. analysis = self.analyze_password(self.current_password)
  400. messagebox.showinfo("Анализ пароля",
  401. f"Надежность: {strength}\n\n"
  402. f"Длина: {len(self.current_password)} символов\n"
  403. f"Заглавные буквы: {'Есть' if any(c.isupper() for c in self.current_password) else 'Нет'}\n"
  404. f"Строчные буквы: {'Есть' if any(c.islower() for c in self.current_password) else 'Нет'}\n"
  405. f"Цифры: {'Есть' if any(c.isdigit() for c in self.current_password) else 'Нет'}\n"
  406. f"Спецсимволы: {'Есть' if any(c in string.punctuation for c in self.current_password) else 'Нет'}\n\n"
  407. f"{analysis}")
  408. def analyze_password(self, password):
  409. suggestions = []
  410. if len(password) < 12:
  411. suggestions.append("• Увеличьте длину пароля (рекомендуется 12+ символов)")
  412. if not any(c.isupper() for c in password):
  413. suggestions.append("• Добавьте заглавные буквы")
  414. if not any(c.islower() for c in password):
  415. suggestions.append("• Добавьте строчные буквы")
  416. if not any(c.isdigit() for c in password):
  417. suggestions.append("• Добавьте цифры")
  418. if not any(c in string.punctuation for c in password):
  419. suggestions.append("• Добавьте специальные символы")
  420. if len(set(password)) / len(password) < 0.6:
  421. suggestions.append("• Используйте больше уникальных символов")
  422. if suggestions:
  423. return "Рекомендации:\n" + "\n".join(suggestions)
  424. else:
  425. return "Пароль соответствует всем рекомендациям безопасности!"
  426. def export_history(self):
  427. try:
  428. conn = sqlite3.connect('passwords.db')
  429. cursor = conn.cursor()
  430. cursor.execute('SELECT * FROM passwords ORDER BY id DESC')
  431. records = cursor.fetchall()
  432. conn.close()
  433. if not records:
  434. messagebox.showwarning("Предупреждение", "Нет данных для экспорта!")
  435. return
  436. filename = f"passwords_export_{datetime.now().strftime('%Y%m%d_%H%M%S')}.txt"
  437. with open(filename, 'w', encoding='utf-8') as f:
  438. f.write("Экспорт паролей\n")
  439. f.write("=" * 50 + "\n\n")
  440. for record in records:
  441. f.write(f"ID: {record[0]}\n")
  442. f.write(f"Пароль: {record[1]}\n")
  443. f.write(f"Надежность: {record[2]}\n")
  444. f.write(f"Создан: {record[3]}\n")
  445. f.write("-" * 30 + "\n")
  446. self.status_bar.config(text=f"Данные экспортированы в файл: {filename}")
  447. messagebox.showinfo("Успех", f"Данные успешно экспортированы в файл:\n{filename}")
  448. except Exception as e:
  449. messagebox.showerror("Ошибка", f"Ошибка экспорта: {str(e)}")
  450. def export_all_passwords(self):
  451. self.export_history()
  452. def show_statistics(self):
  453. try:
  454. conn = sqlite3.connect('passwords.db')
  455. cursor = conn.cursor()
  456. cursor.execute("SELECT COUNT(*) FROM passwords")
  457. total = cursor.fetchone()[0]
  458. cursor.execute("SELECT COUNT(*) FROM passwords WHERE strength = 'Очень надежный'")
  459. very_strong = cursor.fetchone()[0]
  460. cursor.execute("SELECT COUNT(*) FROM passwords WHERE strength = 'Надежный'")
  461. strong = cursor.fetchone()[0]
  462. cursor.execute("SELECT COUNT(*) FROM passwords WHERE strength = 'Средний'")
  463. medium = cursor.fetchone()[0]
  464. cursor.execute("SELECT COUNT(*) FROM passwords WHERE strength = 'Слабый'")
  465. weak = cursor.fetchone()[0]
  466. cursor.execute("SELECT MIN(timestamp), MAX(timestamp) FROM passwords")
  467. dates = cursor.fetchone()
  468. conn.close()
  469. stats_text = f"""
  470. 📊 Статистика паролей
  471. Всего паролей: {total}
  472. По надежности:
  473. • Очень надежные: {very_strong}
  474. • Надежные: {strong}
  475. • Средние: {medium}
  476. • Слабые: {weak}
  477. Временной диапазон:
  478. • Первый пароль: {dates[0] if dates[0] else 'Нет данных'}
  479. • Последний пароль: {dates[1] if dates[1] else 'Нет данных'}
  480. """
  481. messagebox.showinfo("Статистика", stats_text)
  482. except Exception as e:
  483. messagebox.showerror("Ошибка", f"Не удалось получить статистику: {str(e)}")
  484. def set_history_limit(self):
  485. dialog = tk.Toplevel(self.root)
  486. dialog.title("Ограничение истории")
  487. dialog.geometry("300x150")
  488. tk.Label(dialog, text="Максимальное количество записей:").pack(pady=10)
  489. limit_var = tk.IntVar(value=self.history_limit)
  490. spinbox = tk.Spinbox(dialog, from_=5, to=100, textvariable=limit_var, width=10)
  491. spinbox.pack(pady=10)
  492. def apply_limit():
  493. self.history_limit = limit_var.get()
  494. self.load_history()
  495. dialog.destroy()
  496. messagebox.showinfo("Успех", f"Лимит истории установлен: {self.history_limit}")
  497. tk.Button(dialog, text="Применить", command=apply_limit).pack(pady=10)
  498. def save_config(self):
  499. config = {
  500. 'length': self.length_var.get(),
  501. 'letters': self.letters_var.get(),
  502. 'digits': self.digits_var.get(),
  503. 'punctuation': self.punctuation_var.get(),
  504. 'exclude_similar': self.exclude_similar.get(),
  505. 'exclude_ambiguous': self.exclude_ambiguous.get(),
  506. 'history_limit': self.history_limit
  507. }
  508. try:
  509. with open(self.config_file, 'w') as f:
  510. json.dump(config, f)
  511. self.status_bar.config(text="Настройки сохранены")
  512. messagebox.showinfo("Успех", "Настройки успешно сохранены!")
  513. except Exception as e:
  514. messagebox.showerror("Ошибка", f"Не удалось сохранить настройки: {str(e)}")
  515. def load_config(self):
  516. if not os.path.exists(self.config_file):
  517. return
  518. try:
  519. with open(self.config_file, 'r') as f:
  520. config = json.load(f)
  521. self.length_var.set(config.get('length', 16))
  522. self.letters_var.set(config.get('letters', True))
  523. self.digits_var.set(config.get('digits', True))
  524. self.punctuation_var.set(config.get('punctuation', True))
  525. self.exclude_similar.set(config.get('exclude_similar', True))
  526. self.exclude_ambiguous.set(config.get('exclude_ambiguous', False))
  527. self.history_limit = config.get('history_limit', 15)
  528. self.status_bar.config(text="Настройки загружены")
  529. except Exception as e:
  530. messagebox.showerror("Ошибка", f"Не удалось загрузить настройки: {str(e)}")
  531. def reset_settings(self):
  532. if messagebox.askyesno("Подтверждение",
  533. "Вы уверены, что хотите сбросить все настройки к значениям по умолчанию?"):
  534. self.length_var.set(16)
  535. self.letters_var.set(True)
  536. self.digits_var.set(True)
  537. self.punctuation_var.set(True)
  538. self.exclude_similar.set(True)
  539. self.exclude_ambiguous.set(False)
  540. self.history_limit = 15
  541. messagebox.showinfo("Успех", "Настройки сброшены к значениям по умолчанию!")
  542. def show_about(self):
  543. about_text = """
  544. 🔐 Генератор надежных паролей PRO
  545. Версия: 2.0
  546. Разработчик: Password Security Team
  547. Функции:
  548. • Генерация паролей с настройками
  549. • Проверка надежности паролей
  550. • Сохранение истории паролей
  551. • Экспорт данных
  552. • Статистика использования
  553. Используйте этот инструмент для создания
  554. безопасных паролей для всех ваших аккаунтов!
  555. """
  556. messagebox.showinfo("О программе", about_text)
  557. def show_tips(self):
  558. tips = """
  559. 💡 Советы по созданию надежных паролей:
  560. 1. Используйте длину не менее 12 символов
  561. 2. Сочетайте разные типы символов
  562. 3. Избегайте личной информации
  563. 4. Не используйте один пароль на всех сайтах
  564. 5. Регулярно меняйте важные пароли
  565. 6. Используйте менеджер паролей
  566. 7. Включайте двухфакторную аутентификацию
  567. Помните: Лучший пароль - тот, который вы не можете запомнить,
  568. но ваш менеджер паролей может!
  569. """
  570. messagebox.showinfo("Рекомендации по безопасности", tips)
  571. def run(self):
  572. self.load_history()
  573. self.root.mainloop()
  574. if __name__ == "__main__":
  575. app = PasswordGenerator()
  576. app.run()