aboutsummaryrefslogtreecommitdiff
path: root/lib/connection.h
diff options
context:
space:
mode:
authorn-peugnet <n.peugnet@free.fr>2022-10-06 19:27:24 +0200
committern-peugnet <n.peugnet@free.fr>2022-10-06 19:27:24 +0200
commit08632625e1a04257b5c7d4a9db2246ac07436748 (patch)
tree9ddadf219a7e352ddd3549ad1683282c944adfb6 /lib/connection.h
parente9c2e2a26d3711e755aa5eb8a8478917c71d612b (diff)
parentd911b207f49e936b3e992200796110f0749ed150 (diff)
downloadlibquotient-08632625e1a04257b5c7d4a9db2246ac07436748.tar.gz
libquotient-08632625e1a04257b5c7d4a9db2246ac07436748.zip
Update upstream source from tag 'upstream/0.7.0'
Update to upstream version '0.7.0' with Debian dir 30dcb77a77433e4a54eab77c0b82ae925dead2d8
Diffstat (limited to 'lib/connection.h')
-rw-r--r--lib/connection.h275
1 files changed, 152 insertions, 123 deletions
diff --git a/lib/connection.h b/lib/connection.h
index c90cb892..75faf370 100644
--- a/lib/connection.h
+++ b/lib/connection.h
@@ -1,30 +1,16 @@
-/******************************************************************************
- * Copyright (C) 2015 Felix Rohrbach <kde@fxrh.de>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
+// SPDX-FileCopyrightText: 2016 Kitsune Ral <Kitsune-Ral@users.sf.net>
+// SPDX-FileCopyrightText: 2017 Roman Plášil <me@rplasil.name>
+// SPDX-FileCopyrightText: 2019 Alexey Andreyev <aa13q@ya.ru>
+// SPDX-License-Identifier: LGPL-2.1-or-later
#pragma once
-#include "ssosession.h"
-#include "joinstate.h"
-#include "qt_connection_util.h"
#include "quotient_common.h"
+#include "ssosession.h"
+#include "util.h"
-#include "csapi/login.h"
#include "csapi/create_room.h"
+#include "csapi/login.h"
#include "events/accountdataevents.h"
@@ -35,9 +21,12 @@
#include <functional>
-namespace QtOlm {
-class Account;
-}
+#ifdef Quotient_E2EE_ENABLED
+#include "e2ee/e2ee.h"
+#include "e2ee/qolmoutboundsession.h"
+#include "keyverificationsession.h"
+#include "events/keyverificationevent.h"
+#endif
Q_DECLARE_METATYPE(Quotient::GetLoginFlowsJob::LoginFlow)
@@ -61,29 +50,33 @@ class DownloadFileJob;
class SendToDeviceJob;
class SendMessageJob;
class LeaveRoomJob;
+class Database;
+struct EncryptedFileMetadata;
+
+class QOlmAccount;
+class QOlmInboundGroupSession;
+
+using LoginFlow = GetLoginFlowsJob::LoginFlow;
+
+/// Predefined login flows
+namespace LoginFlows {
+ inline const LoginFlow Password { "m.login.password" };
+ inline const LoginFlow SSO { "m.login.sso" };
+ inline const LoginFlow Token { "m.login.token" };
+}
// To simplify comparisons of LoginFlows
-inline bool operator==(const GetLoginFlowsJob::LoginFlow& lhs,
- const GetLoginFlowsJob::LoginFlow& rhs)
+inline bool operator==(const LoginFlow& lhs, const LoginFlow& rhs)
{
return lhs.type == rhs.type;
}
-inline bool operator!=(const GetLoginFlowsJob::LoginFlow& lhs,
- const GetLoginFlowsJob::LoginFlow& rhs)
+inline bool operator!=(const LoginFlow& lhs, const LoginFlow& rhs)
{
return !(lhs == rhs);
}
-/// Predefined login flows
-struct LoginFlows {
- using LoginFlow = GetLoginFlowsJob::LoginFlow;
- static inline const LoginFlow Password { "m.login.password" };
- static inline const LoginFlow SSO { "m.login.sso" };
- static inline const LoginFlow Token { "m.login.token" };
-};
-
class Connection;
using room_factory_t =
@@ -96,11 +89,9 @@ using user_factory_t = std::function<User*(Connection*, const QString&)>;
* \sa Connection::setRoomFactory, Connection::setRoomType
*/
template <typename T = Room>
-static inline room_factory_t defaultRoomFactory()
+auto defaultRoomFactory(Connection* c, const QString& id, JoinState js)
{
- return [](Connection* c, const QString& id, JoinState js) {
- return new T(c, id, js);
- };
+ return new T(c, id, js);
}
/** The default factory to create user objects
@@ -109,9 +100,9 @@ static inline room_factory_t defaultRoomFactory()
* \sa Connection::setUserFactory, Connection::setUserType
*/
template <typename T = User>
-static inline user_factory_t defaultUserFactory()
+auto defaultUserFactory(Connection* c, const QString& id)
{
- return [](Connection* c, const QString& id) { return new T(id, c); };
+ return new T(id, c);
}
// Room ids, rather than room pointers, are used in the direct chat
@@ -120,9 +111,9 @@ static inline user_factory_t defaultUserFactory()
// are stored with no regard to their state.
using DirectChatsMap = QMultiHash<const User*, QString>;
using DirectChatUsersMap = QMultiHash<QString, User*>;
-using IgnoredUsersList = IgnoredUsersEvent::content_type;
+using IgnoredUsersList = IgnoredUsersEvent::value_type;
-class Connection : public QObject {
+class QUOTIENT_API Connection : public QObject {
Q_OBJECT
Q_PROPERTY(User* localUser READ user NOTIFY stateChanged)
@@ -139,10 +130,10 @@ class Connection : public QObject {
Q_PROPERTY(bool supportsPasswordAuth READ supportsPasswordAuth NOTIFY loginFlowsChanged STORED false)
Q_PROPERTY(bool cacheState READ cacheState WRITE setCacheState NOTIFY cacheStateChanged)
Q_PROPERTY(bool lazyLoading READ lazyLoading WRITE setLazyLoading NOTIFY lazyLoadingChanged)
+ Q_PROPERTY(bool canChangePassword READ canChangePassword NOTIFY capabilitiesLoaded)
public:
- using UsersToDevicesToEvents =
- UnorderedMap<QString, UnorderedMap<QString, const Event&>>;
+ using UsersToDevicesToContent = QHash<QString, QHash<QString, QJsonObject>>;
enum RoomVisibility {
PublishRoom,
@@ -153,15 +144,6 @@ public:
explicit Connection(const QUrl& server, QObject* parent = nullptr);
~Connection() override;
- /// Get all Invited and Joined rooms
- /*!
- * \return a hashmap from a composite key - room name and whether
- * it's an Invite rather than Join - to room pointers
- * \sa allRooms, rooms, roomsWithTag
- */
- [[deprecated("Use allRooms(), roomsWithTag() or rooms(joinStates) instead")]]
- QHash<QPair<QString, bool>, Room*> roomMap() const;
-
/// Get all rooms known within this Connection
/*!
* This includes Invite, Join and Leave rooms, in no particular order.
@@ -192,24 +174,25 @@ public:
*/
bool hasAccountData(const QString& type) const;
- /** Get a generic account data event of the given type
- * This returns an account data event of the given type
- * stored on the server. Direct chats map cannot be retrieved
- * using this method _yet_; use directChats() instead.
- */
+ //! \brief Get a generic account data event of the given type
+ //!
+ //! \return an account data event of the given type stored on the server,
+ //! or nullptr if there's none of that type.
+ //! \note Direct chats map cannot be retrieved using this method _yet_;
+ //! use directChats() instead.
const EventPtr& accountData(const QString& type) const;
- /** Get a generic account data event of the given type
- * This returns an account data event of the given type
- * stored on the server. Direct chats map cannot be retrieved
- * using this method _yet_; use directChats() instead.
- */
- template <typename EventT>
- const typename EventT::content_type accountData() const
+ //! \brief Get an account data event of the given type
+ //!
+ //! \return the account data content for the given event type stored
+ //! on the server, or a default-constructed object if there's none
+ //! of that type.
+ //! \note Direct chats map cannot be retrieved using this method _yet_;
+ //! use directChats() instead.
+ template <EventClass EventT>
+ const EventT* accountData() const
{
- if (const auto& eventPtr = accountData(EventT::matrixTypeId()))
- return eventPtr->content();
- return {};
+ return eventCast<EventT>(accountData(EventT::TypeId));
}
/** Get account data as a JSON object
@@ -334,7 +317,38 @@ public:
QByteArray accessToken() const;
bool isLoggedIn() const;
#ifdef Quotient_E2EE_ENABLED
- QtOlm::Account* olmAccount() const;
+ QOlmAccount* olmAccount() const;
+ Database* database() const;
+ PicklingMode picklingMode() const;
+
+ UnorderedMap<QString, QOlmInboundGroupSessionPtr> loadRoomMegolmSessions(
+ const Room* room) const;
+ void saveMegolmSession(const Room* room,
+ const QOlmInboundGroupSession& session) const;
+ QOlmOutboundGroupSessionPtr loadCurrentOutboundMegolmSession(
+ const QString& roomId) const;
+ void saveCurrentOutboundMegolmSession(
+ const QString& roomId, const QOlmOutboundGroupSession& session) const;
+
+ QString edKeyForUserDevice(const QString& userId,
+ const QString& deviceId) const;
+ bool hasOlmSession(const QString& user, const QString& deviceId) const;
+
+ // This assumes that an olm session already exists. If it doesn't, no message is sent.
+ void sendToDevice(const QString& targetUserId, const QString& targetDeviceId,
+ const Event& event, bool encrypted);
+
+ /// Returns true if this megolm session comes from a verified device
+ bool isVerifiedSession(const QString& megolmSessionId) const;
+
+ void sendSessionKeyToDevices(const QString& roomId,
+ const QByteArray& sessionId,
+ const QByteArray& sessionKey,
+ const QMultiHash<QString, QString>& devices,
+ int index);
+
+ QJsonObject decryptNotification(const QJsonObject &notification);
+ QStringList devicesForUser(const QString& userId) const;
#endif // Quotient_E2EE_ENABLED
Q_INVOKABLE Quotient::SyncJob* syncJob() const;
Q_INVOKABLE int millisToReconnect() const;
@@ -368,22 +382,19 @@ public:
* \sa loadingCapabilities */
QVector<SupportedRoomVersion> availableRoomVersions() const;
+ /// Indicate if the user can change its password from the client.
+ /// This is often not the case when SSO is enabled.
+ /// \sa loadingCapabilities
+ bool canChangePassword() const;
+
/**
* Call this before first sync to load from previously saved file.
- *
- * \param fromFile A local path to read the state from. Uses QUrl
- * to be QML-friendly. Empty parameter means saving to the directory
- * defined by stateCachePath() / stateCacheDir().
*/
Q_INVOKABLE void loadState();
/**
* This method saves the current state of rooms (but not messages
* in them) to a local cache file, so that it could be loaded by
* loadState() on a next run of the client.
- *
- * \param toFile A local path to save the state to. Uses QUrl to be
- * QML-friendly. Empty parameter means saving to the directory
- * defined by stateCachePath() / stateCacheDir().
*/
Q_INVOKABLE void saveState() const;
@@ -418,7 +429,7 @@ public:
/*! Start a pre-created job object on this connection */
Q_INVOKABLE BaseJob* run(BaseJob* job,
- RunningPolicy runningPolicy = ForegroundRequest);
+ RunningPolicy runningPolicy = ForegroundRequest);
/*! Start a job of a specified type with specified arguments and policy
*
@@ -463,6 +474,17 @@ public:
std::forward<JobArgTs>(jobArgs)...);
}
+ //! \brief Start a local HTTP server and generate a single sign-on URL
+ //!
+ //! This call does the preparatory steps to carry out single sign-on
+ //! sequence
+ //! \sa https://matrix.org/docs/guides/sso-for-client-developers
+ //! \return A proxy object holding two URLs: one for SSO on the chosen
+ //! homeserver and another for the local callback address. Normally
+ //! you won't need the callback URL unless you proxy the response
+ //! with a custom UI. You do not need to delete the SsoSession
+ //! object; the Connection that issued it will dispose of it once
+ //! the login sequence completes (with any outcome).
Q_INVOKABLE SsoSession* prepareForSso(const QString& initialDeviceName,
const QString& deviceId = {});
@@ -487,21 +509,37 @@ public:
template <typename T>
static void setRoomType()
{
- setRoomFactory(defaultRoomFactory<T>());
+ setRoomFactory(defaultRoomFactory<T>);
}
/// Set the user factory to default with the overriden user type
template <typename T>
static void setUserType()
{
- setUserFactory(defaultUserFactory<T>());
+ setUserFactory(defaultUserFactory<T>);
}
-public slots:
- /** Set the homeserver base URL */
+ /// Saves the olm account data to disk. Usually doesn't need to be called manually.
+ void saveOlmAccount();
+
+public Q_SLOTS:
+ /// \brief Set the homeserver base URL and retrieve its login flows
+ ///
+ /// \sa LoginFlowsJob, loginFlows, loginFlowsChanged, homeserverChanged
void setHomeserver(const QUrl& baseUrl);
- /** Determine and set the homeserver from MXID */
+ /// \brief Determine and set the homeserver from MXID
+ ///
+ /// This attempts to resolve the homeserver by requesting
+ /// .well-known/matrix/client record from the server taken from the MXID
+ /// serverpart. If there is no record found, the serverpart itself is
+ /// attempted as the homeserver base URL; if the record is there but
+ /// is malformed (e.g., the homeserver base URL cannot be found in it)
+ /// resolveError() is emitted and further processing stops. Otherwise,
+ /// setHomeserver is called, preparing the Connection object for the login
+ /// attempt.
+ /// \param mxid user Matrix ID, such as @someone:example.org
+ /// \sa setHomeserver, homeserverChanged, loginFlowsChanged, resolveError
void resolveServer(const QString& mxid);
/** \brief Log in using a username and password pair
@@ -534,30 +572,12 @@ public slots:
*/
void assumeIdentity(const QString& mxId, const QString& accessToken,
const QString& deviceId);
- /*! \deprecated Use loginWithPassword instead */
- void connectToServer(const QString& userId, const QString& password,
- const QString& initialDeviceName,
- const QString& deviceId = {})
- {
- loginWithPassword(userId, password, initialDeviceName, deviceId);
- }
- /*! \deprecated
- * Use assumeIdentity() if you have an access token or
- * loginWithToken() if you have a login token.
- */
- void connectWithToken(const QString& userId, const QString& accessToken,
- const QString& deviceId)
- {
- assumeIdentity(userId, accessToken, deviceId);
- }
/// Explicitly request capabilities from the server
void reloadCapabilities();
/// Find out if capabilites are still loading from the server
bool loadingCapabilities() const;
- /** @deprecated Use stopSync() instead */
- void disconnectFromServer() { stopSync(); }
void logout();
void sync(int timeout = -1);
@@ -566,6 +586,8 @@ public slots:
void stopSync();
QString nextBatchToken() const;
+ Q_INVOKABLE QUrl makeMediaUrl(QUrl mxcUrl) const;
+
virtual MediaThumbnailJob*
getThumbnail(const QString& mediaId, QSize requestedSize,
RunningPolicy policy = BackgroundRequest);
@@ -587,6 +609,11 @@ public slots:
DownloadFileJob* downloadFile(const QUrl& url,
const QString& localFilename = {});
+#ifdef Quotient_E2EE_ENABLED
+ DownloadFileJob* downloadFile(const QUrl& url,
+ const EncryptedFileMetadata& fileMetadata,
+ const QString& localFilename = {});
+#endif
/**
* \brief Create a room (generic method)
* This method allows to customize room entirely to your liking,
@@ -664,7 +691,7 @@ public slots:
ForgetRoomJob* forgetRoom(const QString& id);
SendToDeviceJob* sendToDevices(const QString& eventType,
- const UsersToDevicesToEvents& eventsMap);
+ const UsersToDevicesToContent& contents);
/** \deprecated This method is experimental and may be removed any time */
SendMessageJob* sendMessage(const QString& roomId, const RoomEvent& event);
@@ -672,24 +699,18 @@ public slots:
/** \deprecated Do not use this directly, use Room::leaveRoom() instead */
virtual LeaveRoomJob* leaveRoom(Room* room);
- // Old API that will be abolished any time soon. DO NOT USE.
+#ifdef Quotient_E2EE_ENABLED
+ void startKeyVerificationSession(const QString& deviceId);
- /** @deprecated Use callApi<PostReceiptJob>() or Room::postReceipt() instead
- */
- virtual PostReceiptJob* postReceipt(Room* room, RoomEvent* event);
+ void encryptionUpdate(Room *room);
+#endif
-signals:
- /**
- * @deprecated
- * This was a signal resulting from a successful resolveServer().
- * Since Connection now provides setHomeserver(), the HS URL
- * may change even without resolveServer() invocation. Use
- * loginFLowsChanged() instead of resolved(). You can also use
- * loginWith*() and assumeIdentity() without the HS URL set in
- * advance (i.e. without calling resolveServer), as they trigger
- * server name resolution from MXID if the server URL is not valid.
- */
- void resolved();
+Q_SIGNALS:
+ /// \brief Initial server resolution has failed
+ ///
+ /// This signal is emitted when resolveServer() did not manage to resolve
+ /// the homeserver using its .well-known/client record or otherwise.
+ /// \sa resolveServer
void resolveError(QString error);
void homeserverChanged(QUrl baseUrl);
@@ -697,7 +718,6 @@ signals:
void capabilitiesLoaded();
void connected();
- void reconnected(); //< \deprecated Use connected() instead
void loggedOut();
/** Login data or state have changed
*
@@ -841,6 +861,15 @@ signals:
void cacheStateChanged();
void lazyLoadingChanged();
void turnServersChanged(const QJsonObject& servers);
+ void devicesListLoaded();
+
+#ifdef Quotient_E2EE_ENABLED
+ void newKeyVerificationSession(KeyVerificationSession* session);
+ void keyVerificationStateChanged(
+ const KeyVerificationSession* session,
+ Quotient::KeyVerificationSession::State state);
+ void sessionVerified(const QString& userId, const QString& deviceId);
+#endif
protected:
/**
@@ -875,12 +904,12 @@ protected:
*/
void onSyncSuccess(SyncData&& data, bool fromCache = false);
-protected slots:
+protected Q_SLOTS:
void syncLoopIteration();
private:
class Private;
- QScopedPointer<Private> d;
+ ImplPtr<Private> d;
static room_factory_t _roomFactory;
static user_factory_t _userFactory;