From d7202ae0a7393c31a22b18e0be965ab8738f4d99 Mon Sep 17 00:00:00 2001 From: Joshua Goins Date: Tue, 24 Dec 2024 21:45:08 -0500 Subject: [PATCH] Implement request for user data erasure This adds UI for MSC4025 to the account deactivation dialog, if the server supports it. We also switch away from our customDeactivateAccountJob to libQuotient's. Fixes #670. --- src/CMakeLists.txt | 2 -- src/jobs/neochatdeactivateaccountjob.cpp | 14 ----------- src/jobs/neochatdeactivateaccountjob.h | 12 ---------- src/neochatconnection.cpp | 28 +++++++++++++--------- src/neochatconnection.h | 10 +++++++- src/qml/ConfirmDeactivateAccountDialog.qml | 24 +++++++++++++------ 6 files changed, 43 insertions(+), 47 deletions(-) delete mode 100644 src/jobs/neochatdeactivateaccountjob.cpp delete mode 100644 src/jobs/neochatdeactivateaccountjob.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 07c9b0a33..1828bcdd0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -126,8 +126,6 @@ add_library(neochat STATIC registration.cpp neochatconnection.cpp neochatconnection.h - jobs/neochatdeactivateaccountjob.cpp - jobs/neochatdeactivateaccountjob.h jobs/neochatgetcommonroomsjob.cpp jobs/neochatgetcommonroomsjob.h mediasizehelper.cpp diff --git a/src/jobs/neochatdeactivateaccountjob.cpp b/src/jobs/neochatdeactivateaccountjob.cpp deleted file mode 100644 index 8fc90810d..000000000 --- a/src/jobs/neochatdeactivateaccountjob.cpp +++ /dev/null @@ -1,14 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Tobias Fella -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "neochatdeactivateaccountjob.h" - -using namespace Quotient; - -NeoChatDeactivateAccountJob::NeoChatDeactivateAccountJob(const std::optional &auth) - : BaseJob(HttpVerb::Post, u"DisableDeviceJob"_s, "_matrix/client/v3/account/deactivate") -{ - QJsonObject data; - addParam(data, u"auth"_s, auth); - setRequestData(data); -} diff --git a/src/jobs/neochatdeactivateaccountjob.h b/src/jobs/neochatdeactivateaccountjob.h deleted file mode 100644 index 327c04761..000000000 --- a/src/jobs/neochatdeactivateaccountjob.h +++ /dev/null @@ -1,12 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Tobias Fella -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include - -class NeoChatDeactivateAccountJob : public Quotient::BaseJob -{ -public: - explicit NeoChatDeactivateAccountJob(const std::optional &auth = {}); -}; diff --git a/src/neochatconnection.cpp b/src/neochatconnection.cpp index a001d5172..1ae4e8432 100644 --- a/src/neochatconnection.cpp +++ b/src/neochatconnection.cpp @@ -6,7 +6,6 @@ #include #include -#include "jobs/neochatdeactivateaccountjob.h" #include "neochatconfig.h" #include "neochatroom.h" #include "spacehierarchycache.h" @@ -142,6 +141,8 @@ void NeoChatConnection::connectSignals() connect(job, &GetVersionsJob::success, this, [this, job] { m_canCheckMutualRooms = job->unstableFeatures().contains("uk.half-shot.msc2666.query_mutual_rooms"_L1); Q_EMIT canCheckMutualRoomsChanged(); + m_canEraseData = job->unstableFeatures().contains("org.matrix.msc4025"_L1) || job->versions().count("v1.10"_L1); + Q_EMIT canEraseDataChanged(); }); }, Qt::SingleShotConnection); @@ -255,20 +256,20 @@ QString NeoChatConnection::label() const return accountDataJson("org.kde.neochat.account_label"_L1)["account_label"_L1].toString(); } -void NeoChatConnection::deactivateAccount(const QString &password) +void NeoChatConnection::deactivateAccount(const QString &password, const bool erase) { - auto job = callApi(); - connect(job, &BaseJob::result, this, [this, job, password] { + auto job = callApi(); + connect(job, &BaseJob::result, this, [this, job, password, erase] { if (job->error() == 103) { QJsonObject replyData = job->jsonData(); - QJsonObject authData; - authData["session"_L1] = replyData["session"_L1]; - authData["password"_L1] = password; - authData["type"_L1] = "m.login.password"_L1; - authData["user"_L1] = user()->id(); + AuthenticationData authData; + authData.session = replyData["session"_L1].toString(); + authData.authInfo["password"_L1] = password; + authData.type = "m.login.password"_L1; + authData.authInfo["user"_L1] = user()->id(); QJsonObject identifier = {{"type"_L1, "m.id.user"_L1}, {"user"_L1, user()->id()}}; - authData["identifier"_L1] = identifier; - auto innerJob = callApi(authData); + authData.authInfo["identifier"_L1] = identifier; + auto innerJob = callApi(authData, QString{}, erase); connect(innerJob, &BaseJob::success, this, [this]() { logout(false); }); @@ -548,4 +549,9 @@ KeyImport::Error NeoChatConnection::exportMegolmSessions(const QString &passphra return KeyImport::Success; } +bool NeoChatConnection::canEraseData() const +{ + return m_canEraseData; +} + #include "moc_neochatconnection.cpp" diff --git a/src/neochatconnection.h b/src/neochatconnection.h index 79054994c..519f77c7d 100644 --- a/src/neochatconnection.h +++ b/src/neochatconnection.h @@ -87,6 +87,11 @@ class NeoChatConnection : public Quotient::Connection */ Q_PROPERTY(bool canCheckMutualRooms READ canCheckMutualRooms NOTIFY canCheckMutualRoomsChanged) + /** + * @brief Whether the server supports erasing user data when deactivating the account. This checks for MSC4025. + */ + Q_PROPERTY(bool canEraseData READ canEraseData NOTIFY canEraseDataChanged) + public: /** * @brief Defines the status after an attempt to change the password on an account. @@ -104,6 +109,7 @@ public: Q_INVOKABLE void logout(bool serverSideLogout); Q_INVOKABLE QVariantList getSupportedRoomVersions() const; bool canCheckMutualRooms() const; + bool canEraseData() const; /** * @brief Change the password for an account. @@ -123,7 +129,7 @@ public: [[nodiscard]] QString label() const; void setLabel(const QString &label); - Q_INVOKABLE void deactivateAccount(const QString &password); + Q_INVOKABLE void deactivateAccount(const QString &password, bool erase); ThreePIdModel *threePIdModel() const; @@ -194,6 +200,7 @@ Q_SIGNALS: void userConsentRequired(QUrl url); void badgeNotificationCountChanged(NeoChatConnection *connection, int count); void canCheckMutualRoomsChanged(); + void canEraseDataChanged(); /** * @brief Request a message be shown to the user of the given type. @@ -223,4 +230,5 @@ private: QCache m_linkPreviewers; bool m_canCheckMutualRooms = false; + bool m_canEraseData = false; }; diff --git a/src/qml/ConfirmDeactivateAccountDialog.qml b/src/qml/ConfirmDeactivateAccountDialog.qml index a45eb138b..f7e933b4b 100644 --- a/src/qml/ConfirmDeactivateAccountDialog.qml +++ b/src/qml/ConfirmDeactivateAccountDialog.qml @@ -2,6 +2,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later import QtQuick +import QtQuick.Layouts import QtQuick.Controls as QQC2 import org.kde.kirigamiaddons.formcard as FormCard @@ -18,12 +19,21 @@ Kirigami.PromptDialog { dialogType: Kirigami.PromptDialog.Warning - mainItem: FormCard.FormTextFieldDelegate { - id: passwordField - label: i18nc("@label:textbox", "Password") - echoMode: TextInput.Password - horizontalPadding: 0 - bottomPadding: 0 + mainItem: ColumnLayout { + FormCard.FormTextFieldDelegate { + id: passwordField + label: i18nc("@label:textbox", "Password") + echoMode: TextInput.Password + horizontalPadding: 0 + bottomPadding: 0 + } + + FormCard.FormCheckDelegate { + id: eraseDelegate + text: i18nc("@label:checkbox", "Erase Data") + description: i18nc("@info", "Request your server to delete as much user data as possible.") + visible: connection.canEraseData + } } footer: QQC2.DialogButtonBox { @@ -34,7 +44,7 @@ Kirigami.PromptDialog { icon.name: "emblem-warning" enabled: passwordField.text.length > 0 onClicked: { - root.connection.deactivateAccount(passwordField.text); + root.connection.deactivateAccount(passwordField.text, eraseDelegate.checked); root.closeDialog(); } }