From 27f4dfbf8e20fe0d9635b1a592f6fc29737a2586 Mon Sep 17 00:00:00 2001 From: Tobias Fella Date: Sun, 26 May 2024 14:43:41 +0200 Subject: [PATCH] Work --- src/controller.cpp | 9 ++++ src/controller.h | 1 + src/foreigntypes.h | 8 +++ src/neochatconnection.cpp | 12 +++++ src/neochatconnection.h | 2 + src/settings/CMakeLists.txt | 2 + src/settings/ExportKeysDialog.qml | 48 ++++++++++++++++++ src/settings/ImportKeysDialog.qml | 73 ++++++++++++++++++++++++++++ src/settings/NeoChatSecurityPage.qml | 25 ++++++++++ 9 files changed, 180 insertions(+) create mode 100644 src/settings/ExportKeysDialog.qml create mode 100644 src/settings/ImportKeysDialog.qml diff --git a/src/controller.cpp b/src/controller.cpp index 0ec0603f6..bf4bad35d 100644 --- a/src/controller.cpp +++ b/src/controller.cpp @@ -406,3 +406,12 @@ void Controller::removeConnection(const QString &userId) SettingsGroup("Accounts"_ls).remove(userId); } } + +void Controller::saveFileContent(const QString &path, const QByteArray &data) const +{ + QUrl url(path); + QFile file(url.toLocalFile()); + file.open(QFile::WriteOnly); + file.write(data); + file.close(); +} diff --git a/src/controller.h b/src/controller.h index faa4a3bcf..c34553fba 100644 --- a/src/controller.h +++ b/src/controller.h @@ -87,6 +87,7 @@ public: static void listenForNotifications(); Q_INVOKABLE QString loadFileContent(const QString &path) const; + Q_INVOKABLE void saveFileContent(const QString &path, const QByteArray &data) const; Quotient::AccountRegistry &accounts(); diff --git a/src/foreigntypes.h b/src/foreigntypes.h index 3bfb65fac..d3143261e 100644 --- a/src/foreigntypes.h +++ b/src/foreigntypes.h @@ -7,6 +7,7 @@ #include #include +#include #include #include "controller.h" @@ -50,3 +51,10 @@ struct ForeignSSSSHandler { QML_FOREIGN(Quotient::SSSSHandler) QML_NAMED_ELEMENT(SSSSHandler) }; + +struct ForeignKeyImport { + Q_GADGET + QML_FOREIGN(Quotient::KeyImport) + QML_NAMED_ELEMENT(KeyImport) + QML_SINGLETON +}; diff --git a/src/neochatconnection.cpp b/src/neochatconnection.cpp index 126855f02..f6530ebb9 100644 --- a/src/neochatconnection.cpp +++ b/src/neochatconnection.cpp @@ -17,6 +17,7 @@ #include #include +#include #include #include @@ -500,4 +501,15 @@ LinkPreviewer *NeoChatConnection::previewerForLink(const QUrl &link) return previewer; } +void NeoChatConnection::exportMegolmSessions(const QString &passphrase, const QString &path) +{ + KeyImport keyImport; + auto result = keyImport.exportKeys(passphrase, this); + if (!result.has_value()) { + qWarning() << "error TODO"; + return; + } + Controller::instance().saveFileContent(path, result.value()); +} + #include "moc_neochatconnection.cpp" diff --git a/src/neochatconnection.h b/src/neochatconnection.h index 9eff1bdad..23bb978a6 100644 --- a/src/neochatconnection.h +++ b/src/neochatconnection.h @@ -160,6 +160,8 @@ public: LinkPreviewer *previewerForLink(const QUrl &link); + Q_INVOKABLE void exportMegolmSessions(const QString &passphrase, const QString &path); + Q_SIGNALS: void labelChanged(); void directChatNotificationsChanged(); diff --git a/src/settings/CMakeLists.txt b/src/settings/CMakeLists.txt index f45c4fd19..c231c82ed 100644 --- a/src/settings/CMakeLists.txt +++ b/src/settings/CMakeLists.txt @@ -35,4 +35,6 @@ qt_add_qml_module(settings PasswordSheet.qml ThemeRadioButton.qml ThreePIdCard.qml + ImportKeysDialog.qml + ExportKeysDialog.qml ) diff --git a/src/settings/ExportKeysDialog.qml b/src/settings/ExportKeysDialog.qml new file mode 100644 index 000000000..4e9126990 --- /dev/null +++ b/src/settings/ExportKeysDialog.qml @@ -0,0 +1,48 @@ +// SPDX-FileCopyrightText: 2024 Tobias Fella +// SPDX-License-Identifier: LGPL-2.0-or-later + +import QtQuick +import QtQuick.Controls as QQC2 +import QtQuick.Layouts +import QtQuick.Dialogs + +import org.kde.kirigami as Kirigami +import org.kde.kirigamiaddons.formcard as FormCard + +import org.kde.neochat + +FormCard.FormCardPage { + id: root + + title: i18nc("@title", "Export Keys") + + required property NeoChatConnection connection + + FormCard.FormCard { + Layout.topMargin: Kirigami.Units.largeSpacing + FormCard.FormTextFieldDelegate { + id: passphraseField + label: i18nc("@label:textbox", "Passphrase:") + echoMode: TextInput.Password + } + FormCard.FormButtonDelegate { + enabled: passphraseField.text.length > 0 + text: i18nc("@action:button", "Export keys") + onClicked: { + let dialog = saveDialog.createObject(root); + dialog.accepted.connect(() => { + root.connection.exportMegolmSessions(passphraseField.text, dialog.selectedFile); + }); + dialog.open(); + } + } + } + + Component { + id: saveDialog + FileDialog { + fileMode: FileDialog.SaveFile + currentFolder: Config.lastSaveDirectory.length > 0 ? Config.lastSaveDirectory : StandardPaths.writableLocation(StandardPaths.DocumentsLocation) + } + } +} diff --git a/src/settings/ImportKeysDialog.qml b/src/settings/ImportKeysDialog.qml new file mode 100644 index 000000000..ebaa8bafd --- /dev/null +++ b/src/settings/ImportKeysDialog.qml @@ -0,0 +1,73 @@ +// SPDX-FileCopyrightText: 2024 Tobias Fella +// SPDX-License-Identifier: LGPL-2.0-or-later + +import QtQuick +import QtQuick.Controls as QQC2 +import QtQuick.Layouts + +import org.kde.kirigami as Kirigami +import org.kde.kirigamiaddons.formcard as FormCard +import org.kde.kirigamiaddons.labs.components as KirigamiComponents + +import org.kde.neochat + +FormCard.FormCardPage { + id: root + + required property NeoChatConnection connection + + title: i18nc("@title", "Import Keys") + + header: KirigamiComponents.Banner { + id: banner + showCloseButton: true + visible: false + type: Kirigami.MessageType.Error + } + + FormCard.FormCard { + Layout.topMargin: Kirigami.Units.largeSpacing + FormCard.FormButtonDelegate { + id: fileButton + text: i18nc("@action:button", "Choose backup file") + description: "" + icon.name: "cloud-upload" + onClicked: { + let dialog = Qt.createComponent("org.kde.neochat", "OpenFileDialog").createObject(root); + dialog.chosen.connect(path => { + fileButton.description = path.substring(7); + }); + dialog.open(); + } + } + FormCard.FormDelegateSeparator {} + FormCard.FormTextFieldDelegate { + id: passphraseField + label: i18nc("@label:textbox", "Passphrase:") + echoMode: TextInput.Password + } + FormCard.FormDelegateSeparator {} + FormCard.FormButtonDelegate { + text: i18nc("@action:button", "Import keys") + enabled: fileButton.description.length > 0 && passphraseField.text.length > 0 + onClicked: { + banner.visible = false; + let error = KeyImport.importKeys(Controller.loadFileContent(fileButton.description), passphraseField.text, root.connection); + if (error === KeyImport.Success) { + root.closeDialog(); + } else if (error === KeyImport.InvalidPassphrase) { + banner.text = i18nc("@info", "Invalid passphrase"); + banner.visible = true; + } else if (error === KeyImport.InvalidData) { + banner.text = i18nc("@info", "Invalid key backup data"); + banner.visible = true; + } else { + banner.text = i18nc("@info", "Unknown error"); + banner.visible = true; + } + } + } + } + + +} diff --git a/src/settings/NeoChatSecurityPage.qml b/src/settings/NeoChatSecurityPage.qml index e71975b4d..c1e8624be 100644 --- a/src/settings/NeoChatSecurityPage.qml +++ b/src/settings/NeoChatSecurityPage.qml @@ -33,6 +33,31 @@ FormCard.FormCardPage { description: i18n("Device id") } } + + FormCard.FormHeader { + title: i18nc("@title", "Encryption Keys") + } + FormCard.FormCard { + FormCard.FormButtonDelegate { + text: i18nc("@action:button", "Import Encryption Keys") + icon.name: "document-import" + onClicked: pageStack.pushDialogLayer(Qt.createComponent("org.kde.neochat.settings", "ImportKeysDialog"), { + connection: root.connection + }, { + title: i18nc("@title", "Import Keys") + }) + } + FormCard.FormButtonDelegate { + text: i18nc("@action:button", "Export Encryption Keys") + icon.name: "document-export" + onClicked: pageStack.pushDialogLayer(Qt.createComponent("org.kde.neochat.settings", "ExportKeysDialog"), { + connection: root.connection + }, { + title: i18nc("@title", "Export Keys") + }) + } + } + FormCard.FormHeader { title: i18nc("@title:group", "Ignored Users") }