diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/connection.cpp | 73 | ||||
-rw-r--r-- | lib/syncdata.cpp | 30 | ||||
-rw-r--r-- | lib/syncdata.h | 23 |
3 files changed, 126 insertions, 0 deletions
diff --git a/lib/connection.cpp b/lib/connection.cpp index 1485a347..66590bd8 100644 --- a/lib/connection.cpp +++ b/lib/connection.cpp @@ -102,6 +102,13 @@ public: QMetaObject::Connection syncLoopConnection {}; int syncTimeout = -1; +#ifdef Quotient_E2EE_ENABLED + QSet<QString> trackedUsers; + QSet<QString> outdatedUsers; + QHash<QString, QHash<QString, QueryKeysJob::DeviceInformation>> deviceKeys; + QueryKeysJob *currentQueryKeysJob = nullptr; +#endif + GetCapabilitiesJob* capabilitiesJob = nullptr; GetCapabilitiesJob::Capabilities capabilities; @@ -153,6 +160,7 @@ public: void consumeAccountData(Events&& accountDataEvents); void consumePresenceData(Events&& presenceData); void consumeToDeviceEvents(Events&& toDeviceEvents); + void consumeDevicesList(DevicesList&& devicesList); template <typename EventT> EventT* unpackAccountData() const @@ -247,6 +255,10 @@ public: return std::move(decryptedEvent); #endif // Quotient_E2EE_ENABLED } +#ifdef Quotient_E2EE_ENABLED + void loadOutdatedUserDevices(); + void createDevicesList(); +#endif }; Connection::Connection(const QUrl& server, QObject* parent) @@ -468,6 +480,11 @@ void Connection::Private::completeSetup(const QString& mxId) emit q->stateChanged(); emit q->connected(); q->reloadCapabilities(); +#ifdef Quotient_E2EE_ENABLED + connectSingleShot(q, &Connection::syncDone, q, [=](){ + createDevicesList(); + }); +#endif } void Connection::Private::checkAndConnect(const QString& userId, @@ -637,6 +654,7 @@ void Connection::onSyncSuccess(SyncData&& data, bool fromCache) }); } #endif // Quotient_E2EE_ENABLED + d->consumeDevicesList(data.takeDevicesList()); } void Connection::Private::consumeRoomData(SyncDataList&& roomDataList, @@ -790,6 +808,21 @@ void Connection::Private::consumeToDeviceEvents(Events&& toDeviceEvents) #endif } +void Connection::Private::consumeDevicesList(DevicesList&& devicesList) +{ +#ifdef Quotient_E2EE_ENABLED + for(const auto &changed : devicesList.changed) { + outdatedUsers += changed; + } + for(const auto &left : devicesList.left) { + trackedUsers -= left; + outdatedUsers -= left; + deviceKeys.remove(left); + } + loadOutdatedUserDevices(); +#endif +} + void Connection::stopSync() { // If there's a sync loop, break it @@ -1784,3 +1817,43 @@ QVector<Connection::SupportedRoomVersion> Connection::availableRoomVersions() co } return result; } + +#ifdef Quotient_E2EE_ENABLED +void Connection::Private::createDevicesList() +{ + for(const auto &room : q->allRooms()) { + if(!room->usesEncryption()) { + continue; + } + for(const auto &user : room->users()) { + if(user->id() != q->userId()) { + trackedUsers += user->id(); + } + } + } + outdatedUsers += trackedUsers; + loadOutdatedUserDevices(); +} + +void Connection::Private::loadOutdatedUserDevices() +{ + QHash<QString, QStringList> users; + for(const auto &user : outdatedUsers) { + users[user] += QStringList(); + } + if(currentQueryKeysJob) { + currentQueryKeysJob->abandon(); + currentQueryKeysJob = nullptr; + } + auto queryKeysJob = q->callApi<QueryKeysJob>(users); + currentQueryKeysJob = queryKeysJob; + connect(queryKeysJob, &BaseJob::success, q, [=](){ + const auto data = queryKeysJob->deviceKeys(); + for(const auto &[user, keys] : asKeyValueRange(data)) { + //TODO Check key signature + deviceKeys[user] = keys; + outdatedUsers -= user; + } + }); +} +#endif diff --git a/lib/syncdata.cpp b/lib/syncdata.cpp index 396e77eb..9c54888c 100644 --- a/lib/syncdata.cpp +++ b/lib/syncdata.cpp @@ -99,6 +99,34 @@ SyncRoomData::SyncRoomData(QString roomId_, JoinState joinState, fromJson(unreadJson.value(HighlightCountKey), highlightCount); } +QDebug Quotient::operator<<(QDebug dbg, const DevicesList& devicesList) +{ + QDebugStateSaver _(dbg); + QStringList sl; + if (!devicesList.changed.isEmpty()) + sl << QStringLiteral("changed: %1").arg(devicesList.changed.join(", ")); + if (!devicesList.left.isEmpty()) + sl << QStringLiteral("left %1").arg(devicesList.left.join(", ")); + dbg.nospace().noquote() << sl.join(QStringLiteral("; ")); + return dbg; +} + +void JsonObjectConverter<DevicesList>::dumpTo(QJsonObject& jo, + const DevicesList& rs) +{ + addParam<IfNotEmpty>(jo, QStringLiteral("changed"), + rs.changed); + addParam<IfNotEmpty>(jo, QStringLiteral("left"), + rs.left); +} + +void JsonObjectConverter<DevicesList>::fillFrom(const QJsonObject& jo, + DevicesList& rs) +{ + fromJson(jo["changed"_ls], rs.changed); + fromJson(jo["left"_ls], rs.left); +} + SyncData::SyncData(const QString& cacheFileName) { QFileInfo cacheFileInfo { cacheFileName }; @@ -133,6 +161,8 @@ std::pair<int, int> SyncData::cacheVersion() return { MajorCacheVersion, 2 }; } +DevicesList&& SyncData::takeDevicesList() { return std::move(devicesList); } + QJsonObject SyncData::loadJson(const QString& fileName) { QFile roomFile { fileName }; diff --git a/lib/syncdata.h b/lib/syncdata.h index 36d2e0bf..7fa77eda 100644 --- a/lib/syncdata.h +++ b/lib/syncdata.h @@ -41,6 +41,27 @@ struct JsonObjectConverter<RoomSummary> { static void fillFrom(const QJsonObject& jo, RoomSummary& rs); }; +/// Information on e2e device updates. Note: only present on an +/// incremental sync. +struct DevicesList { + /// List of users who have updated their device identity keys, or who + /// now share an encrypted room with the client since the previous + /// sync response. + QStringList changed; + + /// List of users with whom we do not share any encrypted rooms + /// anymore since the previous sync response. + QStringList left; +}; + +QDebug operator<<(QDebug dhg, const DevicesList &devicesList); + +template <> +struct JsonObjectConverter<DevicesList> { + static void dumpTo(QJsonObject &jo, const DevicesList &dev); + static void fillFrom(const QJsonObject& jo, DevicesList& rs); +}; + class SyncRoomData { public: QString roomId; @@ -85,6 +106,7 @@ public: return deviceOneTimeKeysCount_; } SyncDataList&& takeRoomData(); + DevicesList&& takeDevicesList(); QString nextBatch() const { return nextBatch_; } @@ -102,6 +124,7 @@ private: SyncDataList roomData; QStringList unresolvedRoomIds; QHash<QString, int> deviceOneTimeKeysCount_; + DevicesList devicesList; static QJsonObject loadJson(const QString& fileName); }; |