406 lines
17 KiB
Python
406 lines
17 KiB
Python
# modules/bots_module.py
|
||
import tkinter as tk
|
||
from tkinter import ttk, messagebox
|
||
import hashlib
|
||
import os
|
||
import uuid
|
||
import re
|
||
from pathlib import Path
|
||
|
||
|
||
class BotsCountTab:
|
||
"""
|
||
Класс для создания вкладки настройки количества ботов.
|
||
"""
|
||
|
||
def __init__(self, parent_frame):
|
||
"""
|
||
Инициализация компонента вкладки.
|
||
|
||
Args:
|
||
parent_frame: Родительский фрейм, куда будет помещен интерфейс
|
||
"""
|
||
self.parent = parent_frame
|
||
|
||
# Путь для сохранения файла
|
||
self.save_dir = Path.home() / "Documents" / "C4"
|
||
self.file_path = self.save_dir / "BotsAmount.rr"
|
||
|
||
# Переменные
|
||
self.bots_var = tk.IntVar(value=1)
|
||
self.mac_address = self.get_mac_address()
|
||
self.loading_from_file = False # Флаг загрузки из файла
|
||
|
||
# Создаем основной контейнер для вкладки
|
||
self.container = ttk.Frame(parent_frame, padding=20)
|
||
self.container.pack(fill=tk.BOTH, expand=True)
|
||
|
||
self._build_ui()
|
||
|
||
# Загружаем настройки из файла при старте (только один раз)
|
||
self.load_from_file()
|
||
self.update_status()
|
||
|
||
def get_mac_address(self):
|
||
"""Получаем MAC-адрес компьютера"""
|
||
try:
|
||
# Получаем MAC-адрес
|
||
mac = ':'.join(re.findall('..', '%012x' % uuid.getnode()))
|
||
return mac.upper()
|
||
except:
|
||
return "00:00:00:00:00:00"
|
||
|
||
def _build_ui(self):
|
||
"""Построение интерфейса вкладки"""
|
||
|
||
# Заголовок вкладки
|
||
title_frame = ttk.Frame(self.container)
|
||
title_frame.pack(fill=tk.X, pady=(0, 20))
|
||
|
||
title_label = ttk.Label(
|
||
title_frame,
|
||
text='Настройка количества ботов',
|
||
font=("Segoe UI", 12, "bold")
|
||
)
|
||
title_label.pack()
|
||
|
||
# Разделитель
|
||
ttk.Separator(self.container, orient="horizontal").pack(
|
||
fill=tk.X, pady=(0, 20)
|
||
)
|
||
|
||
# Основной контент
|
||
content_frame = ttk.Frame(self.container)
|
||
content_frame.pack(fill=tk.BOTH, expand=True)
|
||
|
||
# Левая панель - выбор количества
|
||
left_panel = ttk.LabelFrame(content_frame, text="Выбор количества", padding=15)
|
||
left_panel.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=(0, 10))
|
||
|
||
ttk.Label(left_panel, text="Выберите количество ботов:",
|
||
font=("Arial", 10)).pack(pady=(0, 10))
|
||
|
||
# Фрейм для радиокнопок
|
||
self.radio_frame = ttk.Frame(left_panel)
|
||
self.radio_frame.pack(pady=5)
|
||
|
||
# Создаем радиокнопки для выбора количества ботов
|
||
self.radio_buttons = []
|
||
for i in range(1, 6):
|
||
rb = tk.Radiobutton(
|
||
self.radio_frame,
|
||
text=f"{i} бот{'ов' if i > 1 else ''}",
|
||
variable=self.bots_var,
|
||
value=i,
|
||
font=("Arial", 10),
|
||
command=self._on_bots_change
|
||
)
|
||
rb.pack(anchor=tk.W, pady=3)
|
||
self.radio_buttons.append(rb)
|
||
|
||
# Кнопки управления
|
||
button_frame = ttk.Frame(left_panel)
|
||
button_frame.pack(pady=20)
|
||
|
||
ttk.Button(
|
||
button_frame,
|
||
text="Сохранить настройки",
|
||
command=self._save_config,
|
||
width=20
|
||
).pack(pady=5)
|
||
|
||
# Правая панель - информация и статус
|
||
right_panel = ttk.LabelFrame(content_frame, text="Информация", padding=15)
|
||
right_panel.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True, padx=(10, 0))
|
||
|
||
# MAC-адрес
|
||
mac_frame = ttk.Frame(right_panel)
|
||
mac_frame.pack(fill=tk.X, pady=(0, 15))
|
||
|
||
ttk.Label(mac_frame, text="MAC-адрес:",
|
||
font=("Arial", 9, "bold")).pack(anchor=tk.W)
|
||
self.mac_label = ttk.Label(
|
||
mac_frame,
|
||
text=self.mac_address,
|
||
font=("Consolas", 9),
|
||
foreground="blue"
|
||
)
|
||
self.mac_label.pack(anchor=tk.W, pady=(2, 0))
|
||
|
||
# Путь к файлу
|
||
path_frame = ttk.Frame(right_panel)
|
||
path_frame.pack(fill=tk.X, pady=(0, 15))
|
||
|
||
ttk.Label(path_frame, text="Файл для сохранения:",
|
||
font=("Arial", 9, "bold")).pack(anchor=tk.W)
|
||
self.path_label = ttk.Label(
|
||
path_frame,
|
||
text=str(self.file_path),
|
||
font=("Consolas", 8),
|
||
wraplength=250
|
||
)
|
||
self.path_label.pack(anchor=tk.W, pady=(2, 0))
|
||
|
||
# Статус
|
||
status_frame = ttk.Frame(right_panel)
|
||
status_frame.pack(fill=tk.X, pady=(0, 15))
|
||
|
||
ttk.Label(status_frame, text="Текущий статус:",
|
||
font=("Arial", 9, "bold")).pack(anchor=tk.W)
|
||
self.status_label = ttk.Label(
|
||
status_frame,
|
||
text="Не сохранено",
|
||
font=("Arial", 10),
|
||
foreground="red"
|
||
)
|
||
self.status_label.pack(anchor=tk.W, pady=(2, 0))
|
||
|
||
# Количество ботов из файла
|
||
bots_frame = ttk.Frame(right_panel)
|
||
bots_frame.pack(fill=tk.X)
|
||
|
||
ttk.Label(bots_frame, text="Количество ботов в файле:",
|
||
font=("Arial", 9, "bold")).pack(anchor=tk.W)
|
||
self.bots_file_label = ttk.Label(
|
||
bots_frame,
|
||
text="не определено",
|
||
font=("Arial", 10),
|
||
foreground="orange"
|
||
)
|
||
self.bots_file_label.pack(anchor=tk.W, pady=(2, 0))
|
||
|
||
def _on_bots_change(self):
|
||
"""Обработчик изменения выбранного количества ботов"""
|
||
# Не обновляем статус при изменении пользователем
|
||
# Просто сбрасываем флаг загрузки из файла
|
||
if not self.loading_from_file:
|
||
# Обновляем только статус файла
|
||
if self.file_path.exists():
|
||
self.status_label.config(text="Файл будет перезаписан", foreground="orange")
|
||
else:
|
||
self.status_label.config(text="Файл будет создан", foreground="blue")
|
||
|
||
def load_from_file(self):
|
||
"""Загрузить настройки из файла при старте"""
|
||
self.loading_from_file = True # Устанавливаем флаг загрузки
|
||
|
||
if not self.file_path.exists():
|
||
self.bots_file_label.config(
|
||
text="файл не найден",
|
||
foreground="red"
|
||
)
|
||
self.loading_from_file = False
|
||
return None
|
||
|
||
try:
|
||
with open(self.file_path, 'r', encoding='utf-8') as f:
|
||
file_hash = f.read().strip()
|
||
|
||
if len(file_hash) != 64: # SHA-256 hash length
|
||
self.bots_file_label.config(
|
||
text="неверный формат хэша",
|
||
foreground="red"
|
||
)
|
||
self.loading_from_file = False
|
||
return None
|
||
|
||
# Пробуем подобрать количество ботов от 1 до 5
|
||
found_bots = None
|
||
for bots in range(1, 6):
|
||
data = str(bots) + "RR_SuPeR" + self.mac_address
|
||
calculated_hash = hashlib.sha256(data.encode()).hexdigest()
|
||
|
||
if calculated_hash == file_hash:
|
||
found_bots = bots
|
||
break
|
||
|
||
if found_bots:
|
||
# Устанавливаем значение из файла
|
||
self.bots_var.set(found_bots)
|
||
self.bots_file_label.config(
|
||
text=f"{found_bots} бот{'ов' if found_bots > 1 else ''}",
|
||
foreground="green"
|
||
)
|
||
self.status_label.config(
|
||
text="✓ Загружено из файла",
|
||
foreground="green"
|
||
)
|
||
self.loading_from_file = False
|
||
return found_bots
|
||
else:
|
||
# Если хэш не совпал ни с одним вариантом
|
||
self.bots_file_label.config(
|
||
text="не совпадает с MAC-адресом",
|
||
foreground="red"
|
||
)
|
||
self.status_label.config(
|
||
text="Файл есть, но не совпадает",
|
||
foreground="orange"
|
||
)
|
||
self.loading_from_file = False
|
||
return None
|
||
|
||
except Exception as e:
|
||
self.bots_file_label.config(
|
||
text=f"ошибка чтения",
|
||
foreground="red"
|
||
)
|
||
self.status_label.config(
|
||
text=f"Ошибка чтения файла",
|
||
foreground="red"
|
||
)
|
||
self.loading_from_file = False
|
||
return None
|
||
|
||
def update_status(self):
|
||
"""Обновить статус (только для отображения, без изменения выбора)"""
|
||
# Проверяем существование файла
|
||
if self.file_path.exists():
|
||
# Читаем хэш из файла для сравнения
|
||
try:
|
||
with open(self.file_path, 'r', encoding='utf-8') as f:
|
||
file_hash = f.read().strip()
|
||
|
||
# Вычисляем хэш для текущего выбора
|
||
current_bots = self.bots_var.get()
|
||
data = str(current_bots) + "RR_SuPeR" + self.mac_address
|
||
current_hash = hashlib.sha256(data.encode()).hexdigest()
|
||
|
||
# Сравниваем
|
||
if current_hash == file_hash:
|
||
self.status_label.config(
|
||
text="✓ Совпадает с файлом",
|
||
foreground="green"
|
||
)
|
||
else:
|
||
self.status_label.config(
|
||
text="Отличается от файла",
|
||
foreground="orange"
|
||
)
|
||
|
||
except Exception:
|
||
self.status_label.config(
|
||
text="✓ Файл существует",
|
||
foreground="green"
|
||
)
|
||
else:
|
||
self.status_label.config(
|
||
text="Файл не найден",
|
||
foreground="red"
|
||
)
|
||
|
||
def check_existing_file(self):
|
||
"""Проверить существующий файл и показать информацию (для диалога)"""
|
||
if self.file_path.exists():
|
||
try:
|
||
with open(self.file_path, 'r', encoding='utf-8') as f:
|
||
hash_content = f.read().strip()
|
||
|
||
# Рассчитываем количество ботов из файла
|
||
bots_count = None
|
||
for bots in range(1, 6):
|
||
data = str(bots) + "RR_SuPeR" + self.mac_address
|
||
calculated_hash = hashlib.sha256(data.encode()).hexdigest()
|
||
if calculated_hash == hash_content:
|
||
bots_count = bots
|
||
break
|
||
|
||
# Показываем диалог с информацией
|
||
if bots_count:
|
||
info_text = (
|
||
f"В файле сохранено: {bots_count} бот{'ов' if bots_count > 1 else ''}\n"
|
||
f"Текущий выбор: {self.bots_var.get()} бот{'ов' if self.bots_var.get() > 1 else ''}\n\n"
|
||
)
|
||
|
||
if bots_count == self.bots_var.get():
|
||
info_text += "Текущий выбор совпадает с сохраненным в файле."
|
||
result = messagebox.showinfo(
|
||
"Информация о файле",
|
||
info_text
|
||
)
|
||
else:
|
||
info_text += "Текущий выбор отличается от сохраненного в файле.\nХотите перезаписать файл?"
|
||
result = messagebox.askyesno(
|
||
"Файл существует",
|
||
info_text
|
||
)
|
||
return result
|
||
else:
|
||
messagebox.showinfo(
|
||
"Информация о файле",
|
||
f"Файл существует, но количество ботов не определено.\n"
|
||
f"(хэш не совпадает с текущим MAC-адресом)"
|
||
)
|
||
|
||
except Exception as e:
|
||
messagebox.showerror("Ошибка", f"Не удалось прочитать файл:\n{str(e)}")
|
||
|
||
return True # По умолчанию разрешаем сохранение
|
||
|
||
def _save_config(self):
|
||
"""Сохраняет количество ботов в файл с хешированием"""
|
||
# Проверяем существующий файл
|
||
if self.file_path.exists():
|
||
result = self.check_existing_file()
|
||
if not result:
|
||
return # Пользователь отказался от перезаписи
|
||
|
||
try:
|
||
# Получаем выбранное значение
|
||
bots = self.bots_var.get()
|
||
|
||
if not 1 <= bots <= 5:
|
||
messagebox.showerror("Ошибка", "Выберите количество ботов от 1 до 5")
|
||
return
|
||
|
||
# Создаем хэш количества ботов с солью и MAC-адресом
|
||
data = str(bots) + "RR_SuPeR" + self.mac_address
|
||
hash_result = hashlib.sha256(data.encode()).hexdigest()
|
||
|
||
# Создаем директорию, если она не существует
|
||
self.save_dir.mkdir(parents=True, exist_ok=True)
|
||
|
||
# Сохраняем в файл
|
||
with open(self.file_path, "w", encoding="utf-8") as f:
|
||
f.write(hash_result)
|
||
|
||
# Обновляем статус
|
||
self.update_status()
|
||
|
||
# Обновляем метку файла
|
||
self.bots_file_label.config(
|
||
text=f"{bots} бот{'ов' if bots > 1 else ''}",
|
||
foreground="green"
|
||
)
|
||
|
||
# Показываем результат
|
||
messagebox.showinfo(
|
||
"Сохранено",
|
||
f"Количество ботов: {bots}\n\n"
|
||
f"Файл сохранен: {self.file_path}"
|
||
)
|
||
|
||
except Exception as e:
|
||
messagebox.showerror("Ошибка", f"Не удалось сохранить файл:\n{str(e)}")
|
||
|
||
def get_bots_count(self):
|
||
"""Получить текущее количество ботов (для использования другими модулями)"""
|
||
return self.bots_var.get()
|
||
|
||
def get_hash_info(self):
|
||
"""Получить информацию о хэше (для использования другими модулями)"""
|
||
bots = self.bots_var.get()
|
||
data = str(bots) + "RR_SuPeR" + self.mac_address
|
||
hash_result = hashlib.sha256(data.encode()).hexdigest()
|
||
|
||
return {
|
||
'bots': bots,
|
||
'mac': self.mac_address,
|
||
'hash': hash_result,
|
||
'file_path': str(self.file_path),
|
||
'data_string': data
|
||
}
|
||
|
||
def save_bots_amount(self):
|
||
"""Сохранить количество ботов (интерфейсный метод для main)"""
|
||
self._save_config() |