Add UI for entering key backup passphrase
This commit is contained in:
@@ -309,6 +309,7 @@ qt_add_qml_module(neochat URI org.kde.neochat NO_PLUGIN
|
|||||||
qml/IgnoredUsersDialog.qml
|
qml/IgnoredUsersDialog.qml
|
||||||
qml/AccountData.qml
|
qml/AccountData.qml
|
||||||
qml/StateKeys.qml
|
qml/StateKeys.qml
|
||||||
|
qml/UnlockSSSSDialog.qml
|
||||||
RESOURCES
|
RESOURCES
|
||||||
qml/confetti.png
|
qml/confetti.png
|
||||||
qml/glowdot.png
|
qml/glowdot.png
|
||||||
|
|||||||
@@ -377,6 +377,14 @@ AccountRegistry &Controller::accounts()
|
|||||||
return m_accountRegistry;
|
return m_accountRegistry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString Controller::loadFileContent(const QString &path) const
|
||||||
|
{
|
||||||
|
QUrl url(path);
|
||||||
|
QFile file(url.isLocalFile() ? url.toLocalFile() : url.toString());
|
||||||
|
file.open(QFile::ReadOnly);
|
||||||
|
return QString::fromLatin1(file.readAll());
|
||||||
|
}
|
||||||
|
|
||||||
#include "moc_controller.cpp"
|
#include "moc_controller.cpp"
|
||||||
|
|
||||||
void Controller::setTestMode(bool test)
|
void Controller::setTestMode(bool test)
|
||||||
@@ -393,3 +401,12 @@ void Controller::removeConnection(const QString &userId)
|
|||||||
SettingsGroup("Accounts"_ls).remove(userId);
|
SettingsGroup("Accounts"_ls).remove(userId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Controller::ssssSupported() const
|
||||||
|
{
|
||||||
|
#if __has_include("Quotient/e2ee/sssshandler.h")
|
||||||
|
return true;
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|||||||
@@ -56,6 +56,8 @@ class Controller : public QObject
|
|||||||
|
|
||||||
Q_PROPERTY(QStringList accountsLoading MEMBER m_accountsLoading NOTIFY accountsLoadingChanged)
|
Q_PROPERTY(QStringList accountsLoading MEMBER m_accountsLoading NOTIFY accountsLoadingChanged)
|
||||||
|
|
||||||
|
Q_PROPERTY(bool ssssSupported READ ssssSupported CONSTANT)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static Controller &instance();
|
static Controller &instance();
|
||||||
static Controller *create(QQmlEngine *engine, QJSEngine *)
|
static Controller *create(QQmlEngine *engine, QJSEngine *)
|
||||||
@@ -92,12 +94,16 @@ public:
|
|||||||
*/
|
*/
|
||||||
static void listenForNotifications();
|
static void listenForNotifications();
|
||||||
|
|
||||||
|
Q_INVOKABLE QString loadFileContent(const QString &path) const;
|
||||||
|
|
||||||
Quotient::AccountRegistry &accounts();
|
Quotient::AccountRegistry &accounts();
|
||||||
|
|
||||||
static void setTestMode(bool testMode);
|
static void setTestMode(bool testMode);
|
||||||
|
|
||||||
Q_INVOKABLE void removeConnection(const QString &userId);
|
Q_INVOKABLE void removeConnection(const QString &userId);
|
||||||
|
|
||||||
|
bool ssssSupported() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit Controller(QObject *parent = nullptr);
|
explicit Controller(QObject *parent = nullptr);
|
||||||
|
|
||||||
|
|||||||
@@ -35,6 +35,11 @@
|
|||||||
|
|
||||||
#include "neochat-version.h"
|
#include "neochat-version.h"
|
||||||
|
|
||||||
|
#include <Quotient/accountregistry.h>
|
||||||
|
#if __has_include("Quotient/e2ee/sssshandler.h")
|
||||||
|
#include <Quotient/e2ee/sssshandler.h>
|
||||||
|
#endif
|
||||||
|
#include <Quotient/keyverificationsession.h>
|
||||||
#include <Quotient/networkaccessmanager.h>
|
#include <Quotient/networkaccessmanager.h>
|
||||||
|
|
||||||
#include "blurhashimageprovider.h"
|
#include "blurhashimageprovider.h"
|
||||||
@@ -230,6 +235,9 @@ int main(int argc, char *argv[])
|
|||||||
qmlRegisterSingletonInstance("org.kde.neochat.accounts", 1, 0, "AccountRegistry", &Controller::instance().accounts());
|
qmlRegisterSingletonInstance("org.kde.neochat.accounts", 1, 0, "AccountRegistry", &Controller::instance().accounts());
|
||||||
|
|
||||||
qmlRegisterUncreatableType<KeyVerificationSession>("com.github.quotient_im.libquotient", 1, 0, "KeyVerificationSession", {});
|
qmlRegisterUncreatableType<KeyVerificationSession>("com.github.quotient_im.libquotient", 1, 0, "KeyVerificationSession", {});
|
||||||
|
#if __has_include("Quotient/e2ee/sssshandler.h")
|
||||||
|
qmlRegisterType<SSSSHandler>("com.github.quotient_im.libquotient", 1, 0, "SSSSHandler");
|
||||||
|
#endif
|
||||||
|
|
||||||
QQmlApplicationEngine engine;
|
QQmlApplicationEngine engine;
|
||||||
|
|
||||||
|
|||||||
@@ -161,6 +161,10 @@
|
|||||||
<label>Enable threads</label>
|
<label>Enable threads</label>
|
||||||
<default>false</default>
|
<default>false</default>
|
||||||
</entry>
|
</entry>
|
||||||
|
<entry name="SecretBackup" type="bool">
|
||||||
|
<label>Enable secret backup</label>
|
||||||
|
<default>false</default>
|
||||||
|
</entry>
|
||||||
</group>
|
</group>
|
||||||
</kcfg>
|
</kcfg>
|
||||||
|
|
||||||
|
|||||||
@@ -62,6 +62,15 @@ QQC2.Menu {
|
|||||||
height: Kirigami.Units.gridUnit * 42
|
height: Kirigami.Units.gridUnit * 42
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
QQC2.MenuItem {
|
||||||
|
text: i18nc("@action:inmenu", "Open Secret Backup")
|
||||||
|
icon.name: "unlock"
|
||||||
|
visible: Config.secretBackup
|
||||||
|
onTriggered: pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'UnlockSSSSDialog.qml'), {}, {
|
||||||
|
title: i18nc("@title:window", "Open Key Backup")
|
||||||
|
})
|
||||||
|
enabled: Controller.ssssSupported
|
||||||
|
}
|
||||||
QQC2.MenuItem {
|
QQC2.MenuItem {
|
||||||
text: i18n("Logout")
|
text: i18n("Logout")
|
||||||
icon.name: "list-remove-user"
|
icon.name: "list-remove-user"
|
||||||
|
|||||||
@@ -23,5 +23,11 @@ FormCard.FormCardPage {
|
|||||||
|
|
||||||
onToggled: Config.threads = checked
|
onToggled: Config.threads = checked
|
||||||
}
|
}
|
||||||
|
FormCard.FormCheckDelegate {
|
||||||
|
text: i18nc("@option:check Enable the matrix 'secret backup' feature", "Secret Backup")
|
||||||
|
checked: Config.secretBackup
|
||||||
|
|
||||||
|
onToggled: Config.secretBackup = checked
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
137
src/qml/UnlockSSSSDialog.qml
Normal file
137
src/qml/UnlockSSSSDialog.qml
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2023 Tobias Fella <tobias.fella@kde.org>
|
||||||
|
// SPDX-License-Identifier: GPL-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 com.github.quotient_im.libquotient
|
||||||
|
|
||||||
|
import org.kde.neochat
|
||||||
|
|
||||||
|
FormCard.FormCardPage {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
title: i18nc("@title:window", "Load your encrypted messages")
|
||||||
|
|
||||||
|
topPadding: Kirigami.Units.gridUnit
|
||||||
|
leftPadding: 0
|
||||||
|
rightPadding: 0
|
||||||
|
|
||||||
|
header: KirigamiComponents.Banner {
|
||||||
|
id: banner
|
||||||
|
showCloseButton: true
|
||||||
|
visible: false
|
||||||
|
type: Kirigami.MessageType.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
property SSSSHandler ssssHandler: SSSSHandler {
|
||||||
|
id: ssssHandler
|
||||||
|
|
||||||
|
property bool processing: false
|
||||||
|
|
||||||
|
connection: Controller.activeConnection
|
||||||
|
onKeyBackupUnlocked: {
|
||||||
|
ssssHandler.processing = false
|
||||||
|
root.closeDialog()
|
||||||
|
}
|
||||||
|
onError: error => {
|
||||||
|
if (error !== SSSSHandler.WrongKeyError) {
|
||||||
|
banner.text = error
|
||||||
|
banner.visible = true
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
passwordField.clear()
|
||||||
|
ssssHandler.processing = false
|
||||||
|
banner.text = i18nc("@info:status", "The security phrase was not correct.")
|
||||||
|
banner.visible = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FormCard.FormHeader {
|
||||||
|
title: i18nc("@title", "Unlock using Passphrase")
|
||||||
|
}
|
||||||
|
FormCard.FormCard {
|
||||||
|
FormCard.FormTextDelegate {
|
||||||
|
description: i18nc("@info", "If you have a backup passphrase for this account, enter it below.")
|
||||||
|
}
|
||||||
|
FormCard.FormTextFieldDelegate {
|
||||||
|
id: passwordField
|
||||||
|
label: i18nc("@label:textbox", "Backup Password:")
|
||||||
|
echoMode: TextInput.Password
|
||||||
|
}
|
||||||
|
FormCard.FormButtonDelegate {
|
||||||
|
id: unlockButton
|
||||||
|
text: i18nc("@action:button", "Unlock")
|
||||||
|
icon.name: "unlock"
|
||||||
|
enabled: passwordField.text.length > 0 && !ssssHandler.processing
|
||||||
|
onClicked: {
|
||||||
|
ssssHandler.processing = true
|
||||||
|
banner.visible = false
|
||||||
|
ssssHandler.unlockSSSSWithPassphrase(passwordField.text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FormCard.FormHeader {
|
||||||
|
title: i18nc("@title", "Unlock using Security Key")
|
||||||
|
}
|
||||||
|
FormCard.FormCard {
|
||||||
|
FormCard.FormTextDelegate {
|
||||||
|
description: i18nc("@info", "If you have a security key for this account, enter it below or upload it as a file.")
|
||||||
|
}
|
||||||
|
FormCard.FormTextFieldDelegate {
|
||||||
|
id: securityKeyField
|
||||||
|
label: i18nc("@label:textbox", "Security Key:")
|
||||||
|
echoMode: TextInput.Password
|
||||||
|
}
|
||||||
|
FormCard.FormButtonDelegate {
|
||||||
|
id: uploadSecurityKeyButton
|
||||||
|
text: i18nc("@action:button", "Upload from File")
|
||||||
|
icon.name: "cloud-upload"
|
||||||
|
enabled: !ssssHandler.processing
|
||||||
|
onClicked: {
|
||||||
|
ssssHandler.processing = true
|
||||||
|
openFileDialog.open()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FormCard.FormButtonDelegate {
|
||||||
|
id: unlockSecurityKeyButton
|
||||||
|
text: i18nc("@action:button", "Unlock")
|
||||||
|
icon.name: "unlock"
|
||||||
|
enabled: securityKeyField.text.length > 0 && !ssssHandler.processing
|
||||||
|
onClicked: {
|
||||||
|
ssssHandler.processing = true
|
||||||
|
ssssHandler.unlockSSSSFromSecurityKey(securityKeyField.text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FormCard.FormHeader {
|
||||||
|
title: i18nc("@title", "Unlock from Cross-Signing")
|
||||||
|
}
|
||||||
|
FormCard.FormCard {
|
||||||
|
FormCard.FormTextDelegate {
|
||||||
|
description: i18nc("@info", "If you have previously verified this device, you can try loading the backup key from other devices by clicking the button below.")
|
||||||
|
}
|
||||||
|
FormCard.FormButtonDelegate {
|
||||||
|
id: unlockCrossSigningButton
|
||||||
|
icon.name: "emblem-shared-symbolic"
|
||||||
|
text: i18nc("@action:button", "Request from other Devices")
|
||||||
|
enabled: !ssssHandler.processing
|
||||||
|
onClicked: {
|
||||||
|
ssssHandler.processing = true
|
||||||
|
ssssHandler.unlockSSSSFromCrossSigning()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
property OpenFileDialog openFileDialog: OpenFileDialog {
|
||||||
|
id: openFileDialog
|
||||||
|
onChosen: securityKeyField.text = Controller.loadFileContent(path)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user