From 9825f1bbd049e818a0b8b06aeae3375909bafad6 Mon Sep 17 00:00:00 2001
From: Nicolas Werner <nicolas.werner@hotmail.de>
Date: Tue, 15 Dec 2020 15:48:33 +0100
Subject: [PATCH] Send SSSS requests

---
 src/Olm.cpp              | 80 ++++++++++++++++++++++++++++++++++++++++
 src/Olm.h                |  7 ++++
 src/UserSettingsPage.cpp | 17 +++++++++
 3 files changed, 104 insertions(+)

diff --git a/src/Olm.cpp b/src/Olm.cpp
index 1f58758c1..2b7382c9a 100644
--- a/src/Olm.cpp
+++ b/src/Olm.cpp
@@ -1,9 +1,13 @@
 #include "Olm.h"
 
 #include <QObject>
+#include <QTimer>
+
 #include <nlohmann/json.hpp>
 #include <variant>
 
+#include <mtx/secret_storage.hpp>
+
 #include "Cache.h"
 #include "Cache_p.h"
 #include "ChatPage.h"
@@ -18,6 +22,8 @@ constexpr auto MEGOLM_ALGO = "m.megolm.v1.aes-sha2";
 
 namespace {
 auto client_ = std::make_unique<mtx::crypto::OlmClient>();
+
+std::map<std::string, std::string> request_id_to_secret_name;
 }
 
 namespace olm {
@@ -1035,4 +1041,78 @@ send_encrypted_to_device_messages(const std::map<std::string, std::vector<std::s
         }
 }
 
+void
+request_cross_signing_keys()
+{
+        mtx::events::msg::SecretRequest secretRequest{};
+        secretRequest.action               = mtx::events::msg::RequestAction::Request;
+        secretRequest.requesting_device_id = http::client()->device_id();
+
+        auto local_user = http::client()->user_id();
+
+        auto verificationStatus = cache::verificationStatus(local_user.to_string());
+
+        if (!verificationStatus)
+                return;
+
+        auto request = [&](std::string secretName) {
+                secretRequest.name       = secretName;
+                secretRequest.request_id = "ss." + http::client()->generate_txn_id();
+
+                request_id_to_secret_name[secretRequest.request_id] = secretRequest.name;
+
+                std::map<mtx::identifiers::User,
+                         std::map<std::string, mtx::events::msg::SecretRequest>>
+                  body;
+
+                for (const auto &dev : verificationStatus->verified_devices) {
+                        if (dev != secretRequest.requesting_device_id)
+                                body[local_user][dev] = secretRequest;
+                }
+
+                http::client()->send_to_device<mtx::events::msg::SecretRequest>(
+                  http::client()->generate_txn_id(),
+                  body,
+                  [request_id = secretRequest.request_id, secretName](mtx::http::RequestErr err) {
+                          if (err) {
+                                  request_id_to_secret_name.erase(request_id);
+                                  nhlog::net()->error("Failed to send request for secrect '{}'",
+                                                      secretName);
+                                  return;
+                          }
+                  });
+
+                for (const auto &dev : verificationStatus->verified_devices) {
+                        if (dev != secretRequest.requesting_device_id)
+                                body[local_user][dev].action =
+                                  mtx::events::msg::RequestAction::Cancellation;
+                }
+
+                // timeout after 15 min
+                QTimer::singleShot(15 * 60 * 1000, [secretRequest, body]() {
+                        if (request_id_to_secret_name.count(secretRequest.request_id)) {
+                                request_id_to_secret_name.erase(secretRequest.request_id);
+                                http::client()->send_to_device<mtx::events::msg::SecretRequest>(
+                                  http::client()->generate_txn_id(),
+                                  body,
+                                  [secretRequest](mtx::http::RequestErr err) {
+                                          if (err) {
+                                                  nhlog::net()->error(
+                                                    "Failed to cancel request for secrect '{}'",
+                                                    secretRequest.name);
+                                                  return;
+                                          }
+                                  });
+                        }
+                });
+        };
+
+        request(mtx::secret_storage::secrets::cross_signing_self_signing);
+        request(mtx::secret_storage::secrets::cross_signing_user_signing);
+        request(mtx::secret_storage::secrets::megolm_backup_v1);
+}
+void
+download_cross_signing_keys()
+{}
+
 } // namespace olm
diff --git a/src/Olm.h b/src/Olm.h
index 3400f9930..78c1e6414 100644
--- a/src/Olm.h
+++ b/src/Olm.h
@@ -102,4 +102,11 @@ send_encrypted_to_device_messages(const std::map<std::string, std::vector<std::s
                                   const mtx::events::collections::DeviceEvents &event,
                                   bool force_new_session = false);
 
+//! Request backup and signing keys and cache them locally
+void
+request_cross_signing_keys();
+//! Download backup and signing keys and cache them locally
+void
+download_cross_signing_keys();
+
 } // namespace olm
diff --git a/src/UserSettingsPage.cpp b/src/UserSettingsPage.cpp
index 17d1adb8d..a773af1c3 100644
--- a/src/UserSettingsPage.cpp
+++ b/src/UserSettingsPage.cpp
@@ -649,6 +649,18 @@ UserSettingsPage::UserSettingsPage(QSharedPointer<UserSettings> settings, QWidge
         sessionKeysLayout->addWidget(sessionKeysExportBtn, 0, Qt::AlignRight);
         sessionKeysLayout->addWidget(sessionKeysImportBtn, 0, Qt::AlignRight);
 
+        auto crossSigningKeysLabel = new QLabel{tr("Cross Signing Keys"), this};
+        crossSigningKeysLabel->setFont(font);
+        crossSigningKeysLabel->setMargin(OptionMargin);
+
+        auto crossSigningRequestBtn  = new QPushButton{tr("REQUEST"), this};
+        auto crossSigningDownloadBtn = new QPushButton{tr("DOWNLOAD"), this};
+
+        auto crossSigningKeysLayout = new QHBoxLayout;
+        crossSigningKeysLayout->addWidget(new QLabel{"", this}, 1, Qt::AlignRight);
+        crossSigningKeysLayout->addWidget(crossSigningRequestBtn, 0, Qt::AlignRight);
+        crossSigningKeysLayout->addWidget(crossSigningDownloadBtn, 0, Qt::AlignRight);
+
         auto boxWrap = [this, &font](QString labelText, QWidget *field, QString tooltipText = "") {
                 auto label = new QLabel{labelText, this};
                 label->setFont(font);
@@ -787,6 +799,7 @@ UserSettingsPage::UserSettingsPage(QSharedPointer<UserSettings> settings, QWidge
           tr("Automatically replies to key requests from other users, if they are verified."));
         formLayout_->addRow(new HorizontalLine{this});
         formLayout_->addRow(sessionKeysLabel, sessionKeysLayout);
+        formLayout_->addRow(crossSigningKeysLabel, crossSigningKeysLayout);
 
         auto scrollArea_ = new QScrollArea{this};
         scrollArea_->setFrameShape(QFrame::NoFrame);
@@ -982,6 +995,10 @@ UserSettingsPage::UserSettingsPage(QSharedPointer<UserSettings> settings, QWidge
         connect(
           sessionKeysExportBtn, &QPushButton::clicked, this, &UserSettingsPage::exportSessionKeys);
 
+        connect(crossSigningRequestBtn, &QPushButton::clicked, this, []() {
+                olm::request_cross_signing_keys();
+        });
+
         connect(backBtn_, &QPushButton::clicked, this, [this]() {
                 settings_->save();
                 emit moveBack();
-- 
GitLab