Support adding 3 PIDs
Implements part of network/neochat#565 Note the phone number stuff is untested as neither kde.org or matrix.org have them switched on.
This commit is contained in:
@@ -175,6 +175,10 @@ add_library(neochat STATIC
|
|||||||
foreigntypes.h
|
foreigntypes.h
|
||||||
models/threepidmodel.cpp
|
models/threepidmodel.cpp
|
||||||
models/threepidmodel.h
|
models/threepidmodel.h
|
||||||
|
threepidaddhelper.cpp
|
||||||
|
threepidaddhelper.h
|
||||||
|
jobs/neochatadd3pidjob.cpp
|
||||||
|
jobs/neochatadd3pidjob.h
|
||||||
)
|
)
|
||||||
|
|
||||||
set_source_files_properties(qml/OsmLocationPlugin.qml PROPERTIES
|
set_source_files_properties(qml/OsmLocationPlugin.qml PROPERTIES
|
||||||
|
|||||||
@@ -28,5 +28,14 @@ FormCard.FormCardPage {
|
|||||||
|
|
||||||
onToggled: Config.secretBackup = checked
|
onToggled: Config.secretBackup = checked
|
||||||
}
|
}
|
||||||
|
FormCard.FormCheckDelegate {
|
||||||
|
text: i18nc("@option:check Enable the matrix feature to add a phone number as a third party ID", "Add phone numbers as 3PIDs")
|
||||||
|
checked: Config.phone3PId
|
||||||
|
|
||||||
|
onToggled: {
|
||||||
|
Config.phone3PId = checked
|
||||||
|
Config.save();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
16
src/jobs/neochatadd3pidjob.cpp
Normal file
16
src/jobs/neochatadd3pidjob.cpp
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2024 James Graham <james.h.graham@protonmail.com>
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||||
|
|
||||||
|
#include "neochatadd3pidjob.h"
|
||||||
|
|
||||||
|
using namespace Quotient;
|
||||||
|
|
||||||
|
NeochatAdd3PIdJob::NeochatAdd3PIdJob(const QString &clientSecret, const QString &sid, const Omittable<QJsonObject> &auth)
|
||||||
|
: BaseJob(HttpVerb::Post, QStringLiteral("Add3PIDJob"), makePath("/_matrix/client/v3", "/account/3pid/add"))
|
||||||
|
{
|
||||||
|
QJsonObject _dataJson;
|
||||||
|
addParam<IfNotEmpty>(_dataJson, QStringLiteral("auth"), auth);
|
||||||
|
addParam<>(_dataJson, QStringLiteral("client_secret"), clientSecret);
|
||||||
|
addParam<>(_dataJson, QStringLiteral("sid"), sid);
|
||||||
|
setRequestData({_dataJson});
|
||||||
|
}
|
||||||
13
src/jobs/neochatadd3pidjob.h
Normal file
13
src/jobs/neochatadd3pidjob.h
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2024 James Graham <james.h.graham@protonmail.com>
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Quotient/jobs/basejob.h>
|
||||||
|
#include <Quotient/omittable.h>
|
||||||
|
|
||||||
|
class NeochatAdd3PIdJob : public Quotient::BaseJob
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit NeochatAdd3PIdJob(const QString &clientSecret, const QString &sid, const Quotient::Omittable<QJsonObject> &auth = Quotient::none);
|
||||||
|
};
|
||||||
@@ -10,15 +10,7 @@ ThreePIdModel::ThreePIdModel(NeoChatConnection *connection)
|
|||||||
{
|
{
|
||||||
Q_ASSERT(connection);
|
Q_ASSERT(connection);
|
||||||
connect(connection, &NeoChatConnection::stateChanged, this, [this]() {
|
connect(connection, &NeoChatConnection::stateChanged, this, [this]() {
|
||||||
const auto connection = dynamic_cast<NeoChatConnection *>(this->parent());
|
refreshModel();
|
||||||
if (connection != nullptr && connection->isLoggedIn()) {
|
|
||||||
const auto threePIdJob = connection->callApi<Quotient::GetAccount3PIDsJob>();
|
|
||||||
connect(threePIdJob, &Quotient::BaseJob::success, this, [this, threePIdJob]() {
|
|
||||||
beginResetModel();
|
|
||||||
m_threePIds = threePIdJob->threepids();
|
|
||||||
endResetModel();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,4 +48,17 @@ QHash<int, QByteArray> ThreePIdModel::roleNames() const
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ThreePIdModel::refreshModel()
|
||||||
|
{
|
||||||
|
const auto connection = dynamic_cast<NeoChatConnection *>(this->parent());
|
||||||
|
if (connection != nullptr && connection->isLoggedIn()) {
|
||||||
|
const auto threePIdJob = connection->callApi<Quotient::GetAccount3PIDsJob>();
|
||||||
|
connect(threePIdJob, &Quotient::BaseJob::success, this, [this, threePIdJob]() {
|
||||||
|
beginResetModel();
|
||||||
|
m_threePIds = threePIdJob->threepids();
|
||||||
|
endResetModel();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#include "moc_threepidmodel.cpp"
|
#include "moc_threepidmodel.cpp"
|
||||||
|
|||||||
@@ -53,6 +53,8 @@ public:
|
|||||||
*/
|
*/
|
||||||
[[nodiscard]] QHash<int, QByteArray> roleNames() const override;
|
[[nodiscard]] QHash<int, QByteArray> roleNames() const override;
|
||||||
|
|
||||||
|
Q_INVOKABLE void refreshModel();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QVector<Quotient::GetAccount3PIDsJob::ThirdPartyIdentifier> m_threePIds;
|
QVector<Quotient::GetAccount3PIDsJob::ThirdPartyIdentifier> m_threePIds;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -182,6 +182,10 @@
|
|||||||
<label>Enable secret backup</label>
|
<label>Enable secret backup</label>
|
||||||
<default>false</default>
|
<default>false</default>
|
||||||
</entry>
|
</entry>
|
||||||
|
<entry name="Phone3PId" type="bool">
|
||||||
|
<label>Enable add phone numbers as 3PIDs</label>
|
||||||
|
<default>false</default>
|
||||||
|
</entry>
|
||||||
</group>
|
</group>
|
||||||
</kcfg>
|
</kcfg>
|
||||||
|
|
||||||
|
|||||||
@@ -48,11 +48,15 @@ RowLayout {
|
|||||||
|
|
||||||
activeFocusOnTab: true
|
activeFocusOnTab: true
|
||||||
|
|
||||||
onClicked: pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat.settings', 'AccountEditorPage'), {
|
onClicked: pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat.settings', 'NeoChatSettings'), {
|
||||||
connection: root.connection
|
defaultPage: "accounts",
|
||||||
|
connection: root.connection,
|
||||||
|
initialAccount: root.connection
|
||||||
}, {
|
}, {
|
||||||
title: i18nc("@title:window", "Account editor")
|
title: i18nc("@action:button", "Configure"),
|
||||||
});
|
width: Kirigami.Units.gridUnit * 50,
|
||||||
|
height: Kirigami.Units.gridUnit * 42
|
||||||
|
})
|
||||||
|
|
||||||
TapHandler {
|
TapHandler {
|
||||||
acceptedButtons: Qt.RightButton
|
acceptedButtons: Qt.RightButton
|
||||||
|
|||||||
@@ -202,6 +202,7 @@ FormCard.FormCardPage {
|
|||||||
medium: "email"
|
medium: "email"
|
||||||
}
|
}
|
||||||
ThreePIdCard {
|
ThreePIdCard {
|
||||||
|
visible: Config.phone3PId
|
||||||
connection: root.connection
|
connection: root.connection
|
||||||
title: i18n("Phone Numbers")
|
title: i18n("Phone Numbers")
|
||||||
medium: "msisdn"
|
medium: "msisdn"
|
||||||
|
|||||||
@@ -16,8 +16,25 @@ import org.kde.neochat
|
|||||||
FormCard.FormCardPage {
|
FormCard.FormCardPage {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
property NeoChatConnection initialAccount
|
||||||
|
|
||||||
title: i18n("Accounts")
|
title: i18n("Accounts")
|
||||||
|
|
||||||
|
Component.onCompleted: if (initialAccount) {
|
||||||
|
intialAccountTimer.restart()
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: intialAccountTimer
|
||||||
|
interval: 10
|
||||||
|
running: false
|
||||||
|
onTriggered: applicationWindow().pageStack.layers.push(Qt.createComponent('org.kde.neochat.settings', 'AccountEditorPage'), {
|
||||||
|
connection: initialAccount
|
||||||
|
}, {
|
||||||
|
title: i18n("Account editor")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
FormCard.FormHeader {
|
FormCard.FormHeader {
|
||||||
title: i18n("Accounts")
|
title: i18n("Accounts")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ qt_add_qml_module(settings
|
|||||||
EmoticonFormCard.qml
|
EmoticonFormCard.qml
|
||||||
IgnoredUsersDialog.qml
|
IgnoredUsersDialog.qml
|
||||||
NotificationRuleItem.qml
|
NotificationRuleItem.qml
|
||||||
|
PasswordSheet.qml
|
||||||
ThemeRadioButton.qml
|
ThemeRadioButton.qml
|
||||||
ThreePIdCard.qml
|
ThreePIdCard.qml
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ KirigamiSettings.CategorizedSettings {
|
|||||||
|
|
||||||
property NeoChatConnection connection
|
property NeoChatConnection connection
|
||||||
|
|
||||||
|
property NeoChatConnection initialAccount
|
||||||
|
|
||||||
objectName: "settingsPage"
|
objectName: "settingsPage"
|
||||||
actions: [
|
actions: [
|
||||||
KirigamiSettings.SettingAction {
|
KirigamiSettings.SettingAction {
|
||||||
@@ -54,6 +56,11 @@ KirigamiSettings.CategorizedSettings {
|
|||||||
text: i18n("Accounts")
|
text: i18n("Accounts")
|
||||||
icon.name: "preferences-system-users"
|
icon.name: "preferences-system-users"
|
||||||
page: Qt.resolvedUrl("AccountsPage.qml")
|
page: Qt.resolvedUrl("AccountsPage.qml")
|
||||||
|
initialProperties: {
|
||||||
|
return {
|
||||||
|
initialAccount: root.initialAccount
|
||||||
|
};
|
||||||
|
}
|
||||||
},
|
},
|
||||||
KirigamiSettings.SettingAction {
|
KirigamiSettings.SettingAction {
|
||||||
actionName: "emoticons"
|
actionName: "emoticons"
|
||||||
|
|||||||
34
src/settings/PasswordSheet.qml
Normal file
34
src/settings/PasswordSheet.qml
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2024 James Graham <james.h.graham@protonmail.com>
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls as QQC2
|
||||||
|
import QtQuick.Layouts
|
||||||
|
|
||||||
|
import org.kde.kirigami as Kirigami
|
||||||
|
import org.kde.kirigamiaddons.formcard as FormCard
|
||||||
|
|
||||||
|
Kirigami.Dialog {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
signal submitPassword(string password)
|
||||||
|
|
||||||
|
title: i18nc("@title:dialog", "Enter password")
|
||||||
|
|
||||||
|
preferredWidth: Kirigami.Units.gridUnit * 24
|
||||||
|
|
||||||
|
standardButtons: QQC2.Dialog.Ok | QQC2.Dialog.Cancel
|
||||||
|
onAccepted: {
|
||||||
|
root.submitPassword(passwordField.text);
|
||||||
|
passwordField.text = "";
|
||||||
|
root.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
FormCard.FormTextFieldDelegate {
|
||||||
|
id: passwordField
|
||||||
|
label: i18nc("@label:textbox", "Password:")
|
||||||
|
echoMode: TextInput.Password
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
import QtQuick
|
import QtQuick
|
||||||
|
import QtQuick.Controls as QQC2
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
|
|
||||||
import org.kde.kirigami as Kirigami
|
import org.kde.kirigami as Kirigami
|
||||||
@@ -18,8 +19,6 @@ ColumnLayout {
|
|||||||
required property string title
|
required property string title
|
||||||
required property string medium
|
required property string medium
|
||||||
|
|
||||||
visible: deviceRepeater.count > 0
|
|
||||||
|
|
||||||
FormCard.FormHeader {
|
FormCard.FormHeader {
|
||||||
title: root.title
|
title: root.title
|
||||||
}
|
}
|
||||||
@@ -34,10 +33,124 @@ ColumnLayout {
|
|||||||
filterString: root.medium
|
filterString: root.medium
|
||||||
}
|
}
|
||||||
|
|
||||||
delegate: FormCard.FormTextDelegate {
|
delegate: FormCard.AbstractFormDelegate {
|
||||||
|
id: threePIdDelegate
|
||||||
|
required property string address
|
||||||
|
required property string medium
|
||||||
|
|
||||||
|
contentItem: RowLayout {
|
||||||
|
QQC2.Label {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: threePIdDelegate.address
|
||||||
|
textFormat: Text.PlainText
|
||||||
|
elide: Text.ElideRight
|
||||||
|
wrapMode: Text.Wrap
|
||||||
|
maximumLineCount: 2
|
||||||
|
color: Kirigami.Theme.textColor
|
||||||
|
}
|
||||||
|
QQC2.ToolButton {
|
||||||
|
text: i18nc("@action:button", "Remove")
|
||||||
|
icon.name: "edit-delete-remove"
|
||||||
|
onClicked: threePIdAddHelper.remove3PId(threePIdDelegate.address, threePIdDelegate.medium)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
FormCard.FormTextDelegate {
|
||||||
required property string address
|
required property string address
|
||||||
text: address
|
text: address
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
FormCard.FormTextFieldDelegate {
|
||||||
|
id: newCountryCode
|
||||||
|
visible: root.medium === "msisdn"
|
||||||
|
readOnly: threePIdAddHelper.newIdStatus == ThreePIdAddHelper.Verification ||
|
||||||
|
threePIdAddHelper.newIdStatus == ThreePIdAddHelper.Authentication ||
|
||||||
|
threePIdAddHelper.newIdStatus == ThreePIdAddHelper.AuthFailure ||
|
||||||
|
threePIdAddHelper.newIdStatus == ThreePIdAddHelper.VerificationFailure
|
||||||
|
label: i18nc("@label:textbox", "Country Code for new phone number")
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: root.connection.threePIdModel
|
||||||
|
|
||||||
|
function onModelReset() {
|
||||||
|
newCountryCode.text = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FormCard.FormTextFieldDelegate {
|
||||||
|
id: newId
|
||||||
|
readOnly: threePIdAddHelper.newIdStatus == ThreePIdAddHelper.Verification ||
|
||||||
|
threePIdAddHelper.newIdStatus == ThreePIdAddHelper.Authentication ||
|
||||||
|
threePIdAddHelper.newIdStatus == ThreePIdAddHelper.AuthFailure ||
|
||||||
|
threePIdAddHelper.newIdStatus == ThreePIdAddHelper.VerificationFailure
|
||||||
|
label: root.medium === "email" ? i18nc("@label:textbox", "New email address") : i18nc("@label:textbox", "New phone number")
|
||||||
|
|
||||||
|
statusMessage: switch(threePIdAddHelper.newIdStatus) {
|
||||||
|
case ThreePIdAddHelper.Verification:
|
||||||
|
return i18n("%1. Please follow the instructions there and then click the button below", root.medium == "email" ? i18n("We've sent you an email") : i18n("We've sent you a text message"));
|
||||||
|
case ThreePIdAddHelper.Invalid:
|
||||||
|
return root.medium == "email" ? i18n("The entered email is not valid") : i18n("The entered phone number is not valid");
|
||||||
|
case ThreePIdAddHelper.AuthFailure:
|
||||||
|
return i18n("Incorrect password entered");
|
||||||
|
case ThreePIdAddHelper.VerificationFailure:
|
||||||
|
return root.medium == "email" ? i18n("The email has not been verified. Please go to the email and follow the instructions there and then click the button below") : i18n("The phone number has not been verified. Please go to the text message and follow the instructions there and then click the button below");
|
||||||
|
default:
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
status: switch(threePIdAddHelper.newIdStatus) {
|
||||||
|
case ThreePIdAddHelper.Invalid:
|
||||||
|
case ThreePIdAddHelper.AuthFailure:
|
||||||
|
return Kirigami.MessageType.Error;
|
||||||
|
case ThreePIdAddHelper.VerificationFailure:
|
||||||
|
return Kirigami.MessageType.Warning;
|
||||||
|
default:
|
||||||
|
return Kirigami.MessageType.Information;
|
||||||
|
}
|
||||||
|
|
||||||
|
onAccepted: _private.openPasswordSheet()
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: root.connection.threePIdModel
|
||||||
|
|
||||||
|
function onModelReset() {
|
||||||
|
newId.text = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FormCard.FormButtonDelegate {
|
||||||
|
text: threePIdAddHelper.newIdStatus == ThreePIdAddHelper.Ready ? i18nc("@action:button Add new email or phone number", "Add") : i18nc("@action:button", "Continue")
|
||||||
|
onClicked: _private.openPasswordSheet()
|
||||||
|
}
|
||||||
|
FormCard.FormButtonDelegate {
|
||||||
|
visible: threePIdAddHelper.newIdStatus == ThreePIdAddHelper.Verification ||
|
||||||
|
threePIdAddHelper.newIdStatus == ThreePIdAddHelper.Authentication ||
|
||||||
|
threePIdAddHelper.newIdStatus == ThreePIdAddHelper.AuthFailure ||
|
||||||
|
threePIdAddHelper.newIdStatus == ThreePIdAddHelper.VerificationFailure
|
||||||
|
text: i18nc("@action:button As in 'go back'", "Back")
|
||||||
|
onClicked: threePIdAddHelper.back()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ThreePIdAddHelper {
|
||||||
|
id: threePIdAddHelper
|
||||||
|
connection: root.connection
|
||||||
|
medium: root.medium
|
||||||
|
newId: newId.text
|
||||||
|
}
|
||||||
|
|
||||||
|
QtObject {
|
||||||
|
id: _private
|
||||||
|
function openPasswordSheet() {
|
||||||
|
if (threePIdAddHelper.newIdStatus == ThreePIdAddHelper.Ready) {
|
||||||
|
threePIdAddHelper.initiateNewIdAdd();
|
||||||
|
} else {
|
||||||
|
let dialog = Qt.createComponent('org.kde.neochat.settings', 'PasswordSheet').createObject(root, {});
|
||||||
|
dialog.submitPassword.connect(password => threePIdAddHelper.finalizeNewIdAdd(password));
|
||||||
|
dialog.open();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
199
src/threepidaddhelper.cpp
Normal file
199
src/threepidaddhelper.cpp
Normal file
@@ -0,0 +1,199 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2024 James Graham <james.h.graham@protonmail.com>
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||||
|
|
||||||
|
#include "threepidaddhelper.h"
|
||||||
|
|
||||||
|
#include <Quotient/converters.h>
|
||||||
|
#include <Quotient/csapi/definitions/auth_data.h>
|
||||||
|
#include <Quotient/csapi/definitions/request_msisdn_validation.h>
|
||||||
|
#include <Quotient/jobs/basejob.h>
|
||||||
|
|
||||||
|
#include "jobs/neochatadd3pidjob.h"
|
||||||
|
#include "neochatconnection.h"
|
||||||
|
|
||||||
|
ThreePIdAddHelper::ThreePIdAddHelper(QObject *parent)
|
||||||
|
: QObject(parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
NeoChatConnection *ThreePIdAddHelper::connection() const
|
||||||
|
{
|
||||||
|
return m_connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ThreePIdAddHelper::setConnection(NeoChatConnection *connection)
|
||||||
|
{
|
||||||
|
if (m_connection == connection) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_connection = connection;
|
||||||
|
Q_EMIT connectionChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ThreePIdAddHelper::medium() const
|
||||||
|
{
|
||||||
|
return m_medium;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ThreePIdAddHelper::setMedium(const QString &medium)
|
||||||
|
{
|
||||||
|
if (m_medium == medium) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_medium = medium;
|
||||||
|
Q_EMIT mediumChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ThreePIdAddHelper::newId() const
|
||||||
|
{
|
||||||
|
return m_newId;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ThreePIdAddHelper::setNewId(const QString &newId)
|
||||||
|
{
|
||||||
|
if (newId == m_newId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_newId = newId;
|
||||||
|
Q_EMIT newIdChanged();
|
||||||
|
|
||||||
|
m_newIdSecret.clear();
|
||||||
|
m_newIdSid.clear();
|
||||||
|
m_newIdStatus = Ready;
|
||||||
|
Q_EMIT newIdStatusChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ThreePIdAddHelper::newCountryCode() const
|
||||||
|
{
|
||||||
|
return m_newCountryCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ThreePIdAddHelper::setNewCountryCode(const QString &newCountryCode)
|
||||||
|
{
|
||||||
|
if (newCountryCode == m_newCountryCode) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_newCountryCode = newCountryCode;
|
||||||
|
Q_EMIT newCountryCodeChanged();
|
||||||
|
|
||||||
|
m_newIdSecret.clear();
|
||||||
|
m_newIdSid.clear();
|
||||||
|
m_newIdStatus = Ready;
|
||||||
|
Q_EMIT newIdStatusChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ThreePIdAddHelper::initiateNewIdAdd()
|
||||||
|
{
|
||||||
|
if (m_newId.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (m_medium == QLatin1String("email")) {
|
||||||
|
emailTokenJob();
|
||||||
|
} else {
|
||||||
|
msisdnTokenJob();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ThreePIdAddHelper::emailTokenJob()
|
||||||
|
{
|
||||||
|
m_newIdSecret = QString::fromLatin1(QUuid::createUuid().toString().toLatin1().toBase64());
|
||||||
|
Quotient::EmailValidationData data;
|
||||||
|
data.email = m_newId;
|
||||||
|
data.clientSecret = m_newIdSecret;
|
||||||
|
data.sendAttempt = 0;
|
||||||
|
|
||||||
|
const auto job = m_connection->callApi<Quotient::RequestTokenTo3PIDEmailJob>(data);
|
||||||
|
connect(job, &Quotient::BaseJob::finished, this, &ThreePIdAddHelper::tokenJobFinished);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ThreePIdAddHelper::msisdnTokenJob()
|
||||||
|
{
|
||||||
|
m_newIdSecret = QString::fromLatin1(QUuid::createUuid().toString().toLatin1().toBase64());
|
||||||
|
Quotient::MsisdnValidationData data;
|
||||||
|
data.country = m_newCountryCode;
|
||||||
|
data.phoneNumber = m_newId;
|
||||||
|
data.clientSecret = m_newIdSecret;
|
||||||
|
data.sendAttempt = 0;
|
||||||
|
|
||||||
|
const auto job = m_connection->callApi<Quotient::RequestTokenTo3PIDMSISDNJob>(data);
|
||||||
|
connect(job, &Quotient::BaseJob::finished, this, &ThreePIdAddHelper::tokenJobFinished);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ThreePIdAddHelper::tokenJobFinished(Quotient::BaseJob *job)
|
||||||
|
{
|
||||||
|
if (job->status() == Quotient::BaseJob::Success) {
|
||||||
|
m_newIdSid = job->jsonData()[QLatin1String("sid")].toString();
|
||||||
|
m_newIdStatus = Verification;
|
||||||
|
Q_EMIT newIdStatusChanged();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_newIdStatus = Invalid;
|
||||||
|
Q_EMIT newIdStatusChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
ThreePIdAddHelper::ThreePIdStatus ThreePIdAddHelper::newIdStatus() const
|
||||||
|
{
|
||||||
|
return m_newIdStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ThreePIdAddHelper::finalizeNewIdAdd(const QString &password)
|
||||||
|
{
|
||||||
|
const auto job = m_connection->callApi<NeochatAdd3PIdJob>(m_newIdSecret, m_newIdSid);
|
||||||
|
connect(job, &Quotient::BaseJob::result, this, [this, job, password] {
|
||||||
|
m_newIdStatus = Authentication;
|
||||||
|
Q_EMIT newIdStatusChanged();
|
||||||
|
|
||||||
|
if (static_cast<Quotient::BaseJob::StatusCode>(job->error()) == Quotient::BaseJob::Unauthorised) {
|
||||||
|
QJsonObject replyData = job->jsonData();
|
||||||
|
QJsonObject authData;
|
||||||
|
authData[QLatin1String("session")] = replyData[QLatin1String("session")];
|
||||||
|
authData[QLatin1String("password")] = password;
|
||||||
|
authData[QLatin1String("type")] = QLatin1String("m.login.password");
|
||||||
|
QJsonObject identifier = {{QLatin1String("type"), QLatin1String("m.id.user")}, {QLatin1String("user"), m_connection->userId()}};
|
||||||
|
authData[QLatin1String("identifier")] = identifier;
|
||||||
|
const auto innerJob = m_connection->callApi<NeochatAdd3PIdJob>(m_newIdSecret, m_newIdSid, authData);
|
||||||
|
connect(innerJob, &Quotient::BaseJob::success, this, [this]() {
|
||||||
|
m_connection->threePIdModel()->refreshModel();
|
||||||
|
m_newIdSecret.clear();
|
||||||
|
m_newIdSid.clear();
|
||||||
|
m_newIdStatus = Success;
|
||||||
|
Q_EMIT newIdStatusChanged();
|
||||||
|
});
|
||||||
|
connect(innerJob, &Quotient::BaseJob::failure, this, [innerJob, this]() {
|
||||||
|
if (innerJob->jsonData()[QLatin1String("errcode")] == QLatin1String("M_FORBIDDEN")) {
|
||||||
|
m_newIdStatus = AuthFailure;
|
||||||
|
Q_EMIT newIdStatusChanged();
|
||||||
|
} else if (innerJob->jsonData()[QLatin1String("errcode")] == QLatin1String("M_THREEPID_AUTH_FAILED")) {
|
||||||
|
m_newIdStatus = VerificationFailure;
|
||||||
|
Q_EMIT newIdStatusChanged();
|
||||||
|
} else {
|
||||||
|
m_newIdStatus = Other;
|
||||||
|
Q_EMIT newIdStatusChanged();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ThreePIdAddHelper::remove3PId(const QString &threePId, const QString &type)
|
||||||
|
{
|
||||||
|
const auto job = m_connection->callApi<Quotient::Delete3pidFromAccountJob>(type, threePId);
|
||||||
|
connect(job, &Quotient::BaseJob::success, this, [this]() {
|
||||||
|
m_connection->threePIdModel()->refreshModel();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ThreePIdAddHelper::back()
|
||||||
|
{
|
||||||
|
switch (m_newIdStatus) {
|
||||||
|
case Verification:
|
||||||
|
case Authentication:
|
||||||
|
case AuthFailure:
|
||||||
|
case VerificationFailure:
|
||||||
|
m_newIdStatus = Ready;
|
||||||
|
Q_EMIT newIdStatusChanged();
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
133
src/threepidaddhelper.h
Normal file
133
src/threepidaddhelper.h
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2024 James Graham <james.h.graham@protonmail.com>
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QQmlEngine>
|
||||||
|
|
||||||
|
#include <Quotient/jobs/basejob.h>
|
||||||
|
|
||||||
|
class NeoChatConnection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class ThreePIdAddHelper
|
||||||
|
*
|
||||||
|
* This class is designed to help the process of adding a new 3PID to the account.
|
||||||
|
* It will manage the various stages of verification and authentication.
|
||||||
|
*/
|
||||||
|
class ThreePIdAddHelper : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
QML_ELEMENT
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The connection to add a 3PID to.
|
||||||
|
*/
|
||||||
|
Q_PROPERTY(NeoChatConnection *connection READ connection WRITE setConnection NOTIFY connectionChanged)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The type of 3PID being added.
|
||||||
|
*
|
||||||
|
* email or msisdn.
|
||||||
|
*/
|
||||||
|
Q_PROPERTY(QString medium READ medium WRITE setMedium NOTIFY mediumChanged)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The 3PID to add.
|
||||||
|
*
|
||||||
|
* Email or phone number depending on type.
|
||||||
|
*/
|
||||||
|
Q_PROPERTY(QString newId READ newId WRITE setNewId NOTIFY newIdChanged)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The country code if a phone number is being added.
|
||||||
|
*/
|
||||||
|
Q_PROPERTY(QString newCountryCode READ newCountryCode WRITE setNewCountryCode NOTIFY newCountryCodeChanged)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The current status.
|
||||||
|
*
|
||||||
|
* @sa ThreePIdStatus
|
||||||
|
*/
|
||||||
|
Q_PROPERTY(ThreePIdStatus newIdStatus READ newIdStatus NOTIFY newIdStatusChanged)
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Defines the current status for adding a 3PID.
|
||||||
|
*/
|
||||||
|
enum ThreePIdStatus {
|
||||||
|
Ready, /**< The process is ready to start. I.e. there is no ongoing attempt to set a new 3PID. */
|
||||||
|
Verification, /**< The request to verify the new 3PID has been sent. */
|
||||||
|
Authentication, /**< The user needs to authenticate. */
|
||||||
|
Success, /**< The 3PID has been successfully added. */
|
||||||
|
Invalid, /**< The 3PID can't be used. */
|
||||||
|
AuthFailure, /**< The authentication was wrong. */
|
||||||
|
VerificationFailure, /**< The verification has not been completed. */
|
||||||
|
Other, /**< An unknown problem occurred. */
|
||||||
|
};
|
||||||
|
Q_ENUM(ThreePIdStatus)
|
||||||
|
|
||||||
|
explicit ThreePIdAddHelper(QObject *parent = nullptr);
|
||||||
|
|
||||||
|
[[nodiscard]] NeoChatConnection *connection() const;
|
||||||
|
void setConnection(NeoChatConnection *connection);
|
||||||
|
|
||||||
|
[[nodiscard]] QString medium() const;
|
||||||
|
void setMedium(const QString &medium);
|
||||||
|
|
||||||
|
[[nodiscard]] QString newId() const;
|
||||||
|
void setNewId(const QString &newEmail);
|
||||||
|
|
||||||
|
[[nodiscard]] QString newCountryCode() const;
|
||||||
|
void setNewCountryCode(const QString &newCountryCode);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Start the process to add the new 3PID.
|
||||||
|
*
|
||||||
|
* This will start the process of verifying the 3PID credentials that have been given.
|
||||||
|
*/
|
||||||
|
Q_INVOKABLE void initiateNewIdAdd();
|
||||||
|
|
||||||
|
[[nodiscard]] ThreePIdStatus newIdStatus() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Finalize the process of adding the new 3PID.
|
||||||
|
*
|
||||||
|
* @param password the user's password to authenticate the addition.
|
||||||
|
*/
|
||||||
|
Q_INVOKABLE void finalizeNewIdAdd(const QString &password);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Remove the given 3PID.
|
||||||
|
*/
|
||||||
|
Q_INVOKABLE void remove3PId(const QString &threePId, const QString &type);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Go back a step in the process.
|
||||||
|
*/
|
||||||
|
Q_INVOKABLE void back();
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
void connectionChanged();
|
||||||
|
void mediumChanged();
|
||||||
|
void newIdChanged();
|
||||||
|
void newCountryCodeChanged();
|
||||||
|
void newEmailSessionStartedChanged();
|
||||||
|
void newIdStatusChanged();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QPointer<NeoChatConnection> m_connection;
|
||||||
|
QString m_medium = QString();
|
||||||
|
|
||||||
|
ThreePIdStatus m_newIdStatus = Ready;
|
||||||
|
QString m_newId = QString();
|
||||||
|
QString m_newCountryCode = QString();
|
||||||
|
QString m_newIdSecret = QString();
|
||||||
|
QString m_newIdSid = QString();
|
||||||
|
|
||||||
|
void emailTokenJob();
|
||||||
|
void msisdnTokenJob();
|
||||||
|
|
||||||
|
void tokenJobFinished(Quotient::BaseJob *job);
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user