diff options
author | Alexey Rusakov <Kitsune-Ral@users.sf.net> | 2022-05-27 19:09:26 +0200 |
---|---|---|
committer | Alexey Rusakov <Kitsune-Ral@users.sf.net> | 2022-05-29 08:22:35 +0200 |
commit | 0f8335a32debc4c61d9fc9875c79c0ba6ba05357 (patch) | |
tree | fb78230a898754b2df982b890a4129839937f110 /lib | |
parent | 64797165f04a16d290dd27c2f962060b40f85be3 (diff) | |
download | libquotient-0f8335a32debc4c61d9fc9875c79c0ba6ba05357.tar.gz libquotient-0f8335a32debc4c61d9fc9875c79c0ba6ba05357.zip |
Move some Meg/Olm session logic from Room::Private to Connection::Private
Functions (Room::Private::)createOlmSession, payloadForUserDevice
and sendRoomKeyToDevices don't have a lot to do with the given Room
object but deal with quite a few things stored in Connection. This
commit moves them to Connection::Private, exposing
sendSessionKeyToDevices (the new name for sendRoomKeyToDevices) in
Connection so that Room could call it from Room::P::sendMegolmSession().
While moving these over, a few additional things were adjusted:
- more functions marked as const
- a few functions could be moved now from Connection
to Connection::Private
- false slots in Connection (such as picklingMode) are moved out of
the slots block
- keys.yml in Matrix CS API definitions has been adjusted to match
the real structure of `/claim` response (see quotient-im/matrix-spec
repo); csapi/keys.h has been regenerated accordingly.
Diffstat (limited to 'lib')
-rw-r--r-- | lib/connection.cpp | 227 | ||||
-rw-r--r-- | lib/connection.h | 34 | ||||
-rw-r--r-- | lib/csapi/keys.h | 4 | ||||
-rw-r--r-- | lib/e2ee/qolmsession.cpp | 5 | ||||
-rw-r--r-- | lib/e2ee/qolmsession.h | 2 | ||||
-rw-r--r-- | lib/events/roomkeyevent.h | 4 | ||||
-rw-r--r-- | lib/room.cpp | 113 |
7 files changed, 209 insertions, 180 deletions
diff --git a/lib/connection.cpp b/lib/connection.cpp index 1193eb75..ab4a7dea 100644 --- a/lib/connection.cpp +++ b/lib/connection.cpp @@ -39,6 +39,7 @@ # include "e2ee/qolmaccount.h" # include "e2ee/qolminboundsession.h" # include "e2ee/qolmsession.h" +# include "e2ee/qolmutility.h" # include "e2ee/qolmutils.h" # if QT_VERSION_MAJOR >= 6 @@ -62,7 +63,6 @@ #include <QtCore/QStringBuilder> #include <QtNetwork/QDnsLookup> - using namespace Quotient; // This is very much Qt-specific; STL iterators don't have key() and value() @@ -210,11 +210,11 @@ public: #ifdef Quotient_E2EE_ENABLED void loadSessions() { - olmSessions = q->database()->loadOlmSessions(q->picklingMode()); + olmSessions = q->database()->loadOlmSessions(picklingMode); } - void saveSession(QOlmSession& session, const QString& senderKey) + void saveSession(const QOlmSession& session, const QString& senderKey) const { - if (auto pickleResult = session.pickle(q->picklingMode())) + if (auto pickleResult = session.pickle(picklingMode)) q->database()->saveOlmSession(senderKey, session.sessionId(), *pickleResult, QDateTime::currentDateTime()); @@ -364,9 +364,27 @@ public: #endif // Quotient_E2EE_ENABLED } #ifdef Quotient_E2EE_ENABLED + bool isKnownCurveKey(const QString& userId, const QString& curveKey) const; + void loadOutdatedUserDevices(); void saveDevicesList(); void loadDevicesList(); + + // This function assumes that an olm session with (user, device) exists + std::pair<QOlmMessage::Type, QByteArray> olmEncryptMessage( + const QString& userId, const QString& device, + const QByteArray& message) const; + bool createOlmSession(const QString& targetUserId, + const QString& targetDeviceId, + const QJsonObject& oneTimeKeyObject); + QString curveKeyForUserDevice(const QString& userId, + const QString& device) const; + QString edKeyForUserDevice(const QString& userId, + const QString& device) const; + std::unique_ptr<EncryptedEvent> makeEventForSessionKey( + const QString& roomId, const QString& targetUserId, + const QString& targetDeviceId, const QByteArray& sessionId, + const QByteArray& sessionKey) const; #endif }; @@ -935,20 +953,23 @@ void Connection::Private::consumeToDeviceEvents(Events&& toDeviceEvents) { #ifdef Quotient_E2EE_ENABLED if (!toDeviceEvents.empty()) { - qCDebug(E2EE) << "Consuming" << toDeviceEvents.size() << "to-device events"; + qCDebug(E2EE) << "Consuming" << toDeviceEvents.size() + << "to-device events"; visitEach(toDeviceEvents, [this](const EncryptedEvent& event) { if (event.algorithm() != OlmV1Curve25519AesSha2AlgoKey) { - qCDebug(E2EE) << "Unsupported algorithm" << event.id() << "for event" << event.algorithm(); + qCDebug(E2EE) << "Unsupported algorithm" << event.id() + << "for event" << event.algorithm(); return; } - if (q->isKnownCurveKey(event.senderId(), event.senderKey())) { + if (isKnownCurveKey(event.senderId(), event.senderKey())) { handleEncryptedToDeviceEvent(event); return; } trackedUsers += event.senderId(); outdatedUsers += event.senderId(); encryptionUpdateRequired = true; - pendingEncryptedEvents.push_back(std::make_unique<EncryptedEvent>(event.fullJson())); + pendingEncryptedEvents.push_back( + makeEvent<EncryptedEvent>(event.fullJson())); }); } #endif @@ -1316,9 +1337,8 @@ ForgetRoomJob* Connection::forgetRoom(const QString& id) return forgetJob; } -SendToDeviceJob* -Connection::sendToDevices(const QString& eventType, - const UsersToDevicesToEvents& eventsMap) +SendToDeviceJob* Connection::sendToDevices( + const QString& eventType, const UsersToDevicesToEvents& eventsMap) { QHash<QString, QHash<QString, QJsonObject>> json; json.reserve(int(eventsMap.size())); @@ -2063,7 +2083,7 @@ void Connection::Private::loadOutdatedUserDevices() saveDevicesList(); for(size_t i = 0; i < pendingEncryptedEvents.size();) { - if (q->isKnownCurveKey( + if (isKnownCurveKey( pendingEncryptedEvents[i]->fullJson()[SenderKeyL].toString(), pendingEncryptedEvents[i]->contentPart<QString>("sender_key"_ls))) { handleEncryptedToDeviceEvent(*pendingEncryptedEvents[i]); @@ -2193,13 +2213,13 @@ Database* Connection::database() const } UnorderedMap<QString, QOlmInboundGroupSessionPtr> -Connection::loadRoomMegolmSessions(const Room* room) +Connection::loadRoomMegolmSessions(const Room* room) const { return database()->loadMegolmSessions(room->id(), picklingMode()); } void Connection::saveMegolmSession(const Room* room, - const QOlmInboundGroupSession& session) + const QOlmInboundGroupSession& session) const { database()->saveMegolmSession(room->id(), session.sessionId(), session.pickle(picklingMode()), @@ -2211,64 +2231,179 @@ QStringList Connection::devicesForUser(const QString& userId) const return d->deviceKeys[userId].keys(); } -QString Connection::curveKeyForUserDevice(const QString& userId, - const QString& device) const +QString Connection::Private::curveKeyForUserDevice(const QString& userId, + const QString& device) const { - return d->deviceKeys[userId][device].keys["curve25519:" % device]; + return deviceKeys[userId][device].keys["curve25519:" % device]; } -QString Connection::edKeyForUserDevice(const QString& userId, - const QString& device) const +QString Connection::Private::edKeyForUserDevice(const QString& userId, + const QString& device) const { - return d->deviceKeys[userId][device].keys["ed25519:" % device]; + return deviceKeys[userId][device].keys["ed25519:" % device]; } -bool Connection::isKnownCurveKey(const QString& userId, - const QString& curveKey) const +bool Connection::Private::isKnownCurveKey(const QString& userId, + const QString& curveKey) const { - auto query = database()->prepareQuery(QStringLiteral("SELECT * FROM tracked_devices WHERE matrixId=:matrixId AND curveKey=:curveKey")); + auto query = database->prepareQuery( + QStringLiteral("SELECT * FROM tracked_devices WHERE matrixId=:matrixId " + "AND curveKey=:curveKey")); query.bindValue(":matrixId", userId); query.bindValue(":curveKey", curveKey); - database()->execute(query); + database->execute(query); return query.next(); } -bool Connection::hasOlmSession(const QString& user, const QString& deviceId) const +bool Connection::hasOlmSession(const QString& user, + const QString& deviceId) const { - const auto& curveKey = curveKeyForUserDevice(user, deviceId); + const auto& curveKey = d->curveKeyForUserDevice(user, deviceId); return d->olmSessions.contains(curveKey) && !d->olmSessions[curveKey].empty(); } -std::pair<QOlmMessage::Type, QByteArray> Connection::olmEncryptMessage( - const QString& userId, const QString& device, const QByteArray& message) const +std::pair<QOlmMessage::Type, QByteArray> Connection::Private::olmEncryptMessage( + const QString& userId, const QString& device, + const QByteArray& message) const { const auto& curveKey = curveKeyForUserDevice(userId, device); - QOlmMessage::Type type = d->olmSessions[curveKey][0]->encryptMessageType(); - const auto result = d->olmSessions[curveKey][0]->encrypt(message); - if (const auto pickle = - d->olmSessions[curveKey][0]->pickle(picklingMode())) { - database()->updateOlmSession(curveKey, - d->olmSessions[curveKey][0]->sessionId(), - *pickle); + const auto& olmSession = olmSessions.at(curveKey).front(); + QOlmMessage::Type type = olmSession->encryptMessageType(); + const auto result = olmSession->encrypt(message); + if (const auto pickle = olmSession->pickle(picklingMode)) { + database->updateOlmSession(curveKey, olmSession->sessionId(), *pickle); } else { - qCWarning(E2EE) << "Failed to pickle olm session: " << pickle.error(); + qWarning(E2EE) << "Failed to pickle olm session: " << pickle.error(); } return { type, result.toCiphertext() }; } -void Connection::createOlmSession(const QString& theirIdentityKey, - const QString& theirOneTimeKey) const -{ - auto session = QOlmSession::createOutboundSession(olmAccount(), - theirIdentityKey, - theirOneTimeKey); +bool Connection::Private::createOlmSession(const QString& targetUserId, + const QString& targetDeviceId, + const QJsonObject& oneTimeKeyObject) +{ + static QOlmUtility verifier; + qDebug(E2EE) << "Creating a new session for" << targetUserId + << targetDeviceId; + if (oneTimeKeyObject.isEmpty()) { + qWarning(E2EE) << "No one time key for" << targetUserId + << targetDeviceId; + return false; + } + auto signedOneTimeKey = oneTimeKeyObject.constBegin()->toObject(); + // Verify contents of signedOneTimeKey - for that, drop `signatures` and + // `unsigned` and then verify the object against the respective signature + const auto signature = + signedOneTimeKey.take("signatures"_ls)[targetUserId]["ed25519:"_ls % targetDeviceId] + .toString() + .toLatin1(); + signedOneTimeKey.remove("unsigned"_ls); + if (!verifier.ed25519Verify( + edKeyForUserDevice(targetUserId, targetDeviceId).toLatin1(), + QJsonDocument(signedOneTimeKey).toJson(QJsonDocument::Compact), + signature)) { + qWarning(E2EE) << "Failed to verify one-time-key signature for" << targetUserId + << targetDeviceId << ". Skipping this device."; + return false; + } + const auto recipientCurveKey = + curveKeyForUserDevice(targetUserId, targetDeviceId); + auto session = + QOlmSession::createOutboundSession(olmAccount.get(), recipientCurveKey, + signedOneTimeKey["key"].toString()); if (!session) { qCWarning(E2EE) << "Failed to create olm session for " - << theirIdentityKey << session.error(); + << recipientCurveKey << session.error(); + return false; + } + saveSession(**session, recipientCurveKey); + olmSessions[recipientCurveKey].push_back(std::move(*session)); + return true; +} + +std::unique_ptr<EncryptedEvent> Connection::Private::makeEventForSessionKey( + const QString& roomId, const QString& targetUserId, + const QString& targetDeviceId, const QByteArray& sessionId, + const QByteArray& sessionKey) const +{ + // Noisy but nice for debugging + // qDebug(E2EE) << "Creating the payload for" << data->userId() << device << + // sessionId << sessionKey.toHex(); + const auto event = makeEvent<RoomKeyEvent>("m.megolm.v1.aes-sha2", roomId, + sessionId, sessionKey, + data->userId()); + auto payloadJson = event->fullJson(); + payloadJson.insert("recipient"_ls, targetUserId); + payloadJson.insert(SenderKeyL, data->userId()); + payloadJson.insert("recipient_keys"_ls, + QJsonObject { { Ed25519Key, + edKeyForUserDevice(targetUserId, + targetDeviceId) } }); + payloadJson.insert("keys"_ls, + QJsonObject { + { Ed25519Key, + QString(olmAccount->identityKeys().ed25519) } }); + payloadJson.insert("sender_device"_ls, data->deviceId()); + + const auto [type, cipherText] = olmEncryptMessage( + targetUserId, targetDeviceId, + QJsonDocument(payloadJson).toJson(QJsonDocument::Compact)); + QJsonObject encrypted { + { curveKeyForUserDevice(targetUserId, targetDeviceId), + QJsonObject { { "type"_ls, type }, + { "body"_ls, QString(cipherText) } } } + }; + + return makeEvent<EncryptedEvent>(encrypted, + olmAccount->identityKeys().curve25519); +} + +void Connection::sendSessionKeyToDevices( + const QString& roomId, const QByteArray& sessionId, + const QByteArray& sessionKey, const QMultiHash<QString, QString>& devices, + int index) +{ + qDebug(E2EE) << "Sending room key to devices:" << sessionId + << sessionKey.toHex(); + QHash<QString, QHash<QString, QString>> hash; + for (const auto& [userId, deviceId] : asKeyValueRange(devices)) + if (!hasOlmSession(userId, deviceId)) { + hash[userId].insert(deviceId, "signed_curve25519"_ls); + qDebug(E2EE) << "Adding" << userId << deviceId + << "to keys to claim"; + } + + if (hash.isEmpty()) return; - } - d->saveSession(**session, theirIdentityKey); - d->olmSessions[theirIdentityKey].push_back(std::move(*session)); + + auto job = callApi<ClaimKeysJob>(hash); + connect(job, &BaseJob::success, this, [job, this, roomId, sessionId, sessionKey, devices, index] { + UsersToDevicesToEvents usersToDevicesToEvents; + const auto oneTimeKeys = job->oneTimeKeys(); + for (const auto& [targetUserId, targetDeviceId] : + asKeyValueRange(devices)) { + if (!hasOlmSession(targetUserId, targetDeviceId) + && !d->createOlmSession( + targetUserId, targetDeviceId, + oneTimeKeys[targetUserId][targetDeviceId])) + continue; + + usersToDevicesToEvents[targetUserId][targetDeviceId] = + d->makeEventForSessionKey(roomId, targetUserId, targetDeviceId, + sessionId, sessionKey); + } + if (!usersToDevicesToEvents.empty()) { + sendToDevices(EncryptedEvent::TypeId, usersToDevicesToEvents); + QVector<std::tuple<QString, QString, QString>> receivedDevices; + receivedDevices.reserve(devices.size()); + for (const auto& [user, device] : asKeyValueRange(devices)) + receivedDevices.push_back( + { user, device, d->curveKeyForUserDevice(user, device) }); + + database()->setDevicesReceivedKey(roomId, receivedDevices, + sessionId, index); + } + }); } QOlmOutboundGroupSessionPtr Connection::loadCurrentOutboundMegolmSession( diff --git a/lib/connection.h b/lib/connection.h index a2824744..5b806350 100644 --- a/lib/connection.h +++ b/lib/connection.h @@ -319,22 +319,26 @@ public: #ifdef Quotient_E2EE_ENABLED QOlmAccount* olmAccount() const; Database* database() const; + PicklingMode picklingMode() const; UnorderedMap<QString, QOlmInboundGroupSessionPtr> loadRoomMegolmSessions( - const Room* room); + const Room* room) const; void saveMegolmSession(const Room* room, - const QOlmInboundGroupSession& session); + const QOlmInboundGroupSession& session) const; bool hasOlmSession(const QString& user, const QString& deviceId) const; QOlmOutboundGroupSessionPtr loadCurrentOutboundMegolmSession( const QString& roomId) const; - void saveCurrentOutboundMegolmSession(const QString& roomId, const QOlmOutboundGroupSession &session) const; - - //This assumes that an olm session with (user, device) exists - std::pair<QOlmMessage::Type, QByteArray> olmEncryptMessage( - const QString& userId, const QString& device, - const QByteArray& message) const; - void createOlmSession(const QString& theirIdentityKey, - const QString& theirOneTimeKey) const; + void saveCurrentOutboundMegolmSession( + const QString& roomId, const QOlmOutboundGroupSession& session) const; + + void sendSessionKeyToDevices(const QString& roomId, + const QByteArray& sessionId, + const QByteArray& sessionKey, + const QMultiHash<QString, QString>& devices, + int index); + + QJsonObject decryptNotification(const QJsonObject ¬ification); + QStringList devicesForUser(const QString& userId) const; #endif // Quotient_E2EE_ENABLED Q_INVOKABLE Quotient::SyncJob* syncJob() const; Q_INVOKABLE int millisToReconnect() const; @@ -695,16 +699,8 @@ public Q_SLOTS: #ifdef Quotient_E2EE_ENABLED void encryptionUpdate(Room *room); - PicklingMode picklingMode() const; - QJsonObject decryptNotification(const QJsonObject ¬ification); - - QStringList devicesForUser(const QString& userId) const; - QString curveKeyForUserDevice(const QString& userId, - const QString& device) const; - QString edKeyForUserDevice(const QString& userId, - const QString& device) const; - bool isKnownCurveKey(const QString& userId, const QString& curveKey) const; #endif + Q_SIGNALS: /// \brief Initial server resolution has failed /// diff --git a/lib/csapi/keys.h b/lib/csapi/keys.h index ce1ca9ed..bcf1ad41 100644 --- a/lib/csapi/keys.h +++ b/lib/csapi/keys.h @@ -207,9 +207,9 @@ public: /// /// See the [key algorithms](/client-server-api/#key-algorithms) section for /// information on the Key Object format. - QHash<QString, QHash<QString, QVariant>> oneTimeKeys() const + QHash<QString, QHash<QString, QJsonObject>> oneTimeKeys() const { - return loadFromJson<QHash<QString, QHash<QString, QVariant>>>( + return loadFromJson<QHash<QString, QHash<QString, QJsonObject>>>( "one_time_keys"_ls); } }; diff --git a/lib/e2ee/qolmsession.cpp b/lib/e2ee/qolmsession.cpp index 2b149aac..2a98d5d8 100644 --- a/lib/e2ee/qolmsession.cpp +++ b/lib/e2ee/qolmsession.cpp @@ -96,12 +96,13 @@ QOlmExpected<QOlmSessionPtr> QOlmSession::createOutboundSession( return std::make_unique<QOlmSession>(olmOutboundSession); } -QOlmExpected<QByteArray> QOlmSession::pickle(const PicklingMode &mode) +QOlmExpected<QByteArray> QOlmSession::pickle(const PicklingMode &mode) const { QByteArray pickledBuf(olm_pickle_session_length(m_session), '0'); QByteArray key = toKey(mode); const auto error = olm_pickle_session(m_session, key.data(), key.length(), - pickledBuf.data(), pickledBuf.length()); + pickledBuf.data(), + pickledBuf.length()); if (error == olm_error()) { return lastError(m_session); diff --git a/lib/e2ee/qolmsession.h b/lib/e2ee/qolmsession.h index faae16ef..021092c7 100644 --- a/lib/e2ee/qolmsession.h +++ b/lib/e2ee/qolmsession.h @@ -31,7 +31,7 @@ public: const QString& theirOneTimeKey); //! Serialises an `QOlmSession` to encrypted Base64. - QOlmExpected<QByteArray> pickle(const PicklingMode &mode); + QOlmExpected<QByteArray> pickle(const PicklingMode &mode) const; //! Deserialises from encrypted Base64 that was previously obtained by pickling a `QOlmSession`. static QOlmExpected<QOlmSessionPtr> unpickle( diff --git a/lib/events/roomkeyevent.h b/lib/events/roomkeyevent.h index 2bda3086..3093db41 100644 --- a/lib/events/roomkeyevent.h +++ b/lib/events/roomkeyevent.h @@ -12,7 +12,9 @@ public: DEFINE_EVENT_TYPEID("m.room_key", RoomKeyEvent) explicit RoomKeyEvent(const QJsonObject& obj); - explicit RoomKeyEvent(const QString& algorithm, const QString& roomId, const QString &sessionId, const QString& sessionKey, const QString& senderId); + explicit RoomKeyEvent(const QString& algorithm, const QString& roomId, + const QString& sessionId, const QString& sessionKey, + const QString& senderId); QString algorithm() const { return contentPart<QString>("algorithm"_ls); } QString roomId() const { return contentPart<QString>(RoomIdKeyL); } diff --git a/lib/room.cpp b/lib/room.cpp index 07d03467..6ec06aa8 100644 --- a/lib/room.cpp +++ b/lib/room.cpp @@ -457,28 +457,6 @@ public: addInboundGroupSession(currentOutboundMegolmSession->sessionId(), *sessionKey, q->localUser()->id(), "SELF"_ls); } - std::unique_ptr<EncryptedEvent> payloadForUserDevice(QString user, const QString& device, const QByteArray& sessionId, const QByteArray& sessionKey) - { - // Noisy but nice for debugging - //qCDebug(E2EE) << "Creating the payload for" << user->id() << device << sessionId << sessionKey.toHex(); - const auto event = makeEvent<RoomKeyEvent>("m.megolm.v1.aes-sha2", q->id(), sessionId, sessionKey, q->localUser()->id()); - QJsonObject payloadJson = event->fullJson(); - payloadJson["recipient"] = user; - payloadJson["sender"] = connection->user()->id(); - QJsonObject recipientObject; - recipientObject["ed25519"] = connection->edKeyForUserDevice(user, device); - payloadJson["recipient_keys"] = recipientObject; - QJsonObject senderObject; - senderObject["ed25519"] = QString(connection->olmAccount()->identityKeys().ed25519); - payloadJson["keys"] = senderObject; - payloadJson["sender_device"] = connection->deviceId(); - auto cipherText = connection->olmEncryptMessage(user, device, QJsonDocument(payloadJson).toJson(QJsonDocument::Compact)); - QJsonObject encrypted; - encrypted[connection->curveKeyForUserDevice(user, device)] = QJsonObject{{"type", cipherText.first}, {"body", QString(cipherText.second)}}; - - return makeEvent<EncryptedEvent>(encrypted, connection->olmAccount()->identityKeys().curve25519); - } - QMultiHash<QString, QString> getDevicesWithoutKey() const { QMultiHash<QString, QString> devices; @@ -490,91 +468,7 @@ public: id, devices, currentOutboundMegolmSession->sessionId()); } - bool createOlmSession(const QString& user, const QString& device, - const QJsonObject& oneTimeKeyObject) const - { - static QOlmUtility verifier; - qDebug(E2EE) << "Creating a new session for" << user << device; - if (oneTimeKeyObject.isEmpty()) { - qWarning(E2EE) << "No one time key for" << user << device; - return false; - } - const auto oneTimeKeyForId = *oneTimeKeyObject.constBegin(); - const auto signature = - oneTimeKeyForId["signatures"][user]["ed25519:"_ls % device] - .toString() - .toLatin1(); - auto signedObject = oneTimeKeyForId.toObject(); - signedObject.remove("unsigned"_ls); - signedObject.remove("signatures"_ls); - const auto signedData = - QJsonDocument(signedObject).toJson(QJsonDocument::Compact); - if (!verifier.ed25519Verify( - connection->edKeyForUserDevice(user, device).toLatin1(), - signedData, signature)) { - qWarning(E2EE) << "Failed to verify one-time-key signature for" - << user << device << ". Skipping this device."; - return false; - } - const auto recipientCurveKey = - connection->curveKeyForUserDevice(user, device); - connection->createOlmSession(recipientCurveKey, - oneTimeKeyForId["key"].toString()); - return true; - } - - void sendRoomKeyToDevices(const QByteArray& sessionId, - const QByteArray& sessionKey, - const QMultiHash<QString, QString>& devices, - int index) - { - qDebug(E2EE) << "Sending room key to devices:" << sessionId - << sessionKey.toHex(); - QHash<QString, QHash<QString, QString>> hash; - for (const auto& [userId, deviceId] : asKeyValueRange(devices)) - if (!connection->hasOlmSession(userId, deviceId)) { - hash[userId].insert(deviceId, "signed_curve25519"_ls); - qDebug(E2EE) - << "Adding" << userId << deviceId << "to keys to claim"; - } - - if (hash.isEmpty()) - return; - - auto job = connection->callApi<ClaimKeysJob>(hash); - connect(job, &BaseJob::success, q, - [job, this, sessionId, sessionKey, devices, index] { - Connection::UsersToDevicesToEvents usersToDevicesToEvents; - const auto data = job->jsonData(); - for (const auto& [user, device] : asKeyValueRange(devices)) { - if (!connection->hasOlmSession(user, device) - && !createOlmSession( - user, device, - data["one_time_keys"][user][device].toObject())) - continue; - - usersToDevicesToEvents[user][device] = - payloadForUserDevice(user, device, sessionId, - sessionKey); - } - if (!usersToDevicesToEvents.empty()) { - connection->sendToDevices("m.room.encrypted"_ls, - usersToDevicesToEvents); - QVector<std::tuple<QString, QString, QString>> receivedDevices; - receivedDevices.reserve(devices.size()); - for (const auto& [user, device] : asKeyValueRange(devices)) - receivedDevices.push_back( - { user, device, - connection->curveKeyForUserDevice(user, device) }); - - connection->database()->setDevicesReceivedKey(id, - receivedDevices, - sessionId, index); - } - }); - } - - void sendMegolmSession(const QMultiHash<QString, QString>& devices) { + void sendMegolmSession(const QMultiHash<QString, QString>& devices) const { // Save the session to this device const auto sessionId = currentOutboundMegolmSession->sessionId(); const auto sessionKey = currentOutboundMegolmSession->sessionKey(); @@ -584,8 +478,9 @@ public: } // Send the session to other people - sendRoomKeyToDevices(sessionId, *sessionKey, devices, - currentOutboundMegolmSession->sessionMessageIndex()); + connection->sendSessionKeyToDevices( + id, sessionId, *sessionKey, devices, + currentOutboundMegolmSession->sessionMessageIndex()); } #endif // Quotient_E2EE_ENABLED |