summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--include/timeline/TimelineView.h5
-rw-r--r--src/Olm.cpp2
-rw-r--r--src/timeline/TimelineView.cc138
3 files changed, 96 insertions, 49 deletions
diff --git a/include/timeline/TimelineView.h b/include/timeline/TimelineView.h
index a86c0286..bbe1dcad 100644
--- a/include/timeline/TimelineView.h
+++ b/include/timeline/TimelineView.h
@@ -195,10 +195,9 @@ private:
           const mtx::events::EncryptedEvent<mtx::events::msg::Encrypted> &e);
 
         void handleClaimedKeys(std::shared_ptr<StateKeeper> keeper,
-                               const std::string &room_key,
-                               const DevicePublicKeys &pks,
+                               const std::map<std::string, std::string> &room_key,
+                               const std::map<std::string, DevicePublicKeys> &pks,
                                const std::string &user_id,
-                               const std::string &device_id,
                                const mtx::responses::ClaimKeys &res,
                                mtx::http::RequestErr err);
 
diff --git a/src/Olm.cpp b/src/Olm.cpp
index c426968f..4d144a2d 100644
--- a/src/Olm.cpp
+++ b/src/Olm.cpp
@@ -6,6 +6,7 @@
 using namespace mtx::crypto;
 
 static const std::string STORAGE_SECRET_KEY("secret");
+constexpr auto MEGOLM_ALGO = "m.megolm.v1.aes-sha2";
 
 namespace {
 auto client_ = std::make_unique<mtx::crypto::OlmClient>();
@@ -142,6 +143,7 @@ encrypt_group_message(const std::string &room_id,
         data.sender_key = olm::client()->identity_keys().curve25519;
         data.session_id = res.data.session_id;
         data.device_id  = device_id;
+        data.algorithm  = MEGOLM_ALGO;
 
         auto message_index = olm_outbound_group_session_message_index(res.session);
         nhlog::crypto()->info("next message_index {}", message_index);
diff --git a/src/timeline/TimelineView.cc b/src/timeline/TimelineView.cc
index 9a69c58a..1a329594 100644
--- a/src/timeline/TimelineView.cc
+++ b/src/timeline/TimelineView.cc
@@ -185,7 +185,6 @@ TimelineView::sliderMoved(int position)
 
                 // Prevent user from moving up when there is pagination in
                 // progress.
-                // TODO: Keep a map of the event ids to filter out duplicates.
                 if (isPaginationInProgress_)
                         return;
 
@@ -1278,12 +1277,18 @@ TimelineView::prepareEncryptedMessage(const PendingMessage &msg)
                           }
 
                           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;
+
+                                  room_key_msgs.clear();
+                                  deviceKeys.clear();
+
                                   for (const auto &dev : user.second) {
                                           const auto user_id   = UserId(dev.second.user_id);
                                           const auto device_id = DeviceId(dev.second.device_id);
 
-                                          nhlog::net()->info("device_id {}", device_id.get());
-
                                           const auto device_keys = dev.second.keys;
                                           const auto curveKey    = "curve25519:" + device_id.get();
                                           const auto edKey       = "ed25519:" + device_id.get();
@@ -1300,12 +1305,6 @@ TimelineView::prepareEncryptedMessage(const PendingMessage &msg)
                                           pks.ed25519    = device_keys.at(edKey);
                                           pks.curve25519 = device_keys.at(curveKey);
 
-                                          // Validate signatures
-                                          for (const auto &algo : dev.second.keys) {
-                                                  nhlog::net()->info(
-                                                    "dev keys {} {}", algo.first, algo.second);
-                                          }
-
                                           try {
                                                   if (!mtx::crypto::verify_identity_signature(
                                                         json(dev.second), device_id, user_id)) {
@@ -1319,6 +1318,11 @@ TimelineView::prepareEncryptedMessage(const PendingMessage &msg)
                                                     "failed to parse device key json: {}",
                                                     e.what());
                                                   continue;
+                                          } catch (const mtx::crypto::olm_exception &e) {
+                                                  nhlog::crypto()->warn(
+                                                    "failed to verify device key json: {}",
+                                                    e.what());
+                                                  continue;
                                           }
 
                                           auto room_key = olm::client()
@@ -1326,19 +1330,41 @@ TimelineView::prepareEncryptedMessage(const PendingMessage &msg)
                                                               user_id, pks.ed25519, megolm_payload)
                                                             .dump();
 
-                                          http::v2::client()->claim_keys(
-                                            user_id,
-                                            {device_id},
-                                            std::bind(&TimelineView::handleClaimedKeys,
-                                                      this,
-                                                      keeper,
-                                                      room_key,
-                                                      pks,
-                                                      user_id,
-                                                      device_id,
-                                                      std::placeholders::_1,
-                                                      std::placeholders::_2));
+                                          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);
+
+                                          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(
+                                    "sending claim request for user {} with {} devices",
+                                    user.first,
+                                    valid_devices.size());
+
+                                  http::v2::client()->claim_keys(
+                                    user.first,
+                                    valid_devices,
+                                    std::bind(&TimelineView::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));
                           }
                   });
 
@@ -1354,44 +1380,62 @@ TimelineView::prepareEncryptedMessage(const PendingMessage &msg)
 
 void
 TimelineView::handleClaimedKeys(std::shared_ptr<StateKeeper> keeper,
-                                const std::string &room_key,
-                                const DevicePublicKeys &pks,
+                                const std::map<std::string, std::string> &room_keys,
+                                const std::map<std::string, DevicePublicKeys> &pks,
                                 const std::string &user_id,
-                                const std::string &device_id,
                                 const mtx::responses::ClaimKeys &res,
                                 mtx::http::RequestErr err)
 {
         if (err) {
-                nhlog::net()->warn("claim keys error: {}", err->matrix_error.error);
+                nhlog::net()->warn("claim keys error: {} {} {}",
+                                   err->matrix_error.error,
+                                   err->parse_error,
+                                   static_cast<int>(err->status_code));
                 return;
         }
 
-        nhlog::net()->info("claimed keys for {} - {}", user_id, device_id);
+        nhlog::net()->info("claimed keys for {}", user_id);
 
         if (res.one_time_keys.size() == 0) {
-                nhlog::net()->info("no one-time keys found for device_id: {}", device_id);
+                nhlog::net()->info("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()->info(
-                  "no one-time keys found in device_id {} for the user {}", device_id, user_id);
+                nhlog::net()->info("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();
+
         for (const auto &rd : retrieved_devices) {
-                nhlog::net()->info("{} : \n {}", rd.first, rd.second.dump(2));
+                const auto device_id = rd.first;
+                nhlog::net()->info("{} : \n {}", device_id, rd.second.dump(2));
 
                 // TODO: Verify signatures
-                auto otk    = rd.second.begin()->at("key");
-                auto id_key = pks.curve25519;
+                auto otk = rd.second.begin()->at("key");
+
+                if (pks.find(device_id) == pks.end()) {
+                        nhlog::net()->critical("couldn't find public key for device: {}",
+                                               device_id);
+                        continue;
+                }
 
-                auto s = olm::client()->create_outbound_session(id_key, otk);
+                auto id_key = pks.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_key, pks.curve25519);
+                if (room_keys.find(device_id) == room_keys.end()) {
+                        nhlog::net()->critical("couldn't find m.room_key for device: {}",
+                                               device_id);
+                        continue;
+                }
+
+                auto device_msg = olm::client()->create_olm_encrypted_content(
+                  s.get(), room_keys.at(device_id), pks.at(device_id).curve25519);
 
                 try {
                         cache::client()->saveOlmSession(id_key, std::move(s));
@@ -1402,16 +1446,18 @@ TimelineView::handleClaimedKeys(std::shared_ptr<StateKeeper> keeper,
                                                   e.what());
                 }
 
-                json body{{"messages", {{user_id, {{device_id, device_msg}}}}}};
-
-                http::v2::client()->send_to_device(
-                  "m.room.encrypted", body, [keeper](mtx::http::RequestErr err) {
-                          if (err) {
-                                  nhlog::net()->warn("failed to send "
-                                                     "send_to_device "
-                                                     "message: {}",
-                                                     err->matrix_error.error);
-                          }
-                  });
+                body["messages"][user_id][device_id] = device_msg;
         }
+
+        nhlog::net()->info("send_to_device: {}", user_id);
+
+        http::v2::client()->send_to_device(
+          "m.room.encrypted", body, [keeper](mtx::http::RequestErr err) {
+                  if (err) {
+                          nhlog::net()->warn("failed to send "
+                                             "send_to_device "
+                                             "message: {}",
+                                             err->matrix_error.error);
+                  }
+          });
 }