@@ -185,6 +185,8 @@ add_library(neochat STATIC
|
||||
enums/powerlevel.h
|
||||
models/permissionsmodel.cpp
|
||||
models/permissionsmodel.h
|
||||
threepidbindhelper.cpp
|
||||
threepidbindhelper.h
|
||||
)
|
||||
|
||||
set_source_files_properties(qml/OsmLocationPlugin.qml PROPERTIES
|
||||
|
||||
@@ -33,43 +33,6 @@ void IdentityServerHelper::setConnection(NeoChatConnection *connection)
|
||||
|
||||
m_connection = connection;
|
||||
Q_EMIT connectionChanged();
|
||||
Q_EMIT currentServerChanged();
|
||||
|
||||
connect(m_connection, &NeoChatConnection::accountDataChanged, this, [this](const QString &type) {
|
||||
if (type == QLatin1String("m.identity_server")) {
|
||||
Q_EMIT currentServerChanged();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
QString IdentityServerHelper::currentServer() const
|
||||
{
|
||||
if (m_connection == nullptr) {
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!m_connection->hasAccountData(QLatin1String("m.identity_server"))) {
|
||||
return i18nc("@info", "No identity server configured");
|
||||
}
|
||||
|
||||
const auto url = m_connection->accountData(QLatin1String("m.identity_server"))->contentPart<QUrl>(QLatin1String("base_url"));
|
||||
if (!url.isEmpty()) {
|
||||
return url.toString();
|
||||
}
|
||||
return i18nc("@info", "No identity server configured");
|
||||
}
|
||||
|
||||
bool IdentityServerHelper::hasCurrentServer() const
|
||||
{
|
||||
if (m_connection == nullptr && !m_connection->hasAccountData(QLatin1String("m.identity_server"))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto url = m_connection->accountData(QLatin1String("m.identity_server"))->contentPart<QUrl>(QLatin1String("base_url"));
|
||||
if (!url.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
QString IdentityServerHelper::url() const
|
||||
@@ -100,7 +63,7 @@ void IdentityServerHelper::checkUrl()
|
||||
m_idServerCheckRequest.clear();
|
||||
}
|
||||
|
||||
if (m_url == currentServer()) {
|
||||
if (m_url == m_connection->identityServer().toString()) {
|
||||
m_status = Match;
|
||||
Q_EMIT statusChanged();
|
||||
return;
|
||||
@@ -134,7 +97,7 @@ void IdentityServerHelper::checkUrl()
|
||||
|
||||
void IdentityServerHelper::setIdentityServer()
|
||||
{
|
||||
if (m_url == currentServer()) {
|
||||
if (m_url == m_connection->identityServer().toString()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -145,7 +108,7 @@ void IdentityServerHelper::setIdentityServer()
|
||||
|
||||
void IdentityServerHelper::clearIdentityServer()
|
||||
{
|
||||
if (currentServer().isEmpty()) {
|
||||
if (m_connection->identityServer().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
m_connection->setAccountData(QLatin1String("m.identity_server"), {{QLatin1String("base_url"), QString()}});
|
||||
|
||||
@@ -26,16 +26,6 @@ class IdentityServerHelper : public QObject
|
||||
*/
|
||||
Q_PROPERTY(NeoChatConnection *connection READ connection WRITE setConnection NOTIFY connectionChanged)
|
||||
|
||||
/**
|
||||
* @brief The current identity server.
|
||||
*/
|
||||
Q_PROPERTY(QString currentServer READ currentServer NOTIFY currentServerChanged)
|
||||
|
||||
/**
|
||||
* @brief Whether an identity server is currently configured.
|
||||
*/
|
||||
Q_PROPERTY(bool hasCurrentServer READ hasCurrentServer NOTIFY currentServerChanged)
|
||||
|
||||
/**
|
||||
* @brief The URL for the desired server.
|
||||
*/
|
||||
@@ -64,10 +54,6 @@ public:
|
||||
[[nodiscard]] NeoChatConnection *connection() const;
|
||||
void setConnection(NeoChatConnection *connection);
|
||||
|
||||
[[nodiscard]] QString currentServer() const;
|
||||
|
||||
[[nodiscard]] bool hasCurrentServer() const;
|
||||
|
||||
[[nodiscard]] QString url() const;
|
||||
void setUrl(const QString &url);
|
||||
|
||||
@@ -87,7 +73,6 @@ public:
|
||||
|
||||
Q_SIGNALS:
|
||||
void connectionChanged();
|
||||
void currentServerChanged();
|
||||
void urlChanged();
|
||||
void statusChanged();
|
||||
|
||||
|
||||
@@ -60,6 +60,9 @@ void NeoChatConnection::connectSignals()
|
||||
if (type == QLatin1String("org.kde.neochat.account_label")) {
|
||||
Q_EMIT labelChanged();
|
||||
}
|
||||
if (type == QLatin1String("m.identity_server")) {
|
||||
Q_EMIT identityServerChanged();
|
||||
}
|
||||
});
|
||||
connect(this, &NeoChatConnection::syncDone, this, [this] {
|
||||
setIsOnline(true);
|
||||
@@ -256,6 +259,41 @@ ThreePIdModel *NeoChatConnection::threePIdModel() const
|
||||
return m_threePIdModel;
|
||||
}
|
||||
|
||||
bool NeoChatConnection::hasIdentityServer() const
|
||||
{
|
||||
if (!hasAccountData(QLatin1String("m.identity_server"))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto url = accountData(QLatin1String("m.identity_server"))->contentPart<QUrl>(QLatin1String("base_url"));
|
||||
if (!url.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
QUrl NeoChatConnection::identityServer() const
|
||||
{
|
||||
if (!hasAccountData(QLatin1String("m.identity_server"))) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const auto url = accountData(QLatin1String("m.identity_server"))->contentPart<QUrl>(QLatin1String("base_url"));
|
||||
if (!url.isEmpty()) {
|
||||
return url;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
QString NeoChatConnection::identityServerUIString() const
|
||||
{
|
||||
if (!hasIdentityServer()) {
|
||||
return i18nc("@info", "No identity server configured");
|
||||
}
|
||||
|
||||
return identityServer().toString();
|
||||
}
|
||||
|
||||
void NeoChatConnection::createRoom(const QString &name, const QString &topic, const QString &parent, bool setChildParent)
|
||||
{
|
||||
QList<CreateRoomJob::StateEvent> initialStateEvents;
|
||||
|
||||
@@ -36,6 +36,19 @@ class NeoChatConnection : public Quotient::Connection
|
||||
*/
|
||||
Q_PROPERTY(ThreePIdModel *threePIdModel READ threePIdModel CONSTANT)
|
||||
|
||||
/**
|
||||
* @brief Whether an identity server is configured.
|
||||
*/
|
||||
Q_PROPERTY(bool hasIdentityServer READ hasIdentityServer NOTIFY identityServerChanged)
|
||||
|
||||
/**
|
||||
* @brief The identity server URL as a string for showing in a UI.
|
||||
*
|
||||
* Will return the string "No identity server configured" if no identity
|
||||
* server configured. Otherwise it returns the URL as a string.
|
||||
*/
|
||||
Q_PROPERTY(QString identityServer READ identityServerUIString NOTIFY identityServerChanged)
|
||||
|
||||
/**
|
||||
* @brief The total number of notifications for all direct chats.
|
||||
*/
|
||||
@@ -105,6 +118,17 @@ public:
|
||||
|
||||
ThreePIdModel *threePIdModel() const;
|
||||
|
||||
bool hasIdentityServer() const;
|
||||
|
||||
/**
|
||||
* @brief The identity server URL.
|
||||
*
|
||||
* Empty if no identity server configured.
|
||||
*/
|
||||
QUrl identityServer() const;
|
||||
|
||||
QString identityServerUIString() const;
|
||||
|
||||
/**
|
||||
* @brief Create new room for a group chat.
|
||||
*/
|
||||
@@ -162,6 +186,7 @@ public:
|
||||
|
||||
Q_SIGNALS:
|
||||
void labelChanged();
|
||||
void identityServerChanged();
|
||||
void directChatNotificationsChanged();
|
||||
void directChatsHaveHighlightNotificationsChanged();
|
||||
void homeNotificationsChanged();
|
||||
|
||||
@@ -17,7 +17,7 @@ FormCard.AbstractFormDelegate {
|
||||
|
||||
property bool editServerUrl: false
|
||||
|
||||
text: identityServerHelper.currentServer
|
||||
text: connection.identityServer
|
||||
|
||||
onClicked: editIdServerButton.toggle()
|
||||
|
||||
@@ -114,7 +114,7 @@ FormCard.AbstractFormDelegate {
|
||||
}
|
||||
QQC2.ToolButton {
|
||||
id: removeIdServerButton
|
||||
visible: identityServerHelper.hasCurrentServer
|
||||
visible: root.connection.hasIdentityServer
|
||||
display: QQC2.AbstractButton.IconOnly
|
||||
text: i18nc("@action:button", "Remove identity server")
|
||||
icon.name: "edit-delete-remove"
|
||||
|
||||
@@ -38,22 +38,72 @@ ColumnLayout {
|
||||
required property string address
|
||||
required property string medium
|
||||
|
||||
contentItem: RowLayout {
|
||||
QQC2.Label {
|
||||
contentItem: ColumnLayout {
|
||||
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 {
|
||||
visible: threePIdBindHelper.bindStatus === ThreePIdBindHelper.Ready && root.connection.hasIdentityServer
|
||||
text: i18nc("@action:button", "Share")
|
||||
icon.name: "send-to-symbolic"
|
||||
onClicked: threePIdBindHelper.bindStatus === ThreePIdBindHelper.Verification ? threePIdBindHelper.finalizeNewIdBind() : threePIdBindHelper.initiateNewIdBind()
|
||||
}
|
||||
QQC2.ToolButton {
|
||||
text: i18nc("@action:button", "Remove")
|
||||
icon.name: "edit-delete-remove"
|
||||
onClicked: threePIdAddHelper.remove3PId(threePIdDelegate.address, threePIdDelegate.medium)
|
||||
}
|
||||
}
|
||||
Kirigami.InlineMessage {
|
||||
id: errorHandler
|
||||
visible: threePIdBindHelper.bindStatusString.length > 0
|
||||
Layout.topMargin: visible ? Kirigami.Units.smallSpacing : 0
|
||||
Layout.fillWidth: true
|
||||
text: threePIdDelegate.address
|
||||
textFormat: Text.PlainText
|
||||
elide: Text.ElideRight
|
||||
wrapMode: Text.Wrap
|
||||
maximumLineCount: 2
|
||||
color: Kirigami.Theme.textColor
|
||||
text: threePIdBindHelper.bindStatusString
|
||||
type: threePIdBindHelper.statusType
|
||||
}
|
||||
QQC2.ToolButton {
|
||||
text: i18nc("@action:button", "Remove")
|
||||
icon.name: "edit-delete-remove"
|
||||
onClicked: threePIdAddHelper.remove3PId(threePIdDelegate.address, threePIdDelegate.medium)
|
||||
RowLayout {
|
||||
visible: threePIdBindHelper.bindStatus !== ThreePIdBindHelper.Ready
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
QQC2.ToolButton {
|
||||
text: i18nc("@action:button", "Complete")
|
||||
icon.name: "answer-correct"
|
||||
onClicked: threePIdBindHelper.finalizeNewIdBind()
|
||||
}
|
||||
QQC2.ToolButton {
|
||||
text: i18nc("@action:button", "Cancel")
|
||||
icon.name: "edit-delete-remove"
|
||||
onClicked: threePIdBindHelper.cancel()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ThreePIdBindHelper {
|
||||
id: threePIdBindHelper
|
||||
|
||||
readonly property int statusType: switch(bindStatus) {
|
||||
case ThreePIdBindHelper.Invalid:
|
||||
case ThreePIdBindHelper.AuthFailure:
|
||||
return Kirigami.MessageType.Error;
|
||||
case ThreePIdBindHelper.VerificationFailure:
|
||||
return Kirigami.MessageType.Warning;
|
||||
default:
|
||||
return Kirigami.MessageType.Information;
|
||||
}
|
||||
|
||||
connection: root.connection
|
||||
newId: threePIdDelegate.address
|
||||
medium: threePIdDelegate.medium
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -183,6 +183,14 @@ void ThreePIdAddHelper::remove3PId(const QString &threePId, const QString &type)
|
||||
});
|
||||
}
|
||||
|
||||
void ThreePIdAddHelper::unbind3PId(const QString &threePId, const QString &type)
|
||||
{
|
||||
const auto job = m_connection->callApi<Quotient::Unbind3pidFromAccountJob>(type, threePId);
|
||||
connect(job, &Quotient::BaseJob::success, this, [this]() {
|
||||
m_connection->threePIdModel()->refreshModel();
|
||||
});
|
||||
}
|
||||
|
||||
void ThreePIdAddHelper::back()
|
||||
{
|
||||
switch (m_newIdStatus) {
|
||||
|
||||
@@ -103,6 +103,11 @@ public:
|
||||
*/
|
||||
Q_INVOKABLE void remove3PId(const QString &threePId, const QString &type);
|
||||
|
||||
/**
|
||||
* @brief Remove the given 3PID.
|
||||
*/
|
||||
Q_INVOKABLE void unbind3PId(const QString &threePId, const QString &type);
|
||||
|
||||
/**
|
||||
* @brief Go back a step in the process.
|
||||
*/
|
||||
|
||||
230
src/threepidbindhelper.cpp
Normal file
230
src/threepidbindhelper.cpp
Normal file
@@ -0,0 +1,230 @@
|
||||
// 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 "threepidbindhelper.h"
|
||||
|
||||
#include <QNetworkReply>
|
||||
|
||||
#include <Quotient/converters.h>
|
||||
#include <Quotient/csapi/definitions/auth_data.h>
|
||||
#include <Quotient/csapi/definitions/request_msisdn_validation.h>
|
||||
#include <Quotient/csapi/openid.h>
|
||||
#include <Quotient/jobs/basejob.h>
|
||||
#include <Quotient/networkaccessmanager.h>
|
||||
|
||||
#include <KLocalizedString>
|
||||
|
||||
#include "neochatconnection.h"
|
||||
|
||||
ThreePIdBindHelper::ThreePIdBindHelper(QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
}
|
||||
|
||||
NeoChatConnection *ThreePIdBindHelper::connection() const
|
||||
{
|
||||
return m_connection;
|
||||
}
|
||||
|
||||
void ThreePIdBindHelper::setConnection(NeoChatConnection *connection)
|
||||
{
|
||||
if (m_connection == connection) {
|
||||
return;
|
||||
}
|
||||
m_connection = connection;
|
||||
Q_EMIT connectionChanged();
|
||||
}
|
||||
|
||||
QString ThreePIdBindHelper::medium() const
|
||||
{
|
||||
return m_medium;
|
||||
}
|
||||
|
||||
void ThreePIdBindHelper::setMedium(const QString &medium)
|
||||
{
|
||||
if (m_medium == medium) {
|
||||
return;
|
||||
}
|
||||
m_medium = medium;
|
||||
Q_EMIT mediumChanged();
|
||||
}
|
||||
|
||||
QString ThreePIdBindHelper::newId() const
|
||||
{
|
||||
return m_newId;
|
||||
}
|
||||
|
||||
void ThreePIdBindHelper::setNewId(const QString &newId)
|
||||
{
|
||||
if (newId == m_newId) {
|
||||
return;
|
||||
}
|
||||
m_newId = newId;
|
||||
Q_EMIT newIdChanged();
|
||||
|
||||
m_newIdSecret.clear();
|
||||
m_newIdSid.clear();
|
||||
m_identityServerToken.clear();
|
||||
m_bindStatus = Ready;
|
||||
Q_EMIT bindStatusChanged();
|
||||
}
|
||||
|
||||
QString ThreePIdBindHelper::newCountryCode() const
|
||||
{
|
||||
return m_newCountryCode;
|
||||
}
|
||||
|
||||
void ThreePIdBindHelper::setNewCountryCode(const QString &newCountryCode)
|
||||
{
|
||||
if (newCountryCode == m_newCountryCode) {
|
||||
return;
|
||||
}
|
||||
m_newCountryCode = newCountryCode;
|
||||
Q_EMIT newCountryCodeChanged();
|
||||
|
||||
m_newIdSecret.clear();
|
||||
m_newIdSid.clear();
|
||||
m_identityServerToken.clear();
|
||||
m_bindStatus = Ready;
|
||||
Q_EMIT bindStatusChanged();
|
||||
}
|
||||
|
||||
void ThreePIdBindHelper::initiateNewIdBind()
|
||||
{
|
||||
if (m_newId.isEmpty() || m_connection == nullptr || !m_connection->hasIdentityServer()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto openIdJob = m_connection->callApi<Quotient::RequestOpenIdTokenJob>(m_connection->userId());
|
||||
connect(openIdJob, &Quotient::BaseJob::success, this, [this, openIdJob]() {
|
||||
const auto requestUrl = QUrl(m_connection->identityServer().toString() + QStringLiteral("/_matrix/identity/v2/account/register"));
|
||||
if (!(requestUrl.scheme() == QStringLiteral("https") || requestUrl.scheme() == QStringLiteral("http"))) {
|
||||
m_bindStatus = AuthFailure;
|
||||
Q_EMIT bindStatusChanged();
|
||||
return;
|
||||
}
|
||||
|
||||
QNetworkRequest request(requestUrl);
|
||||
auto newRequest = Quotient::NetworkAccessManager::instance()->post(request, QJsonDocument(openIdJob->jsonData()).toJson());
|
||||
connect(newRequest, &QNetworkReply::finished, this, [this, newRequest]() {
|
||||
QJsonObject replyJson = parseJson(newRequest->readAll());
|
||||
m_identityServerToken = replyJson[QLatin1String("token")].toString();
|
||||
|
||||
const auto requestUrl = QUrl(m_connection->identityServer().toString() + QStringLiteral("/_matrix/identity/v2/validate/email/requestToken"));
|
||||
if (!(requestUrl.scheme() == QStringLiteral("https") || requestUrl.scheme() == QStringLiteral("http"))) {
|
||||
m_bindStatus = AuthFailure;
|
||||
Q_EMIT bindStatusChanged();
|
||||
return;
|
||||
}
|
||||
|
||||
QNetworkRequest validationRequest(requestUrl);
|
||||
validationRequest.setRawHeader("Authorization", "Bearer " + m_identityServerToken.toLatin1());
|
||||
|
||||
auto tokenRequest = Quotient::NetworkAccessManager::instance()->post(validationRequest, validationRequestData());
|
||||
connect(tokenRequest, &QNetworkReply::finished, this, [this, tokenRequest]() {
|
||||
tokenRequestFinished(tokenRequest);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
QByteArray ThreePIdBindHelper::validationRequestData()
|
||||
{
|
||||
m_newIdSecret = QString::fromLatin1(QUuid::createUuid().toString().toLatin1().toBase64());
|
||||
QJsonObject requestData = {
|
||||
{QLatin1String("client_secret"), m_newIdSecret},
|
||||
{QLatin1String("send_attempt"), 0},
|
||||
};
|
||||
|
||||
if (m_medium == QLatin1String("email")) {
|
||||
requestData[QLatin1String("email")] = m_newId;
|
||||
} else {
|
||||
requestData[QLatin1String("phone_number")] = m_newId;
|
||||
requestData[QLatin1String("country")] = m_newCountryCode;
|
||||
}
|
||||
|
||||
return QJsonDocument(requestData).toJson();
|
||||
}
|
||||
|
||||
void ThreePIdBindHelper::tokenRequestFinished(QNetworkReply *reply)
|
||||
{
|
||||
if (reply->error() != QNetworkReply::NoError) {
|
||||
return;
|
||||
}
|
||||
|
||||
QJsonObject replyJson = parseJson(reply->readAll());
|
||||
m_newIdSid = replyJson[QLatin1String("sid")].toString();
|
||||
|
||||
if (m_newIdSid.isEmpty()) {
|
||||
m_bindStatus = Invalid;
|
||||
Q_EMIT bindStatusChanged();
|
||||
} else {
|
||||
m_bindStatus = Verification;
|
||||
Q_EMIT bindStatusChanged();
|
||||
}
|
||||
}
|
||||
|
||||
ThreePIdBindHelper::ThreePIdStatus ThreePIdBindHelper::bindStatus() const
|
||||
{
|
||||
return m_bindStatus;
|
||||
}
|
||||
|
||||
QString ThreePIdBindHelper::bindStatusString() const
|
||||
{
|
||||
switch (m_bindStatus) {
|
||||
case Verification:
|
||||
return i18n("%1. Please follow the instructions there and then click the button above",
|
||||
m_medium == QStringLiteral("email") ? i18n("We've sent you an email") : i18n("We've sent you a text message"));
|
||||
case Invalid:
|
||||
return m_medium == QStringLiteral("email") ? i18n("The entered email is not valid") : i18n("The entered phone number is not valid");
|
||||
case VerificationFailure:
|
||||
return m_medium == QStringLiteral("email")
|
||||
? i18n("The email has not been verified. Please go to the email and follow the instructions there and then click the button above")
|
||||
: i18n("The phone number has not been verified. Please go to the text message and follow the instructions there and then click the button above");
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
void ThreePIdBindHelper::finalizeNewIdBind()
|
||||
{
|
||||
const auto job = m_connection->callApi<Quotient::Bind3PIDJob>(m_newIdSecret, m_connection->identityServer().host(), m_identityServerToken, m_newIdSid);
|
||||
connect(job, &Quotient::BaseJob::success, this, [this] {
|
||||
m_bindStatus = Success;
|
||||
Q_EMIT bindStatusChanged();
|
||||
});
|
||||
connect(job, &Quotient::BaseJob::failure, this, [this, job]() {
|
||||
if (job->jsonData()[QLatin1String("errcode")] == QLatin1String("M_SESSION_NOT_VALIDATED")) {
|
||||
m_bindStatus = VerificationFailure;
|
||||
Q_EMIT bindStatusChanged();
|
||||
} else {
|
||||
m_bindStatus = Other;
|
||||
Q_EMIT bindStatusChanged();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void ThreePIdBindHelper::unbind3PId(const QString &threePId, const QString &type)
|
||||
{
|
||||
const auto job = m_connection->callApi<Quotient::Unbind3pidFromAccountJob>(type, threePId);
|
||||
connect(job, &Quotient::BaseJob::success, this, [this]() {
|
||||
m_connection->threePIdModel()->refreshModel();
|
||||
});
|
||||
}
|
||||
|
||||
void ThreePIdBindHelper::cancel()
|
||||
{
|
||||
m_newIdSecret.clear();
|
||||
m_newIdSid.clear();
|
||||
m_identityServerToken.clear();
|
||||
m_bindStatus = Ready;
|
||||
Q_EMIT bindStatusChanged();
|
||||
}
|
||||
|
||||
QJsonObject ThreePIdBindHelper::parseJson(const QByteArray &json)
|
||||
{
|
||||
const auto document = QJsonDocument::fromJson(json);
|
||||
return document.object();
|
||||
}
|
||||
|
||||
#include "moc_threepidbindhelper.cpp"
|
||||
146
src/threepidbindhelper.h
Normal file
146
src/threepidbindhelper.h
Normal file
@@ -0,0 +1,146 @@
|
||||
// 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 ThreePIdBindHelper
|
||||
*
|
||||
* This class is designed to help the process of bindind a 3PID to an identity server.
|
||||
* It will manage the various stages of verification and authentication.
|
||||
*/
|
||||
class ThreePIdBindHelper : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
QML_ELEMENT
|
||||
|
||||
/**
|
||||
* @brief The connection to bind a 3PID for.
|
||||
*/
|
||||
Q_PROPERTY(NeoChatConnection *connection READ connection WRITE setConnection NOTIFY connectionChanged)
|
||||
|
||||
/**
|
||||
* @brief The type of 3PID being bound.
|
||||
*
|
||||
* email or msisdn.
|
||||
*/
|
||||
Q_PROPERTY(QString medium READ medium WRITE setMedium NOTIFY mediumChanged)
|
||||
|
||||
/**
|
||||
* @brief The 3PID to bind.
|
||||
*
|
||||
* 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 bound.
|
||||
*/
|
||||
Q_PROPERTY(QString newCountryCode READ newCountryCode WRITE setNewCountryCode NOTIFY newCountryCodeChanged)
|
||||
|
||||
/**
|
||||
* @brief The current status.
|
||||
*
|
||||
* @sa ThreePIdStatus
|
||||
*/
|
||||
Q_PROPERTY(ThreePIdStatus bindStatus READ bindStatus NOTIFY bindStatusChanged)
|
||||
|
||||
/**
|
||||
* @brief The current status as a string.
|
||||
*
|
||||
* @sa ThreePIdStatus
|
||||
*/
|
||||
Q_PROPERTY(QString bindStatusString READ bindStatusString NOTIFY bindStatusChanged)
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Defines the current status for binding 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 ThreePIdBindHelper(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 bind the new 3PID.
|
||||
*
|
||||
* This will start the process of verifying the 3PID credentials that have been given.
|
||||
* Will fail if no identity server is configured.
|
||||
*/
|
||||
Q_INVOKABLE void initiateNewIdBind();
|
||||
|
||||
[[nodiscard]] ThreePIdStatus bindStatus() const;
|
||||
|
||||
[[nodiscard]] QString bindStatusString() const;
|
||||
|
||||
/**
|
||||
* @brief Finalize the process of binding the new 3PID.
|
||||
*
|
||||
* Will fail if the user hasn't completed the verification with the identity
|
||||
* server.
|
||||
*/
|
||||
Q_INVOKABLE void finalizeNewIdBind();
|
||||
|
||||
/**
|
||||
* @brief Unbind the given 3PID.
|
||||
*/
|
||||
Q_INVOKABLE void unbind3PId(const QString &threePId, const QString &type);
|
||||
|
||||
/**
|
||||
* @brief Cancel the process.
|
||||
*/
|
||||
Q_INVOKABLE void cancel();
|
||||
|
||||
Q_SIGNALS:
|
||||
void connectionChanged();
|
||||
void mediumChanged();
|
||||
void newIdChanged();
|
||||
void newCountryCodeChanged();
|
||||
void newEmailSessionStartedChanged();
|
||||
void bindStatusChanged();
|
||||
|
||||
private:
|
||||
QPointer<NeoChatConnection> m_connection;
|
||||
QString m_medium = QString();
|
||||
|
||||
ThreePIdStatus m_bindStatus = Ready;
|
||||
QString m_newId = QString();
|
||||
QString m_newCountryCode = QString();
|
||||
QString m_newIdSecret = QString();
|
||||
QString m_newIdSid = QString();
|
||||
QString m_identityServerToken = QString();
|
||||
|
||||
QByteArray validationRequestData();
|
||||
|
||||
void tokenRequestFinished(QNetworkReply *reply);
|
||||
|
||||
static QJsonObject parseJson(const QByteArray &json);
|
||||
};
|
||||
Reference in New Issue
Block a user