summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Cache.cpp38
-rw-r--r--src/ChatPage.cpp11
-rw-r--r--src/Olm.cpp6
-rw-r--r--src/timeline/.TimelineModel.cpp.swnbin0 -> 237568 bytes
-rw-r--r--src/timeline/EventStore.cpp148
-rw-r--r--src/timeline/TimelineModel.cpp204
-rw-r--r--src/timeline/TimelineModel.h12
7 files changed, 207 insertions, 212 deletions
diff --git a/src/Cache.cpp b/src/Cache.cpp
index 5302218a..07d01819 100644
--- a/src/Cache.cpp
+++ b/src/Cache.cpp
@@ -139,24 +139,26 @@ Cache::Cache(const QString &userId, QObject *parent)
   , localUserId_{userId}
 {
         setup();
-        connect(this,
-                &Cache::updateUserCacheFlag,
-                this,
-                [this](const std::string &user_id) {
-                        std::optional<UserCache> cache_ = getUserCache(user_id);
-                        if (cache_.has_value()) {
-                                cache_.value().isUpdated = false;
-                                setUserCache(user_id, cache_.value());
-                        } else {
-                                setUserCache(user_id, UserCache{});
-                        }
-                },
-                Qt::QueuedConnection);
-        connect(this,
-                &Cache::deleteLeftUsers,
-                this,
-                [this](const std::string &user_id) { deleteUserCache(user_id); },
-                Qt::QueuedConnection);
+        connect(
+          this,
+          &Cache::updateUserCacheFlag,
+          this,
+          [this](const std::string &user_id) {
+                  std::optional<UserCache> cache_ = getUserCache(user_id);
+                  if (cache_.has_value()) {
+                          cache_.value().isUpdated = false;
+                          setUserCache(user_id, cache_.value());
+                  } else {
+                          setUserCache(user_id, UserCache{});
+                  }
+          },
+          Qt::QueuedConnection);
+        connect(
+          this,
+          &Cache::deleteLeftUsers,
+          this,
+          [this](const std::string &user_id) { deleteUserCache(user_id); },
+          Qt::QueuedConnection);
 }
 
 void
diff --git a/src/ChatPage.cpp b/src/ChatPage.cpp
index 31ba38d7..704543b5 100644
--- a/src/ChatPage.cpp
+++ b/src/ChatPage.cpp
@@ -606,11 +606,12 @@ ChatPage::ChatPage(QSharedPointer<UserSettings> userSettings, QWidget *parent)
         connect(
           this, &ChatPage::tryInitialSyncCb, this, &ChatPage::tryInitialSync, Qt::QueuedConnection);
         connect(this, &ChatPage::trySyncCb, this, &ChatPage::trySync, Qt::QueuedConnection);
-        connect(this,
-                &ChatPage::tryDelayedSyncCb,
-                this,
-                [this]() { QTimer::singleShot(RETRY_TIMEOUT, this, &ChatPage::trySync); },
-                Qt::QueuedConnection);
+        connect(
+          this,
+          &ChatPage::tryDelayedSyncCb,
+          this,
+          [this]() { QTimer::singleShot(RETRY_TIMEOUT, this, &ChatPage::trySync); },
+          Qt::QueuedConnection);
 
         connect(this,
                 &ChatPage::newSyncResponse,
diff --git a/src/Olm.cpp b/src/Olm.cpp
index 9e997801..4f0c5893 100644
--- a/src/Olm.cpp
+++ b/src/Olm.cpp
@@ -581,9 +581,11 @@ send_megolm_key_to_device(const std::string &user_id,
                                     ->create_room_key_event(UserId(user_id), pks.ed25519, payload)
                                     .dump();
 
+                  mtx::requests::ClaimKeys claim_keys;
+                  claim_keys.one_time_keys[user_id][device_id] = mtx::crypto::SIGNED_CURVE25519;
+
                   http::client()->claim_keys(
-                    user_id,
-                    {device_id},
+                    claim_keys,
                     [room_key, user_id, device_id, pks](const mtx::responses::ClaimKeys &res,
                                                         mtx::http::RequestErr err) {
                             if (err) {
diff --git a/src/timeline/.TimelineModel.cpp.swn b/src/timeline/.TimelineModel.cpp.swn
new file mode 100644
index 00000000..9e965702
--- /dev/null
+++ b/src/timeline/.TimelineModel.cpp.swn
Binary files differdiff --git a/src/timeline/EventStore.cpp b/src/timeline/EventStore.cpp
index 66a6d799..af1f7b23 100644
--- a/src/timeline/EventStore.cpp
+++ b/src/timeline/EventStore.cpp
@@ -32,38 +32,40 @@ EventStore::EventStore(std::string room_id, QObject *)
                 this->last  = range->last;
         }
 
-        connect(this,
-                &EventStore::eventFetched,
-                this,
-                [this](std::string id,
-                       std::string relatedTo,
-                       mtx::events::collections::TimelineEvents timeline) {
-                        cache::client()->storeEvent(room_id_, id, {timeline});
-
-                        if (!relatedTo.empty()) {
-                                auto idx = idToIndex(relatedTo);
-                                if (idx)
-                                        emit dataChanged(*idx, *idx);
-                        }
-                },
-                Qt::QueuedConnection);
-
-        connect(this,
-                &EventStore::oldMessagesRetrieved,
-                this,
-                [this](const mtx::responses::Messages &res) {
-                        uint64_t newFirst = cache::client()->saveOldMessages(room_id_, res);
-                        if (newFirst == first)
-                                fetchMore();
-                        else {
-                                emit beginInsertRows(toExternalIdx(newFirst),
-                                                     toExternalIdx(this->first - 1));
-                                this->first = newFirst;
-                                emit endInsertRows();
-                                emit fetchedMore();
-                        }
-                },
-                Qt::QueuedConnection);
+        connect(
+          this,
+          &EventStore::eventFetched,
+          this,
+          [this](std::string id,
+                 std::string relatedTo,
+                 mtx::events::collections::TimelineEvents timeline) {
+                  cache::client()->storeEvent(room_id_, id, {timeline});
+
+                  if (!relatedTo.empty()) {
+                          auto idx = idToIndex(relatedTo);
+                          if (idx)
+                                  emit dataChanged(*idx, *idx);
+                  }
+          },
+          Qt::QueuedConnection);
+
+        connect(
+          this,
+          &EventStore::oldMessagesRetrieved,
+          this,
+          [this](const mtx::responses::Messages &res) {
+                  uint64_t newFirst = cache::client()->saveOldMessages(room_id_, res);
+                  if (newFirst == first)
+                          fetchMore();
+                  else {
+                          emit beginInsertRows(toExternalIdx(newFirst),
+                                               toExternalIdx(this->first - 1));
+                          this->first = newFirst;
+                          emit endInsertRows();
+                          emit fetchedMore();
+                  }
+          },
+          Qt::QueuedConnection);
 
         connect(this, &EventStore::processPending, this, [this]() {
                 if (!current_txn.empty()) {
@@ -128,46 +130,48 @@ EventStore::EventStore(std::string room_id, QObject *)
                   event->data);
         });
 
-        connect(this,
-                &EventStore::messageFailed,
-                this,
-                [this](std::string txn_id) {
-                        if (current_txn == txn_id) {
-                                current_txn_error_count++;
-                                if (current_txn_error_count > 10) {
-                                        nhlog::ui()->debug("failing txn id '{}'", txn_id);
-                                        cache::client()->removePendingStatus(room_id_, txn_id);
-                                        current_txn_error_count = 0;
-                                }
-                        }
-                        QTimer::singleShot(1000, this, [this]() {
-                                nhlog::ui()->debug("timeout");
-                                this->current_txn = "";
-                                emit processPending();
-                        });
-                },
-                Qt::QueuedConnection);
-
-        connect(this,
-                &EventStore::messageSent,
-                this,
-                [this](std::string txn_id, std::string event_id) {
-                        nhlog::ui()->debug("sent {}", txn_id);
-
-                        http::client()->read_event(
-                          room_id_, event_id, [this, event_id](mtx::http::RequestErr err) {
-                                  if (err) {
-                                          nhlog::net()->warn(
-                                            "failed to read_event ({}, {})", room_id_, event_id);
-                                  }
-                          });
-
-                        cache::client()->removePendingStatus(room_id_, txn_id);
-                        this->current_txn             = "";
-                        this->current_txn_error_count = 0;
-                        emit processPending();
-                },
-                Qt::QueuedConnection);
+        connect(
+          this,
+          &EventStore::messageFailed,
+          this,
+          [this](std::string txn_id) {
+                  if (current_txn == txn_id) {
+                          current_txn_error_count++;
+                          if (current_txn_error_count > 10) {
+                                  nhlog::ui()->debug("failing txn id '{}'", txn_id);
+                                  cache::client()->removePendingStatus(room_id_, txn_id);
+                                  current_txn_error_count = 0;
+                          }
+                  }
+                  QTimer::singleShot(1000, this, [this]() {
+                          nhlog::ui()->debug("timeout");
+                          this->current_txn = "";
+                          emit processPending();
+                  });
+          },
+          Qt::QueuedConnection);
+
+        connect(
+          this,
+          &EventStore::messageSent,
+          this,
+          [this](std::string txn_id, std::string event_id) {
+                  nhlog::ui()->debug("sent {}", txn_id);
+
+                  http::client()->read_event(
+                    room_id_, event_id, [this, event_id](mtx::http::RequestErr err) {
+                            if (err) {
+                                    nhlog::net()->warn(
+                                      "failed to read_event ({}, {})", room_id_, event_id);
+                            }
+                    });
+
+                  cache::client()->removePendingStatus(room_id_, txn_id);
+                  this->current_txn             = "";
+                  this->current_txn_error_count = 0;
+                  emit processPending();
+          },
+          Qt::QueuedConnection);
 }
 
 void
diff --git a/src/timeline/TimelineModel.cpp b/src/timeline/TimelineModel.cpp
index 8f0e470e..ddd238b9 100644
--- a/src/timeline/TimelineModel.cpp
+++ b/src/timeline/TimelineModel.cpp
@@ -204,11 +204,12 @@ TimelineModel::TimelineModel(TimelineViewManager *manager, QString room_id, QObj
   , room_id_(room_id)
   , manager_(manager)
 {
-        connect(this,
-                &TimelineModel::redactionFailed,
-                this,
-                [](const QString &msg) { emit ChatPage::instance()->showNotification(msg); },
-                Qt::QueuedConnection);
+        connect(
+          this,
+          &TimelineModel::redactionFailed,
+          this,
+          [](const QString &msg) { emit ChatPage::instance()->showNotification(msg); },
+          Qt::QueuedConnection);
 
         connect(this,
                 &TimelineModel::newMessageToSend,
@@ -217,17 +218,17 @@ TimelineModel::TimelineModel(TimelineViewManager *manager, QString room_id, QObj
                 Qt::QueuedConnection);
         connect(this, &TimelineModel::addPendingMessageToStore, &events, &EventStore::addPending);
 
-        connect(&events,
-                &EventStore::dataChanged,
-                this,
-                [this](int from, int to) {
-                        nhlog::ui()->debug("data changed {} to {}",
-                                           events.size() - to - 1,
-                                           events.size() - from - 1);
-                        emit dataChanged(index(events.size() - to - 1, 0),
-                                         index(events.size() - from - 1, 0));
-                },
-                Qt::QueuedConnection);
+        connect(
+          &events,
+          &EventStore::dataChanged,
+          this,
+          [this](int from, int to) {
+                  nhlog::ui()->debug(
+                    "data changed {} to {}", events.size() - to - 1, events.size() - from - 1);
+                  emit dataChanged(index(events.size() - to - 1, 0),
+                                   index(events.size() - from - 1, 0));
+          },
+          Qt::QueuedConnection);
 
         connect(&events, &EventStore::beginInsertRows, this, [this](int from, int to) {
                 int first = events.size() - to;
@@ -916,10 +917,20 @@ TimelineModel::sendEncryptedMessage(mtx::events::RoomEvent<T> msg, mtx::events::
                 OutboundGroupSessionData session_data;
                 session_data.session_id    = session_id;
                 session_data.session_key   = session_key;
-                session_data.message_index = 0; // TODO Update me
+                session_data.message_index = 0;
                 cache::saveOutboundMegolmSession(
                   room_id, session_data, std::move(outbound_session));
 
+                {
+                        MegolmSessionIndex index;
+                        index.room_id    = room_id;
+                        index.session_id = session_id;
+                        index.sender_key = olm::client()->identity_keys().curve25519;
+                        auto megolm_session =
+                          olm::client()->init_inbound_group_session(session_key);
+                        cache::saveInboundMegolmSession(index, std::move(megolm_session));
+                }
+
                 const auto members = cache::roomMembers(room_id);
                 nhlog::ui()->info("retrieved {} members for {}", members.size(), room_id);
 
@@ -961,19 +972,23 @@ TimelineModel::sendEncryptedMessage(mtx::events::RoomEvent<T> msg, mtx::events::
                                   return;
                           }
 
-                          for (const auto &user : res.device_keys) {
-                                  // Mapping from a device_id with valid identity keys to the
-                                  // generated room_key event used for sharing the megolm session.
-                                  std::map<std::string, std::string> room_key_msgs;
-                                  std::map<std::string, DevicePublicKeys> deviceKeys;
+                          mtx::requests::ClaimKeys claim_keys;
 
-                                  room_key_msgs.clear();
-                                  deviceKeys.clear();
+                          // Mapping from user id to a device_id with valid identity keys to the
+                          // generated room_key event used for sharing the megolm session.
+                          std::map<std::string, std::map<std::string, std::string>> room_key_msgs;
+                          std::map<std::string, std::map<std::string, DevicePublicKeys>> deviceKeys;
 
+                          for (const auto &user : res.device_keys) {
                                   for (const auto &dev : user.second) {
                                           const auto user_id   = ::UserId(dev.second.user_id);
                                           const auto device_id = DeviceId(dev.second.device_id);
 
+                                          if (user_id.get() ==
+                                                http::client()->user_id().to_string() &&
+                                              device_id.get() == http::client()->device_id())
+                                                  continue;
+
                                           const auto device_keys = dev.second.keys;
                                           const auto curveKey    = "curve25519:" + device_id.get();
                                           const auto edKey       = "ed25519:" + device_id.get();
@@ -1015,42 +1030,25 @@ TimelineModel::sendEncryptedMessage(mtx::events::RoomEvent<T> msg, mtx::events::
                                                               user_id, pks.ed25519, megolm_payload)
                                                             .dump();
 
-                                          room_key_msgs.emplace(device_id, room_key);
-                                          deviceKeys.emplace(device_id, pks);
-                                  }
-
-                                  std::vector<std::string> valid_devices;
-                                  valid_devices.reserve(room_key_msgs.size());
-                                  for (auto const &d : room_key_msgs) {
-                                          valid_devices.push_back(d.first);
+                                          room_key_msgs[user_id].emplace(device_id, room_key);
+                                          deviceKeys[user_id].emplace(device_id, pks);
+                                          claim_keys.one_time_keys[user.first][device_id] =
+                                            mtx::crypto::SIGNED_CURVE25519;
 
-                                          nhlog::net()->info("{}", d.first);
-                                          nhlog::net()->info("  curve25519 {}",
-                                                             deviceKeys.at(d.first).curve25519);
-                                          nhlog::net()->info("  ed25519 {}",
-                                                             deviceKeys.at(d.first).ed25519);
+                                          nhlog::net()->info("{}", device_id.get());
+                                          nhlog::net()->info("  curve25519 {}", pks.curve25519);
+                                          nhlog::net()->info("  ed25519 {}", pks.ed25519);
                                   }
-
-                                  nhlog::net()->info(
-                                    "sending claim request for user {} with {} devices",
-                                    user.first,
-                                    valid_devices.size());
-
-                                  http::client()->claim_keys(
-                                    user.first,
-                                    valid_devices,
-                                    std::bind(&TimelineModel::handleClaimedKeys,
-                                              this,
-                                              keeper,
-                                              room_key_msgs,
-                                              deviceKeys,
-                                              user.first,
-                                              std::placeholders::_1,
-                                              std::placeholders::_2));
-
-                                  // TODO: Wait before sending the next batch of requests.
-                                  std::this_thread::sleep_for(std::chrono::milliseconds(500));
                           }
+
+                          http::client()->claim_keys(claim_keys,
+                                                     std::bind(&TimelineModel::handleClaimedKeys,
+                                                               this,
+                                                               keeper,
+                                                               room_key_msgs,
+                                                               deviceKeys,
+                                                               std::placeholders::_1,
+                                                               std::placeholders::_2));
                   });
 
                 // TODO: Let the user know about the errors.
@@ -1068,12 +1066,12 @@ TimelineModel::sendEncryptedMessage(mtx::events::RoomEvent<T> msg, mtx::events::
 }
 
 void
-TimelineModel::handleClaimedKeys(std::shared_ptr<StateKeeper> keeper,
-                                 const std::map<std::string, std::string> &room_keys,
-                                 const std::map<std::string, DevicePublicKeys> &pks,
-                                 const std::string &user_id,
-                                 const mtx::responses::ClaimKeys &res,
-                                 mtx::http::RequestErr err)
+TimelineModel::handleClaimedKeys(
+  std::shared_ptr<StateKeeper> keeper,
+  const std::map<std::string, std::map<std::string, std::string>> &room_keys,
+  const std::map<std::string, std::map<std::string, DevicePublicKeys>> &pks,
+  const mtx::responses::ClaimKeys &res,
+  mtx::http::RequestErr err)
 {
         if (err) {
                 nhlog::net()->warn("claim keys error: {} {} {}",
@@ -1083,65 +1081,53 @@ TimelineModel::handleClaimedKeys(std::shared_ptr<StateKeeper> keeper,
                 return;
         }
 
-        nhlog::net()->debug("claimed keys for {}", user_id);
-
-        if (res.one_time_keys.size() == 0) {
-                nhlog::net()->debug("no one-time keys found for user_id: {}", user_id);
-                return;
-        }
-
-        if (res.one_time_keys.find(user_id) == res.one_time_keys.end()) {
-                nhlog::net()->debug("no one-time keys found for user_id: {}", user_id);
-                return;
-        }
-
-        auto retrieved_devices = res.one_time_keys.at(user_id);
-
         // Payload with all the to_device message to be sent.
-        json body;
-        body["messages"][user_id] = json::object();
+        nlohmann::json body;
 
-        for (const auto &rd : retrieved_devices) {
-                const auto device_id = rd.first;
-                nhlog::net()->debug("{} : \n {}", device_id, rd.second.dump(2));
+        for (const auto &[user_id, retrieved_devices] : res.one_time_keys) {
+                nhlog::net()->debug("claimed keys for {}", user_id);
+                if (retrieved_devices.size() == 0) {
+                        nhlog::net()->debug("no one-time keys found for user_id: {}", user_id);
+                        return;
+                }
 
-                // TODO: Verify signatures
-                auto otk = rd.second.begin()->at("key");
+                for (const auto &rd : retrieved_devices) {
+                        const auto device_id = rd.first;
 
-                if (pks.find(device_id) == pks.end()) {
-                        nhlog::net()->critical("couldn't find public key for device: {}",
-                                               device_id);
-                        continue;
-                }
+                        nhlog::net()->debug("{} : \n {}", device_id, rd.second.dump(2));
 
-                auto id_key = pks.at(device_id).curve25519;
-                auto s      = olm::client()->create_outbound_session(id_key, otk);
+                        // TODO: Verify signatures
+                        auto otk = rd.second.begin()->at("key");
 
-                if (room_keys.find(device_id) == room_keys.end()) {
-                        nhlog::net()->critical("couldn't find m.room_key for device: {}",
-                                               device_id);
-                        continue;
-                }
+                        auto id_key = pks.at(user_id).at(device_id).curve25519;
+                        auto s      = olm::client()->create_outbound_session(id_key, otk);
+
+                        auto device_msg = olm::client()->create_olm_encrypted_content(
+                          s.get(),
+                          room_keys.at(user_id).at(device_id),
+                          pks.at(user_id).at(device_id).curve25519);
 
-                auto device_msg = olm::client()->create_olm_encrypted_content(
-                  s.get(), room_keys.at(device_id), pks.at(device_id).curve25519);
+                        try {
+                                cache::saveOlmSession(id_key, std::move(s));
+                        } catch (const lmdb::error &e) {
+                                nhlog::db()->critical("failed to save outbound olm session: {}",
+                                                      e.what());
+                        } catch (const mtx::crypto::olm_exception &e) {
+                                nhlog::crypto()->critical(
+                                  "failed to pickle outbound olm session: {}", e.what());
+                        }
 
-                try {
-                        cache::saveOlmSession(id_key, std::move(s));
-                } catch (const lmdb::error &e) {
-                        nhlog::db()->critical("failed to save outbound olm session: {}", e.what());
-                } catch (const mtx::crypto::olm_exception &e) {
-                        nhlog::crypto()->critical("failed to pickle outbound olm session: {}",
-                                                  e.what());
+                        body["messages"][user_id][device_id] = device_msg;
                 }
 
-                body["messages"][user_id][device_id] = device_msg;
+                nhlog::net()->info("send_to_device: {}", user_id);
         }
 
-        nhlog::net()->info("send_to_device: {}", user_id);
-
         http::client()->send_to_device(
-          "m.room.encrypted", body, [keeper](mtx::http::RequestErr err) {
+          mtx::events::to_string(mtx::events::EventType::RoomEncrypted),
+          http::client()->generate_txn_id(),
+          body,
+          [keeper](mtx::http::RequestErr err) {
                   if (err) {
                           nhlog::net()->warn("failed to send "
                                              "send_to_device "
diff --git a/src/timeline/TimelineModel.h b/src/timeline/TimelineModel.h
index 390fa1ed..61d00df9 100644
--- a/src/timeline/TimelineModel.h
+++ b/src/timeline/TimelineModel.h
@@ -285,12 +285,12 @@ signals:
 private:
         template<typename T>
         void sendEncryptedMessage(mtx::events::RoomEvent<T> msg, mtx::events::EventType eventType);
-        void handleClaimedKeys(std::shared_ptr<StateKeeper> keeper,
-                               const std::map<std::string, std::string> &room_key,
-                               const std::map<std::string, DevicePublicKeys> &pks,
-                               const std::string &user_id,
-                               const mtx::responses::ClaimKeys &res,
-                               mtx::http::RequestErr err);
+        void handleClaimedKeys(
+          std::shared_ptr<StateKeeper> keeper,
+          const std::map<std::string, std::map<std::string, std::string>> &room_keys,
+          const std::map<std::string, std::map<std::string, DevicePublicKeys>> &pks,
+          const mtx::responses::ClaimKeys &res,
+          mtx::http::RequestErr err);
         void readEvent(const std::string &id);
 
         void setPaginationInProgress(const bool paginationInProgress);