summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/Cache.cpp49
-rw-r--r--src/Cache_p.h3
-rw-r--r--src/Olm.cpp3
-rw-r--r--src/UserSettingsPage.cpp113
-rw-r--r--src/UserSettingsPage.h7
5 files changed, 127 insertions, 48 deletions
diff --git a/src/Cache.cpp b/src/Cache.cpp
index 7d0b1a89..291df053 100644
--- a/src/Cache.cpp
+++ b/src/Cache.cpp
@@ -3542,7 +3542,7 @@ Cache::roomMembers(const std::string &room_id)
 }
 
 std::map<std::string, std::optional<UserKeyCache>>
-Cache::getMembersWithKeys(const std::string &room_id)
+Cache::getMembersWithKeys(const std::string &room_id, bool verified_only)
 {
         std::string_view keys;
 
@@ -3559,10 +3559,51 @@ Cache::getMembersWithKeys(const std::string &room_id)
                         auto res = keysDb.get(txn, user_id, keys);
 
                         if (res) {
-                                members[std::string(user_id)] =
-                                  json::parse(keys).get<UserKeyCache>();
+                                auto k = json::parse(keys).get<UserKeyCache>();
+                                if (verified_only) {
+                                        auto verif = verificationStatus(std::string(user_id));
+                                        if (verif.user_verified == crypto::Trust::Verified ||
+                                            !verif.verified_devices.empty()) {
+                                                auto keyCopy = k;
+                                                keyCopy.device_keys.clear();
+
+                                                std::copy_if(
+                                                  k.device_keys.begin(),
+                                                  k.device_keys.end(),
+                                                  std::inserter(keyCopy.device_keys,
+                                                                keyCopy.device_keys.end()),
+                                                  [&verif](const auto &key) {
+                                                          auto curve25519 = key.second.keys.find(
+                                                            "curve25519:" + key.first);
+                                                          if (curve25519 == key.second.keys.end())
+                                                                  return false;
+                                                          if (auto t =
+                                                                verif.verified_device_keys.find(
+                                                                  curve25519->second);
+                                                              t ==
+                                                                verif.verified_device_keys.end() ||
+                                                              t->second != crypto::Trust::Verified)
+                                                                  return false;
+
+                                                          return key.first ==
+                                                                   key.second.device_id &&
+                                                                 std::find(
+                                                                   verif.verified_devices.begin(),
+                                                                   verif.verified_devices.end(),
+                                                                   key.first) !=
+                                                                   verif.verified_devices.end();
+                                                  });
+
+                                                if (!keyCopy.device_keys.empty())
+                                                        members[std::string(user_id)] =
+                                                          std::move(keyCopy);
+                                        }
+                                } else {
+                                        members[std::string(user_id)] = std::move(k);
+                                }
                         } else {
-                                members[std::string(user_id)] = {};
+                                if (!verified_only)
+                                        members[std::string(user_id)] = {};
                         }
                 }
                 cursor.close();
diff --git a/src/Cache_p.h b/src/Cache_p.h
index 18b9601f..5d700658 100644
--- a/src/Cache_p.h
+++ b/src/Cache_p.h
@@ -48,7 +48,8 @@ public:
         // user cache stores user keys
         std::optional<UserKeyCache> userKeys(const std::string &user_id);
         std::map<std::string, std::optional<UserKeyCache>> getMembersWithKeys(
-          const std::string &room_id);
+          const std::string &room_id,
+          bool verified_only);
         void updateUserKeys(const std::string &sync_token,
                             const mtx::responses::QueryKeys &keyQuery);
         void markUserKeysOutOfDate(lmdb::txn &txn,
diff --git a/src/Olm.cpp b/src/Olm.cpp
index e3ca1c34..048a6c0f 100644
--- a/src/Olm.cpp
+++ b/src/Olm.cpp
@@ -524,7 +524,8 @@ encrypt_group_message(const std::string &room_id, const std::string &device_id,
 
         auto own_user_id = http::client()->user_id().to_string();
 
-        auto members = cache::client()->getMembersWithKeys(room_id);
+        auto members = cache::client()->getMembersWithKeys(
+          room_id, UserSettings::instance()->onlyShareKeysWithVerifiedUsers());
 
         std::map<std::string, std::vector<std::string>> sendSessionTo;
         mtx::crypto::OutboundGroupSessionPtr session = nullptr;
diff --git a/src/UserSettingsPage.cpp b/src/UserSettingsPage.cpp
index a062780a..ab6ac492 100644
--- a/src/UserSettingsPage.cpp
+++ b/src/UserSettingsPage.cpp
@@ -90,13 +90,11 @@ UserSettings::load(std::optional<QString> profile)
         decryptSidebar_       = settings.value("user/decrypt_sidebar", true).toBool();
         privacyScreen_        = settings.value("user/privacy_screen", false).toBool();
         privacyScreenTimeout_ = settings.value("user/privacy_screen_timeout", 0).toInt();
-        shareKeysWithTrustedUsers_ =
-          settings.value("user/automatically_share_keys_with_trusted_users", false).toBool();
-        mobileMode_        = settings.value("user/mobile_mode", false).toBool();
-        emojiFont_         = settings.value("user/emoji_font_family", "default").toString();
-        baseFontSize_      = settings.value("user/font_size", QFont().pointSizeF()).toDouble();
-        auto tempPresence  = settings.value("user/presence", "").toString().toStdString();
-        auto presenceValue = QMetaEnum::fromType<Presence>().keyToValue(tempPresence.c_str());
+        mobileMode_           = settings.value("user/mobile_mode", false).toBool();
+        emojiFont_            = settings.value("user/emoji_font_family", "default").toString();
+        baseFontSize_         = settings.value("user/font_size", QFont().pointSizeF()).toDouble();
+        auto tempPresence     = settings.value("user/presence", "").toString().toStdString();
+        auto presenceValue    = QMetaEnum::fromType<Presence>().keyToValue(tempPresence.c_str());
         if (presenceValue < 0)
                 presenceValue = 0;
         presence_               = static_cast<Presence>(presenceValue);
@@ -123,6 +121,12 @@ UserSettings::load(std::optional<QString> profile)
         userId_      = settings.value(prefix + "auth/user_id", "").toString();
         deviceId_    = settings.value(prefix + "auth/device_id", "").toString();
 
+        shareKeysWithTrustedUsers_ =
+          settings.value(prefix + "user/automatically_share_keys_with_trusted_users", false)
+            .toBool();
+        onlyShareKeysWithVerifiedUsers_ =
+          settings.value(prefix + "user/only_share_keys_with_verified_users", false).toBool();
+
         disableCertificateValidation_ =
           settings.value("disable_certificate_validation", false).toBool();
 
@@ -402,6 +406,17 @@ UserSettings::setUseStunServer(bool useStunServer)
 }
 
 void
+UserSettings::setOnlyShareKeysWithVerifiedUsers(bool shareKeys)
+{
+        if (shareKeys == onlyShareKeysWithVerifiedUsers_)
+                return;
+
+        onlyShareKeysWithVerifiedUsers_ = shareKeys;
+        emit onlyShareKeysWithVerifiedUsersChanged(shareKeys);
+        save();
+}
+
+void
 UserSettings::setShareKeysWithTrustedUsers(bool shareKeys)
 {
         if (shareKeys == shareKeysWithTrustedUsers_)
@@ -610,8 +625,6 @@ UserSettings::save()
         settings.setValue("decrypt_sidebar", decryptSidebar_);
         settings.setValue("privacy_screen", privacyScreen_);
         settings.setValue("privacy_screen_timeout", privacyScreenTimeout_);
-        settings.setValue("automatically_share_keys_with_trusted_users",
-                          shareKeysWithTrustedUsers_);
         settings.setValue("mobile_mode", mobileMode_);
         settings.setValue("font_size", baseFontSize_);
         settings.setValue("typing_notifications", typingNotifications_);
@@ -650,6 +663,11 @@ UserSettings::save()
         settings.setValue(prefix + "auth/user_id", userId_);
         settings.setValue(prefix + "auth/device_id", deviceId_);
 
+        settings.setValue(prefix + "user/automatically_share_keys_with_trusted_users",
+                          shareKeysWithTrustedUsers_);
+        settings.setValue(prefix + "user/only_share_keys_with_verified_users",
+                          onlyShareKeysWithVerifiedUsers_);
+
         settings.setValue("disable_certificate_validation", disableCertificateValidation_);
 
         settings.sync();
@@ -703,41 +721,43 @@ UserSettingsPage::UserSettingsPage(QSharedPointer<UserSettings> settings, QWidge
         general_->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed);
         general_->setFont(font);
 
-        trayToggle_                = new Toggle{this};
-        startInTrayToggle_         = new Toggle{this};
-        avatarCircles_             = new Toggle{this};
-        decryptSidebar_            = new Toggle(this);
-        privacyScreen_             = new Toggle{this};
-        shareKeysWithTrustedUsers_ = new Toggle(this);
-        groupViewToggle_           = new Toggle{this};
-        timelineButtonsToggle_     = new Toggle{this};
-        typingNotifications_       = new Toggle{this};
-        messageHoverHighlight_     = new Toggle{this};
-        enlargeEmojiOnlyMessages_  = new Toggle{this};
-        sortByImportance_          = new Toggle{this};
-        readReceipts_              = new Toggle{this};
-        markdown_                  = new Toggle{this};
-        desktopNotifications_      = new Toggle{this};
-        alertOnNotification_       = new Toggle{this};
-        useStunServer_             = new Toggle{this};
-        mobileMode_                = new Toggle{this};
-        scaleFactorCombo_          = new QComboBox{this};
-        fontSizeCombo_             = new QComboBox{this};
-        fontSelectionCombo_        = new QFontComboBox{this};
-        emojiFontSelectionCombo_   = new QComboBox{this};
-        ringtoneCombo_             = new QComboBox{this};
-        microphoneCombo_           = new QComboBox{this};
-        cameraCombo_               = new QComboBox{this};
-        cameraResolutionCombo_     = new QComboBox{this};
-        cameraFrameRateCombo_      = new QComboBox{this};
-        timelineMaxWidthSpin_      = new QSpinBox{this};
-        privacyScreenTimeout_      = new QSpinBox{this};
+        trayToggle_                     = new Toggle{this};
+        startInTrayToggle_              = new Toggle{this};
+        avatarCircles_                  = new Toggle{this};
+        decryptSidebar_                 = new Toggle(this);
+        privacyScreen_                  = new Toggle{this};
+        onlyShareKeysWithVerifiedUsers_ = new Toggle(this);
+        shareKeysWithTrustedUsers_      = new Toggle(this);
+        groupViewToggle_                = new Toggle{this};
+        timelineButtonsToggle_          = new Toggle{this};
+        typingNotifications_            = new Toggle{this};
+        messageHoverHighlight_          = new Toggle{this};
+        enlargeEmojiOnlyMessages_       = new Toggle{this};
+        sortByImportance_               = new Toggle{this};
+        readReceipts_                   = new Toggle{this};
+        markdown_                       = new Toggle{this};
+        desktopNotifications_           = new Toggle{this};
+        alertOnNotification_            = new Toggle{this};
+        useStunServer_                  = new Toggle{this};
+        mobileMode_                     = new Toggle{this};
+        scaleFactorCombo_               = new QComboBox{this};
+        fontSizeCombo_                  = new QComboBox{this};
+        fontSelectionCombo_             = new QFontComboBox{this};
+        emojiFontSelectionCombo_        = new QComboBox{this};
+        ringtoneCombo_                  = new QComboBox{this};
+        microphoneCombo_                = new QComboBox{this};
+        cameraCombo_                    = new QComboBox{this};
+        cameraResolutionCombo_          = new QComboBox{this};
+        cameraFrameRateCombo_           = new QComboBox{this};
+        timelineMaxWidthSpin_           = new QSpinBox{this};
+        privacyScreenTimeout_           = new QSpinBox{this};
 
         trayToggle_->setChecked(settings_->tray());
         startInTrayToggle_->setChecked(settings_->startInTray());
         avatarCircles_->setChecked(settings_->avatarCircles());
         decryptSidebar_->setChecked(settings_->decryptSidebar());
         privacyScreen_->setChecked(settings_->privacyScreen());
+        onlyShareKeysWithVerifiedUsers_->setChecked(settings_->onlyShareKeysWithVerifiedUsers());
         shareKeysWithTrustedUsers_->setChecked(settings_->shareKeysWithTrustedUsers());
         groupViewToggle_->setChecked(settings_->groupView());
         timelineButtonsToggle_->setChecked(settings_->buttonsInTimeline());
@@ -1008,10 +1028,14 @@ UserSettingsPage::UserSettingsPage(QSharedPointer<UserSettings> settings, QWidge
         formLayout_->addRow(new HorizontalLine{this});
         boxWrap(tr("Device ID"), deviceIdValue_);
         boxWrap(tr("Device Fingerprint"), deviceFingerprintValue_);
-        boxWrap(
-          tr("Share keys with verified users and devices"),
-          shareKeysWithTrustedUsers_,
-          tr("Automatically replies to key requests from other users, if they are verified."));
+        boxWrap(tr("Send encrypted messages to verified users only"),
+                onlyShareKeysWithVerifiedUsers_,
+                tr("Requires a user to be verified to send encrypted messages to them. This "
+                   "improves safety but makes E2EE more tedious."));
+        boxWrap(tr("Share keys with verified users and devices"),
+                shareKeysWithTrustedUsers_,
+                tr("Automatically replies to key requests from other users, if they are verified, "
+                   "even if that device shouldn't have access to those keys otherwise."));
         formLayout_->addRow(new HorizontalLine{this});
         formLayout_->addRow(sessionKeysLabel, sessionKeysLayout);
         formLayout_->addRow(crossSigningKeysLabel, crossSigningKeysLayout);
@@ -1179,6 +1203,10 @@ UserSettingsPage::UserSettingsPage(QSharedPointer<UserSettings> settings, QWidge
                 }
         });
 
+        connect(onlyShareKeysWithVerifiedUsers_, &Toggle::toggled, this, [this](bool enabled) {
+                settings_->setOnlyShareKeysWithVerifiedUsers(enabled);
+        });
+
         connect(shareKeysWithTrustedUsers_, &Toggle::toggled, this, [this](bool enabled) {
                 settings_->setShareKeysWithTrustedUsers(enabled);
         });
@@ -1271,6 +1299,7 @@ UserSettingsPage::showEvent(QShowEvent *)
         groupViewToggle_->setState(settings_->groupView());
         decryptSidebar_->setState(settings_->decryptSidebar());
         privacyScreen_->setState(settings_->privacyScreen());
+        onlyShareKeysWithVerifiedUsers_->setState(settings_->onlyShareKeysWithVerifiedUsers());
         shareKeysWithTrustedUsers_->setState(settings_->shareKeysWithTrustedUsers());
         avatarCircles_->setState(settings_->avatarCircles());
         typingNotifications_->setState(settings_->typingNotifications());
diff --git a/src/UserSettingsPage.h b/src/UserSettingsPage.h
index acb08569..096aab81 100644
--- a/src/UserSettingsPage.h
+++ b/src/UserSettingsPage.h
@@ -88,6 +88,8 @@ class UserSettings : public QObject
                      setScreenShareHideCursor NOTIFY screenShareHideCursorChanged)
         Q_PROPERTY(
           bool useStunServer READ useStunServer WRITE setUseStunServer NOTIFY useStunServerChanged)
+        Q_PROPERTY(bool onlyShareKeysWithVerifiedUsers READ onlyShareKeysWithVerifiedUsers WRITE
+                     setOnlyShareKeysWithVerifiedUsers NOTIFY onlyShareKeysWithVerifiedUsersChanged)
         Q_PROPERTY(bool shareKeysWithTrustedUsers READ shareKeysWithTrustedUsers WRITE
                      setShareKeysWithTrustedUsers NOTIFY shareKeysWithTrustedUsersChanged)
         Q_PROPERTY(QString profile READ profile WRITE setProfile NOTIFY profileChanged)
@@ -152,6 +154,7 @@ public:
         void setScreenShareRemoteVideo(bool state);
         void setScreenShareHideCursor(bool state);
         void setUseStunServer(bool state);
+        void setOnlyShareKeysWithVerifiedUsers(bool state);
         void setShareKeysWithTrustedUsers(bool state);
         void setProfile(QString profile);
         void setUserId(QString userId);
@@ -208,6 +211,7 @@ public:
         bool screenShareHideCursor() const { return screenShareHideCursor_; }
         bool useStunServer() const { return useStunServer_; }
         bool shareKeysWithTrustedUsers() const { return shareKeysWithTrustedUsers_; }
+        bool onlyShareKeysWithVerifiedUsers() const { return onlyShareKeysWithVerifiedUsers_; }
         QString profile() const { return profile_; }
         QString userId() const { return userId_; }
         QString accessToken() const { return accessToken_; }
@@ -252,6 +256,7 @@ signals:
         void screenShareRemoteVideoChanged(bool state);
         void screenShareHideCursorChanged(bool state);
         void useStunServerChanged(bool state);
+        void onlyShareKeysWithVerifiedUsersChanged(bool state);
         void shareKeysWithTrustedUsersChanged(bool state);
         void profileChanged(QString profile);
         void userIdChanged(QString userId);
@@ -284,6 +289,7 @@ private:
         bool privacyScreen_;
         int privacyScreenTimeout_;
         bool shareKeysWithTrustedUsers_;
+        bool onlyShareKeysWithVerifiedUsers_;
         bool mobileMode_;
         int timelineMaxWidth_;
         int roomListWidth_;
@@ -372,6 +378,7 @@ private:
         Toggle *privacyScreen_;
         QSpinBox *privacyScreenTimeout_;
         Toggle *shareKeysWithTrustedUsers_;
+        Toggle *onlyShareKeysWithVerifiedUsers_;
         Toggle *mobileMode_;
         QLabel *deviceFingerprintValue_;
         QLabel *deviceIdValue_;