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_;
|