# This Python file uses the following encoding: utf-8 import toml from platformdirs import user_config_dir from pathlib import Path from PySide6.QtCore import QObject, Slot, Signal from .Vermasseln import Vermasseln import shutil from urllib.parse import urlparse from .DB.DbManager import DbManager import os from Crypto.Random import get_random_bytes from base64 import b64encode from .DB.UserManager import UserManager from .PyqcrmFlags import PyqcrmFlags class ConfigLoader(QObject): __config = None __version = "0.1-alpha" __check_enc_key = True dbConnectionError = Signal(str, bool) adminUserError = Signal(str, bool) adminNotAvailable = Signal() configurationReady = Signal() backupEncryptionKey = Signal() invalidEncryptionKey = Signal() def __init__(self): super().__init__() # print(f"In {__file__} file, __init__()") self.config_dir = user_config_dir() + '/pyqcrm' config_dir = Path(self.config_dir) if config_dir.exists(): self.__configLoad() if self.__config: self.checkEncryptionKey() else: config_dir.mkdir(0o750, True, True) @Slot(dict, result = bool) def setConfig(self, app_config): # print(f"In {__file__} file, setConfig()") if not self.__config: base_conf = self.__initializeConfig() conf = self.__checkDbConnection(app_config) app_config = toml.dumps(app_config) if conf: app_config = base_conf + app_config self.__config = toml.loads(app_config) self.__saveConfig() conf = self.__checkAdminUser() if conf: self.configurationReady.emit() def __initializeConfig(self): # print(f"In {__file__} file, __initializeConfig()") self.__encrypt_key = b64encode(get_random_bytes(32)).decode("utf-8") conf = f"[pyqcrm]\nVERSION = \"{self.__version}\"\n" conf = conf + f"ENCRYPTION_KEY_VALID = \"No\"\n" conf = conf + f"ENCRYPTION_KEY = \"{self.__encrypt_key}\"\n\n" return conf def __checkDbConnection(self, db_config): # print(f"In {__file__} file, __checkDbConnection()") con = DbManager(db_config['database']).getConnection() if con: self.dbConnectionError.emit("Connection OK", True) return True else: self.dbConnectionError.emit("Connection fehlgeschlagen", False) return False def __saveConfig(self): # print(f"In {__file__} file, saveConfig()") try: with open (self.config_dir + '/pyqcrm.toml', 'w') as f: # print(self.__config) config = Vermasseln().oscarVermasseln(toml.dumps(self.__config)) f.write(config) except FileNotFoundError: print("Konnte die Konfiguration nicht speichern.") def __checkAdminUser(self): # print(f"In {__file__} file, __checkAdminUser()") result = UserManager().checkAdmin() if not result: #if not result[0][0] == 1: self.adminUserError.emit("Kein Admin vorhanden", False) return False else: self.adminUserError.emit("Admin vorhanden", True) return True @Slot(dict, result= bool) def addAdminUser(self, user_config): # print(f"In {__file__} file, addAdminUser()") admin = UserManager(user_config["user"], PyqcrmFlags.ADMIN).createUser() if not admin: #self.adminNotAvailable.emit() self.adminUserError.emit("Benutzername nich verfügbar", False) else: self.__config['pyqcrm']['ENCRYPTION_KEY_VALID'] = 'Yes' self.__saveConfig() self.backupEncryptionKey.emit() return admin """###################################################""" """ """ """ TODO: Rename method and rename self.__encrypt_key """ """ """ """###################################################""" @Slot(str, str) def saveRecoveryKey(self, recovery_file, recovery_password): # print(f"In {__file__} file, saveRecoveryKey()") local = False rp = self.__setRecoveryPassword(recovery_password) rf = rp[1] + self.__encrypt_key + rp[0] rf = Vermasseln().oscarVermasseln(rf, local) rec_file = urlparse(recovery_file) if os.name == "nt": rec_file = rec_file [1:] else: rec_file = rec_file.path + ".pyqrec" try: with open(rec_file, "w") as f: f.write(rf) self.configurationReady.emit() except Exception as e: print(str(e)) @Slot(str, str) def getRecoveryKey(self, recovery_file, recovery_password): rec_file = urlparse(recovery_file) rec_file = rec_file.path if os.name == "nt": rec_file = rec_file [1:] try: ek = self.__parseImport(rec_file, recovery_password) if ek: self.__setEncryptionKey(ek) self.configurationReady.emit() else: self.__invalidateEncryptionKey() self.invalidEncryptionKey.emit() except Exception as e: print(str(e)) def __parseImport(self, rec_file, recovery_password): local = False with open(rec_file, "r") as f: rf = f.read() rf = Vermasseln().entschluesseln(rf, local) ek = rf[128:] ek = ek[:-32] password = rf[:128] salt = rf[-32:] ok = self.__checkRecoveryPassword(recovery_password, password, salt) if ok: return ek else: return None def __invalidateEncryptionKey(self): # print(f"In {__file__} file, __invalidateEncryptionKey()") self.__config['pyqcrm']['ENCRYPTION_KEY_VALID'] = 'No' self.__saveConfig() @Slot() def checkEncryptionKey(self): # print(f"In {__file__} file, __checkEncryptionKey()") if self.__config['pyqcrm']['ENCRYPTION_KEY_VALID'] == 'No': self.invalidEncryptionKey.emit() def __checkRecoveryPassword(self, recovery_password, password, salt): # print(f"In {__file__} file, __checkRecoveryPassword()") rp = self.__setRecoveryPassword(recovery_password, salt) return rp[1] == password @Slot(str, str) # todo: non local encryption def importConfig(self, confile, password): confile = urlparse(confile) confile = confile.path if os.name == "nt": confile = confile[1:] try: ek = self.__parseImport(confile, password) if ek: self.__config = toml.loads(ek) self.__saveConfig() self.configurationReady.emit() else: self.invalidEncryptionKey.emit() except Exception as e: print(str(e)) def __configLoad(self): # print(f"In {__file__} file, __configLoad()") try: with open (self.config_dir + '/pyqcrm.toml', 'r') as f: config = f.read() self.__config = toml.loads(Vermasseln().entschluesseln(config)) self.configurationReady.emit() except FileNotFoundError: print("Konnte die Konfiguration nicht laden.") except TypeError: print(f"Invalid Configuration: {__file__}") except Exception as e: print(str(e)) def getConfig(self): # print(f"In {__file__} file, getConfig()") # print(self.__config) return self.__config def __setRecoveryPassword(self, key, salt = None): # print(f"In {__file__} file, __setRecoveryPassword()") key = Vermasseln.userPasswordHash(key, salt) return key.split("$") @Slot(str) def __setEncryptionKey(self, enc_key): # print(f"In {__file__} file, __setEncryptionKey()") self.__config['pyqcrm']['ENCRYPTION_KEY_VALID'] = 'Yes' self.__config['pyqcrm']['ENCRYPTION_KEY'] = enc_key self.__saveConfig() @Slot(str, str) def backupConfig(self, filename, password): self.__encrypt_key = toml.dumps(self.getConfig()) self.saveRecoveryKey(filename, password)