diff --git a/Gui/AddCustomer.qml b/Gui/AddCustomer.qml index 2665c95..faff464 100644 --- a/Gui/AddCustomer.qml +++ b/Gui/AddCustomer.qml @@ -2,6 +2,7 @@ import QtQuick import QtQuick.Layouts import QtQuick.Controls import QtQuick.Controls.Fusion +import QtQuick.Dialogs import "../js/qmldict.js" as JsLib ColumnLayout @@ -258,6 +259,8 @@ ColumnLayout id: spacer3 Layout.fillHeight: true } + + function isEmptyField() { if (!firmenName.text.trim() || !street.text.trim() || !city.text.trim()) diff --git a/Gui/AdminUserConfig.qml b/Gui/AdminUserConfig.qml index 04a2353..6863a15 100644 --- a/Gui/AdminUserConfig.qml +++ b/Gui/AdminUserConfig.qml @@ -70,9 +70,13 @@ GridLayout { Layout.fillHeight: true } + + + Component.onCompleted: { config.usernameNotAvailable.connect(usernameNotAvailable) + } function usernameNotAvailable() { @@ -81,6 +85,7 @@ GridLayout benutzerNamelabel.color = "red" benutzerNamelabel.font.bold = true } + } diff --git a/Gui/firststart.qml b/Gui/firststart.qml index ebe38c4..579c52e 100644 --- a/Gui/firststart.qml +++ b/Gui/firststart.qml @@ -2,16 +2,26 @@ import QtQuick import QtQuick.Layouts import QtQuick.Controls import QtQuick.Dialogs +import QtCore import "../js/qmldict.js" as Qmldict Item { + property string recpass: "" + property bool adminAvailable: true Component.onCompleted: { config.dbConnectionError.connect(onDbConnectionError) config.adminUserError.connect(onAdminUserError) + config.backupEncryptionKey.connect(onBackupEncryptionKey) + + } + + function onBackupEncryptionKey() + { + recoveryDialog.open() } function onDbConnectionError(msg, success) @@ -27,8 +37,43 @@ Item encryptPwDialog.open() } else + { + adminAvailable = false firstStart.push("AdminUserConfig.qml") + } + } + MessageDialog + { + id: recoveryDialog + + text: qsTr("Diesen Wiederherstellungscode musst du sicher aufbewahren!\nMöchtest du das jetzt machen?") + title: qsTr("Wiederherstellen") + buttons: MessageDialog.Yes | MessageDialog.No + onAccepted: saveRecoveryDialog.open() + + } + FileDialog + { + id: saveRecoveryDialog + title: qsTr("Wiederherstellungsdatei") + fileMode: adminAvailable? FileDialog.OpenFile: FileDialog.SaveFile + nameFilters: ["PYQCRM Recovery files (*.pyqrec)"] + currentFolder: StandardPaths.standardLocations(StandardPaths.DocumentsLocation)[0] + onAccepted: + { + if (!adminAvailable) config.saveRecoveryKey(saveRecoveryDialog.currentFile, recpass) + else + { + config.getRecoveryKey(saveRecoveryDialog.currentFile, recpass) + + } + appLoader.source = "Dashboard.qml" + topBar.visible = true + } + + } + MessageDialog { @@ -43,15 +88,14 @@ Item { id: encryptPwDialog modal: true - title: qsTr("Encryption Key") + title: qsTr("Wiederherstellung") anchors.centerIn: parent standardButtons: Dialog.Ok | Dialog.Cancel onAccepted: { - // TODO: signal for EncryptionKey testing - config.setEncyrptKey(encryptPassword.text) - appLoader.source = "Dashboard.qml" - topBar.visible = true + recpass = encryptPassword.text + saveRecoveryDialog.open() + } ColumnLayout { @@ -59,7 +103,7 @@ Item { Label { - text: qsTr("Encryption Key eingeben:") + text: qsTr("Wiederherstellungspasswort eingeben: ") } TextField @@ -67,12 +111,14 @@ Item id: encryptPassword echoMode: TextInput.Password implicitWidth: 300 - placeholderText: qsTr("Hier Encryption Key eingeben") + placeholderText: qsTr("Hier Wiederherstellungspasswort eingeben") } } } } + + anchors.fill: parent StackView { @@ -129,8 +175,8 @@ Item admin = config.addAdminUser(pyqcrm_conf) if (admin) { - appLoader.source = "Dashboard.qml" - topBar.visible = true + //appLoader.source = "Dashboard.qml" + //topBar.visible = true } else { diff --git a/doc/.$Programmstart Diagramm.drawio.dtmp b/doc/.$Programmstart Diagramm.drawio.dtmp deleted file mode 100644 index 2e2067a..0000000 --- a/doc/.$Programmstart Diagramm.drawio.dtmp +++ /dev/null @@ -1,288 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/doc/Programmstart Diagramm.drawio b/doc/Programmstart Diagramm.drawio index 1aea176..a240a8c 100644 --- a/doc/Programmstart Diagramm.drawio +++ b/doc/Programmstart Diagramm.drawio @@ -81,7 +81,7 @@ - + @@ -91,12 +91,12 @@ - + - + - + @@ -111,7 +111,7 @@ - + @@ -121,7 +121,7 @@ - + @@ -174,7 +174,7 @@ - + @@ -197,10 +197,7 @@ - - - - + @@ -221,18 +218,7 @@ - - - - - - - - - - - - + @@ -243,38 +229,32 @@ - - - - - - - + - + - + - + - + @@ -282,6 +262,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/Programmstart Diagramm.pdf b/doc/Programmstart Diagramm.pdf index 259a89a..055acff 100644 Binary files a/doc/Programmstart Diagramm.pdf and b/doc/Programmstart Diagramm.pdf differ diff --git a/lib/ConfigLoader.py b/lib/ConfigLoader.py index 1f0e165..4922204 100644 --- a/lib/ConfigLoader.py +++ b/lib/ConfigLoader.py @@ -24,7 +24,8 @@ class ConfigLoader(QObject): dbConnectionError = Signal(str, bool) adminUserError = Signal(str, bool) usernameNotAvailable = Signal() - configurationReady = Signal() + configurationReady = Signal(bool) + backupEncryptionKey = Signal() def __init__(self): super().__init__() @@ -36,6 +37,51 @@ class ConfigLoader(QObject): else: config_dir.mkdir(0o750, True, True) + @Slot(str, str) + def saveRecoveryKey(self, recovery_file, recovery_password): + rp = self.__setRecoveryPassword(recovery_password) + rf = rp[1] + self.__encrypt_key + rp[0] + rf = Vermasseln().oscarVermasseln(rf) + rec_file = urlparse(recovery_file) + rec_file = rec_file.path + if os.name == "nt": + rec_file = rec_file [1:] + try: + with open(rec_file, "w") as f: + f.write(rf) + self.configurationReady.emit(True) + 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: + with open(rec_file, "r") as f: + rf = f.read() + rf = Vermasseln().entschluesseln(rf) + ek = rf[128:] + ek = ek[:-32] + password = rf[:128] + salt = rf[-32:] + ok = self.__checkRecoveryPassword(recovery_password, password, salt) + if ok: + self.configurationReady.emit(True) + else: + self.configurationReady.emit(False) + except Exception as e: + print(str(e)) + + def __checkRecoveryPassword(self, recovery_password, password, salt): + rp = self.__setRecoveryPassword(recovery_password, salt) + return rp[1] == password + + + @Slot(str, str) def importConfig(self, confile, password): @@ -52,6 +98,8 @@ class ConfigLoader(QObject): if not admin: self.usernameNotAvailable.emit() + else: + self.backupEncryptionKey.emit() return admin @Slot(dict, result= bool) @@ -66,7 +114,7 @@ class ConfigLoader(QObject): self.__saveConfig() conf = self.__checkAdminUser() if conf: - self.configurationReady.emit() + self.configurationReady.emit(True) @@ -75,6 +123,7 @@ class ConfigLoader(QObject): with open (self.config_dir + '/pyqcrm.toml', 'r') as f: config = f.read() self.__config = toml.loads(Vermasseln().entschluesseln(config)) + self.configurationReady.emit(True) except FileNotFoundError: print("Konnte die Konfiguration nicht laden.") except TypeError: @@ -87,8 +136,8 @@ class ConfigLoader(QObject): return self.__config def __initializeConfig(self): - encrypt_key = b64encode(get_random_bytes(32)).decode("utf-8") - conf = f"[pyqcrm]\nVERSION = \"{self.__version}\"\nENCRYPTION_KEY = \"{encrypt_key}\"\n\n" + self.__encrypt_key = b64encode(get_random_bytes(32)).decode("utf-8") + conf = f"[pyqcrm]\nVERSION = \"{self.__version}\"\nENCRYPTION_KEY = \"{self.__encrypt_key}\"\n\n" return conf @@ -114,12 +163,13 @@ class ConfigLoader(QObject): self.adminUserError.emit("Admin vorhanden", True) return True - @Slot(str) - def setEncyrptKey(self, key): - self.__config['pyqcrm']['ENCRYPTION_KEY'] = key - self.__saveConfig() + + def __setRecoveryPassword(self, key, salt = None): + key = Vermasseln.userPasswordHash(key, salt) + return key.split("$") def __saveConfig(self): + try: with open (self.config_dir + '/pyqcrm.toml', 'w') as f: config = Vermasseln().oscarVermasseln(toml.dumps(self.__config)) diff --git a/main.py b/main.py index b1b27a2..6826d29 100644 --- a/main.py +++ b/main.py @@ -30,16 +30,19 @@ am = None bm = None user = None -def initializeProgram(): - global am, bad_config, bm, user - dbconf = config.getConfig()['database'] - DbManager(dbconf) - bad_config = False - bm = BusinessModel() - user = UserManager() - am = AddressModel() - - publishContext() +def initializeProgram(conf_ok): + if conf_ok: + global am, bad_config, bm, user + dbconf = config.getConfig()['database'] + DbManager(dbconf) + bad_config = False + bm = BusinessModel() + user = UserManager() + am = AddressModel() + publishContext() + else: + # TODO: show message and exit program + print("Kein Zugriff auf die Datenbank") def publishContext(): global engine