import json import os import base64 from typing import Dict, Any from cryptography.fernet import Fernet from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC class ConfigManager: """Класс для работы с зашифрованным конфигом""" def __init__(self, key_string: str = "FISHKArrCONFIG", config_file: str = "Config.rr"): self.key_string = key_string self.config_file = config_file self.config_dir = self._get_config_directory() self.config_path = os.path.join(self.config_dir, config_file) self.current_config = self.load_config() self._observers = [] def _get_config_directory(self) -> str: """Возвращает путь к директории для сохранения конфига""" # Путь: C:\Users\[USERNAME]\AppData\LocalLow\Robotic Retailers\Robonect4 appdata = os.environ.get('LOCALAPPDATA', '') if appdata: # Заменяем 'Local' на 'LocalLow' в пути # Обычно LOCALAPPDATA указывает на ...\AppData\Local # Нам нужно ...\AppData\LocalLow base_path = appdata.replace('Local', 'LocalLow') config_dir = os.path.join(base_path, 'Robotic Retailers', 'Robonect4') else: # Fallback для Linux/Mac base_path = os.path.expanduser('~') config_dir = os.path.join(base_path, '.config', 'Robotic Retailers', 'Robonect4') # Создаем директорию, если она не существует try: os.makedirs(config_dir, exist_ok=True) print(f"Директория для конфига: {config_dir}") except Exception as e: print(f"Ошибка создания директории: {e}") # В случае ошибки используем текущую директорию config_dir = os.getcwd() return config_dir def add_observer(self, callback): """Добавляет наблюдателя для обновлений конфига""" self._observers.append(callback) def notify_observers(self): """Уведомляет наблюдателей об изменении конфига""" for callback in self._observers: callback() def _derive_key(self) -> bytes: """Создает ключ Fernet из строки""" # Соль фиксированная для обратной совместимости salt = b'fishka_salt_1234' kdf = PBKDF2HMAC( algorithm=hashes.SHA256(), length=32, salt=salt, iterations=100000, ) key = base64.urlsafe_b64encode(kdf.derive(self.key_string.encode())) return key def encrypt_data(self, data: Dict[str, Any]) -> bytes: """Шифрует словарь в строку JSON и затем шифрует""" json_str = json.dumps(data, ensure_ascii=False, indent=2) fernet = Fernet(self._derive_key()) encrypted = fernet.encrypt(json_str.encode('utf-8')) return encrypted def decrypt_data(self, encrypted_data: bytes) -> Dict[str, Any]: """Расшифровывает данные""" try: fernet = Fernet(self._derive_key()) decrypted = fernet.decrypt(encrypted_data) return json.loads(decrypted.decode('utf-8')) except Exception as e: print(f"Ошибка расшифровки: {e}") return {} def save_config(self, data: Dict[str, Any]) -> bool: """Сохраняет конфиг в файл в AppData/LocalLow""" try: encrypted = self.encrypt_data(data) # Убеждаемся, что директория существует os.makedirs(self.config_dir, exist_ok=True) # Сохраняем файл with open(self.config_path, 'wb') as f: f.write(encrypted) print(f"Конфиг сохранен: {self.config_path}") self.current_config = data self.notify_observers() return True except Exception as e: print(f"Ошибка сохранения: {e}") return False def load_config(self) -> Dict[str, Any]: """Загружает конфиг из файла в AppData/LocalLow""" if not os.path.exists(self.config_path): print(f"Файл конфига не найден: {self.config_path}") return {} try: with open(self.config_path, 'rb') as f: encrypted = f.read() config = self.decrypt_data(encrypted) print(f"Конфиг загружен: {self.config_path}") return config except Exception as e: print(f"Ошибка загрузки: {e}") return {} def get_config_path(self) -> str: """Возвращает полный путь к файлу конфига""" return self.config_path