@@ -179,6 +179,8 @@ add_library(neochat STATIC
|
||||
threepidaddhelper.h
|
||||
jobs/neochatadd3pidjob.cpp
|
||||
jobs/neochatadd3pidjob.h
|
||||
identityserverhelper.cpp
|
||||
identityserverhelper.h
|
||||
)
|
||||
|
||||
set_source_files_properties(qml/OsmLocationPlugin.qml PROPERTIES
|
||||
|
||||
154
src/identityserverhelper.cpp
Normal file
154
src/identityserverhelper.cpp
Normal file
@@ -0,0 +1,154 @@
|
||||
// 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 "identityserverhelper.h"
|
||||
|
||||
#include <QNetworkReply>
|
||||
|
||||
#include <KLocalizedString>
|
||||
|
||||
#include <Quotient/networkaccessmanager.h>
|
||||
|
||||
#include "neochatconnection.h"
|
||||
|
||||
IdentityServerHelper::IdentityServerHelper(QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
}
|
||||
|
||||
NeoChatConnection *IdentityServerHelper::connection() const
|
||||
{
|
||||
return m_connection;
|
||||
}
|
||||
|
||||
void IdentityServerHelper::setConnection(NeoChatConnection *connection)
|
||||
{
|
||||
if (m_connection == connection) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_connection != nullptr) {
|
||||
m_connection->disconnect(this);
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
return m_url;
|
||||
}
|
||||
|
||||
void IdentityServerHelper::setUrl(const QString &url)
|
||||
{
|
||||
if (url == m_url) {
|
||||
return;
|
||||
}
|
||||
m_url = url;
|
||||
Q_EMIT urlChanged();
|
||||
|
||||
checkUrl();
|
||||
}
|
||||
|
||||
IdentityServerHelper::IdServerStatus IdentityServerHelper::status() const
|
||||
{
|
||||
return m_status;
|
||||
}
|
||||
|
||||
void IdentityServerHelper::checkUrl()
|
||||
{
|
||||
if (m_idServerCheckRequest != nullptr) {
|
||||
m_idServerCheckRequest->abort();
|
||||
m_idServerCheckRequest.clear();
|
||||
}
|
||||
|
||||
if (m_url == currentServer()) {
|
||||
m_status = Match;
|
||||
Q_EMIT statusChanged();
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_url.isEmpty()) {
|
||||
m_status = Valid;
|
||||
Q_EMIT statusChanged();
|
||||
return;
|
||||
}
|
||||
|
||||
const auto requestUrl = QUrl(m_url + QStringLiteral("/_matrix/identity/v2"));
|
||||
if (!(requestUrl.scheme() == QStringLiteral("https") || requestUrl.scheme() == QStringLiteral("http"))) {
|
||||
m_status = Invalid;
|
||||
Q_EMIT statusChanged();
|
||||
return;
|
||||
}
|
||||
|
||||
QNetworkRequest request(requestUrl);
|
||||
m_idServerCheckRequest = Quotient::NetworkAccessManager::instance()->get(request);
|
||||
connect(m_idServerCheckRequest, &QNetworkReply::finished, this, [this]() {
|
||||
if (m_idServerCheckRequest->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() == 200) {
|
||||
m_status = Valid;
|
||||
Q_EMIT statusChanged();
|
||||
} else {
|
||||
m_status = Invalid;
|
||||
Q_EMIT statusChanged();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void IdentityServerHelper::setIdentityServer()
|
||||
{
|
||||
if (m_url == currentServer()) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_connection->setAccountData(QLatin1String("m.identity_server"), {{QLatin1String("base_url"), m_url}});
|
||||
m_status = Ready;
|
||||
Q_EMIT statusChanged();
|
||||
}
|
||||
|
||||
void IdentityServerHelper::clearIdentityServer()
|
||||
{
|
||||
if (currentServer().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
m_connection->setAccountData(QLatin1String("m.identity_server"), {{QLatin1String("base_url"), QString()}});
|
||||
m_status = Ready;
|
||||
Q_EMIT statusChanged();
|
||||
}
|
||||
103
src/identityserverhelper.h
Normal file
103
src/identityserverhelper.h
Normal file
@@ -0,0 +1,103 @@
|
||||
// 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 IdentityServerHelper
|
||||
*
|
||||
* This class is designed to help the process of setting an identity server for the account.
|
||||
* It will manage the various stages of verification and authentication.
|
||||
*/
|
||||
class IdentityServerHelper : 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 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.
|
||||
*/
|
||||
Q_PROPERTY(QString url READ url WRITE setUrl NOTIFY urlChanged)
|
||||
|
||||
/**
|
||||
* @brief The current status.
|
||||
*/
|
||||
Q_PROPERTY(IdServerStatus status READ status NOTIFY statusChanged)
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief The current status for adding an identity server
|
||||
*/
|
||||
enum IdServerStatus {
|
||||
Ready, /**< The process is ready to start. I.e. there is no ongoing attempt to set a new server. */
|
||||
Valid, /**< The server URL is valid. */
|
||||
Invalid, /**< The server URL is invalid. */
|
||||
Match, /**< The server URL is the one that is already configured. */
|
||||
Other, /**< An unknown problem occurred. */
|
||||
};
|
||||
Q_ENUM(IdServerStatus)
|
||||
|
||||
explicit IdentityServerHelper(QObject *parent = nullptr);
|
||||
|
||||
[[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);
|
||||
|
||||
[[nodiscard]] IdServerStatus status() const;
|
||||
|
||||
/**
|
||||
* @brief Set the current URL as the user's identity server.
|
||||
*
|
||||
* Will do nothing if the URL isn't a valid identity server.
|
||||
*/
|
||||
Q_INVOKABLE void setIdentityServer();
|
||||
|
||||
/**
|
||||
* @brief Clear the user's identity server.
|
||||
*/
|
||||
Q_INVOKABLE void clearIdentityServer();
|
||||
|
||||
Q_SIGNALS:
|
||||
void connectionChanged();
|
||||
void currentServerChanged();
|
||||
void urlChanged();
|
||||
void statusChanged();
|
||||
|
||||
private:
|
||||
QPointer<NeoChatConnection> m_connection;
|
||||
|
||||
IdServerStatus m_status = Ready;
|
||||
QString m_url;
|
||||
|
||||
QPointer<QNetworkReply> m_idServerCheckRequest;
|
||||
|
||||
void checkUrl();
|
||||
};
|
||||
@@ -207,6 +207,15 @@ FormCard.FormCardPage {
|
||||
title: i18n("Phone Numbers")
|
||||
medium: "msisdn"
|
||||
}
|
||||
FormCard.FormHeader {
|
||||
Layout.fillWidth: true
|
||||
title: i18n("Identity Server")
|
||||
}
|
||||
FormCard.FormCard {
|
||||
IdentityServerDelegate {
|
||||
connection: root.connection
|
||||
}
|
||||
}
|
||||
FormCard.FormHeader {
|
||||
Layout.fillWidth: true
|
||||
title: i18n("Server Information")
|
||||
|
||||
@@ -29,6 +29,7 @@ qt_add_qml_module(settings
|
||||
DevicesCard.qml
|
||||
DeviceDelegate.qml
|
||||
EmoticonFormCard.qml
|
||||
IdentityServerDelegate.qml
|
||||
IgnoredUsersDialog.qml
|
||||
NotificationRuleItem.qml
|
||||
PasswordSheet.qml
|
||||
|
||||
142
src/settings/IdentityServerDelegate.qml
Normal file
142
src/settings/IdentityServerDelegate.qml
Normal file
@@ -0,0 +1,142 @@
|
||||
// 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
|
||||
|
||||
import org.kde.neochat
|
||||
|
||||
FormCard.AbstractFormDelegate {
|
||||
id: root
|
||||
|
||||
required property NeoChatConnection connection
|
||||
|
||||
property bool editServerUrl: false
|
||||
|
||||
text: identityServerHelper.currentServer
|
||||
|
||||
onClicked: editIdServerButton.toggle()
|
||||
|
||||
contentItem: RowLayout {
|
||||
spacing: Kirigami.Units.largeSpacing
|
||||
|
||||
QQC2.Label {
|
||||
Layout.fillWidth: true
|
||||
visible: !root.editServerUrl
|
||||
text: root.text
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
ColumnLayout {
|
||||
Kirigami.ActionTextField {
|
||||
id: editUrlField
|
||||
Layout.fillWidth: true
|
||||
visible: root.editServerUrl
|
||||
|
||||
Accessible.description: i18n("New identity server url")
|
||||
|
||||
rightActions: [
|
||||
Kirigami.Action {
|
||||
text: i18nc("@action:button", "Cancel editing identity server url")
|
||||
icon.name: "edit-delete-remove"
|
||||
onTriggered: editIdServerButton.toggle()
|
||||
},
|
||||
Kirigami.Action {
|
||||
enabled: identityServerHelper.status == IdentityServerHelper.Valid
|
||||
text: i18nc("@action:button", "Confirm new identity server url")
|
||||
icon.name: "checkmark"
|
||||
visible: editUrlField.text !== root.text
|
||||
onTriggered: {
|
||||
identityServerHelper.setIdentityServer();
|
||||
editUrlField.text = "";
|
||||
editIdServerButton.toggle();
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
onAccepted: {
|
||||
identityServerHelper.setIdentityServer()
|
||||
editUrlField.text = "";
|
||||
editIdServerButton.toggle();
|
||||
}
|
||||
}
|
||||
Kirigami.InlineMessage {
|
||||
id: editUrlStatus
|
||||
visible: root.editServerUrl && text.length > 0 && !warningTimer.running
|
||||
Layout.topMargin: visible ? Kirigami.Units.smallSpacing : 0
|
||||
Layout.fillWidth: true
|
||||
text: switch(identityServerHelper.status) {
|
||||
case IdentityServerHelper.Invalid:
|
||||
return i18n("The entered url is not a valid identity server");
|
||||
case IdentityServerHelper.Match:
|
||||
return i18n("The entered url is already configured as your identity server");
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
|
||||
type: switch(identityServerHelper.status) {
|
||||
case IdentityServerHelper.Invalid:
|
||||
return Kirigami.MessageType.Error;
|
||||
case IdentityServerHelper.Match:
|
||||
return Kirigami.MessageType.Warning;
|
||||
default:
|
||||
return Kirigami.MessageType.Information;
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: warningTimer
|
||||
interval: 500
|
||||
}
|
||||
}
|
||||
}
|
||||
QQC2.ToolButton {
|
||||
id: editIdServerButton
|
||||
display: QQC2.AbstractButton.IconOnly
|
||||
text: i18nc("@action:button", "Edit identity server url")
|
||||
icon.name: "document-edit"
|
||||
checkable: true
|
||||
onCheckedChanged: {
|
||||
root.editServerUrl = !root.editServerUrl;
|
||||
if (checked) {
|
||||
editUrlField.forceActiveFocus();
|
||||
} else {
|
||||
editUrlField.text = "";
|
||||
}
|
||||
}
|
||||
QQC2.ToolTip {
|
||||
text: editIdServerButton.text
|
||||
delay: Kirigami.Units.toolTipDelay
|
||||
visible: editIdServerButton.hovered
|
||||
}
|
||||
}
|
||||
QQC2.ToolButton {
|
||||
id: removeIdServerButton
|
||||
visible: identityServerHelper.hasCurrentServer
|
||||
display: QQC2.AbstractButton.IconOnly
|
||||
text: i18nc("@action:button", "Remove identity server")
|
||||
icon.name: "edit-delete-remove"
|
||||
onClicked: {
|
||||
identityServerHelper.clearIdentityServer();
|
||||
editUrlField.text = "";
|
||||
if (editIdServerButton.checked) {
|
||||
editIdServerButton.toggle();
|
||||
}
|
||||
}
|
||||
QQC2.ToolTip {
|
||||
text: removeIdServerButton.text
|
||||
delay: Kirigami.Units.toolTipDelay
|
||||
visible: removeIdServerButton.hovered
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IdentityServerHelper {
|
||||
id: identityServerHelper
|
||||
connection: root.connection
|
||||
url: editUrlField.text
|
||||
onUrlChanged: warningTimer.restart()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user