aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/connection.cpp73
-rw-r--r--lib/syncdata.cpp30
-rw-r--r--lib/syncdata.h23
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);
};