summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/Cache.cpp44
-rw-r--r--src/UserSettingsPage.cpp3
-rw-r--r--src/encryption/Olm.cpp67
-rw-r--r--src/encryption/Olm.h2
-rw-r--r--src/timeline/EventStore.cpp1
5 files changed, 113 insertions, 4 deletions
diff --git a/src/Cache.cpp b/src/Cache.cpp
index 7284ffaa..cc8516ad 100644
--- a/src/Cache.cpp
+++ b/src/Cache.cpp
@@ -635,6 +635,9 @@ Cache::exportSessionKeys()
 void
 Cache::importSessionKeys(const mtx::crypto::ExportedSessionKeys &keys)
 {
+    std::size_t importCount = 0;
+
+    auto txn = lmdb::txn::begin(env_);
     for (const auto &s : keys.sessions) {
         MegolmSessionIndex index;
         index.room_id    = s.room_id;
@@ -643,14 +646,49 @@ Cache::importSessionKeys(const mtx::crypto::ExportedSessionKeys &keys)
         GroupSessionData data{};
         data.sender_key                      = s.sender_key;
         data.forwarding_curve25519_key_chain = s.forwarding_curve25519_key_chain;
+        data.trusted                         = false;
+
         if (s.sender_claimed_keys.count("ed25519"))
             data.sender_claimed_ed25519_key = s.sender_claimed_keys.at("ed25519");
 
-        auto exported_session = mtx::crypto::import_session(s.session_key);
+        try {
+            auto exported_session = mtx::crypto::import_session(s.session_key);
+
+            using namespace mtx::crypto;
+            const auto key = nlohmann::json(index).dump();
+            const auto pickled =
+              pickle<InboundSessionObject>(exported_session.get(), pickle_secret_);
+
+            std::string_view value;
+            if (inboundMegolmSessionDb_.get(txn, key, value)) {
+                auto oldSession =
+                  unpickle<InboundSessionObject>(std::string(value), pickle_secret_);
+                if (olm_inbound_group_session_first_known_index(exported_session.get()) >=
+                    olm_inbound_group_session_first_known_index(oldSession.get())) {
+                    nhlog::crypto()->warn(
+                      "Not storing inbound session with newer or equal first known index");
+                    continue;
+                }
+            }
+
+            inboundMegolmSessionDb_.put(txn, key, pickled);
+            megolmSessionDataDb_.put(txn, key, nlohmann::json(data).dump());
 
-        saveInboundMegolmSession(index, std::move(exported_session), data);
-        ChatPage::instance()->receivedSessionKey(index.room_id, index.session_id);
+            ChatPage::instance()->receivedSessionKey(index.room_id, index.session_id);
+            importCount++;
+        } catch (const mtx::crypto::olm_exception &e) {
+            nhlog::crypto()->critical(
+              "failed to import inbound megolm session {}: {}", index.session_id, e.what());
+            continue;
+        } catch (const lmdb::error &e) {
+            nhlog::crypto()->critical(
+              "failed to save inbound megolm session {}: {}", index.session_id, e.what());
+            continue;
+        }
     }
+    txn.commit();
+
+    nhlog::crypto()->info("Imported {} out of {} keys", importCount, keys.sessions.size());
 }
 
 //
diff --git a/src/UserSettingsPage.cpp b/src/UserSettingsPage.cpp
index dc8e87fc..666a03b4 100644
--- a/src/UserSettingsPage.cpp
+++ b/src/UserSettingsPage.cpp
@@ -548,6 +548,9 @@ UserSettings::setUseOnlineKeyBackup(bool useBackup)
     useOnlineKeyBackup_ = useBackup;
     emit useOnlineKeyBackupChanged(useBackup);
     save();
+
+    if (useBackup)
+        olm::download_full_keybackup();
 }
 
 void
diff --git a/src/encryption/Olm.cpp b/src/encryption/Olm.cpp
index 8bf2222f..ed84a275 100644
--- a/src/encryption/Olm.cpp
+++ b/src/encryption/Olm.cpp
@@ -874,6 +874,73 @@ mark_keys_as_published()
 }
 
 void
+download_full_keybackup()
+{
+    if (!UserSettings::instance()->useOnlineKeyBackup()) {
+        // Online key backup disabled
+        return;
+    }
+
+    auto backupVersion = cache::client()->backupVersion();
+    if (!backupVersion) {
+        // no trusted OKB
+        return;
+    }
+
+    using namespace mtx::crypto;
+
+    auto decryptedSecret = cache::secret(mtx::secret_storage::secrets::megolm_backup_v1);
+    if (!decryptedSecret) {
+        // no backup key available
+        return;
+    }
+    auto sessionDecryptionKey = to_binary_buf(base642bin(*decryptedSecret));
+
+    http::client()->room_keys(
+      backupVersion->version,
+      [sessionDecryptionKey](const mtx::responses::backup::KeysBackup &bk,
+                             mtx::http::RequestErr err) {
+          if (err) {
+              if (err->status_code != 404)
+                  nhlog::crypto()->error("Failed to dowload backup {}:{}: {} - {}",
+                                         mtx::errors::to_string(err->matrix_error.errcode),
+                                         err->matrix_error.error);
+              return;
+          }
+
+          mtx::crypto::ExportedSessionKeys allKeys;
+          try {
+              for (const auto &[room, roomKey] : bk.rooms) {
+                  for (const auto &[session_id, encSession] : roomKey.sessions) {
+                      auto session = decrypt_session(encSession.session_data, sessionDecryptionKey);
+
+                      if (session.algorithm != mtx::crypto::MEGOLM_ALGO)
+                          // don't know this algorithm
+                          return;
+
+                      ExportedSession sess{};
+                      sess.session_id = session_id;
+                      sess.room_id    = room;
+                      sess.algorithm  = mtx::crypto::MEGOLM_ALGO;
+                      sess.forwarding_curve25519_key_chain =
+                        std::move(session.forwarding_curve25519_key_chain);
+                      sess.sender_claimed_keys = std::move(session.sender_claimed_keys);
+                      sess.sender_key          = std::move(session.sender_key);
+                      sess.session_key         = std::move(session.session_key);
+                      allKeys.sessions.push_back(std::move(sess));
+                  }
+              }
+
+              // call on UI thread
+              QTimer::singleShot(0, ChatPage::instance(), [keys = std::move(allKeys)] {
+                  cache::importSessionKeys(keys);
+              });
+          } catch (const lmdb::error &e) {
+              nhlog::crypto()->critical("failed to save inbound megolm session: {}", e.what());
+          }
+      });
+}
+void
 lookup_keybackup(const std::string room, const std::string session_id)
 {
     if (!UserSettings::instance()->useOnlineKeyBackup()) {
diff --git a/src/encryption/Olm.h b/src/encryption/Olm.h
index 9d99bcf4..1189fffa 100644
--- a/src/encryption/Olm.h
+++ b/src/encryption/Olm.h
@@ -73,6 +73,8 @@ import_inbound_megolm_session(
   const mtx::events::DeviceEvent<mtx::events::msg::ForwardedRoomKey> &roomKey);
 void
 lookup_keybackup(const std::string room, const std::string session_id);
+void
+download_full_keybackup();
 
 nlohmann::json
 handle_pre_key_olm_message(const std::string &sender,
diff --git a/src/timeline/EventStore.cpp b/src/timeline/EventStore.cpp
index 122a6f8e..019cf78b 100644
--- a/src/timeline/EventStore.cpp
+++ b/src/timeline/EventStore.cpp
@@ -754,7 +754,6 @@ EventStore::requestSession(const mtx::events::EncryptedEvent<mtx::events::msg::E
     if (suppressKeyRequests)
         return;
 
-    // TODO: Look in key backup
     auto copy    = ev;
     copy.room_id = room_id_;
     if (pending_key_requests.count(ev.content.session_id)) {