Add option to only send encrypted messages to verified devices

fixes #636
This commit is contained in:
Nicolas Werner 2021-08-01 00:59:46 +02:00
parent 760f675792
commit 25e7a985b8
No known key found for this signature in database
GPG key ID: C8D75E610773F2D9
5 changed files with 127 additions and 48 deletions

View file

@ -3542,7 +3542,7 @@ Cache::roomMembers(const std::string &room_id)
} }
std::map<std::string, std::optional<UserKeyCache>> 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; std::string_view keys;
@ -3559,9 +3559,50 @@ Cache::getMembersWithKeys(const std::string &room_id)
auto res = keysDb.get(txn, user_id, keys); auto res = keysDb.get(txn, user_id, keys);
if (res) { if (res) {
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)] = members[std::string(user_id)] =
json::parse(keys).get<UserKeyCache>(); std::move(keyCopy);
}
} else { } else {
members[std::string(user_id)] = std::move(k);
}
} else {
if (!verified_only)
members[std::string(user_id)] = {}; members[std::string(user_id)] = {};
} }
} }

View file

@ -48,7 +48,8 @@ public:
// user cache stores user keys // user cache stores user keys
std::optional<UserKeyCache> userKeys(const std::string &user_id); std::optional<UserKeyCache> userKeys(const std::string &user_id);
std::map<std::string, std::optional<UserKeyCache>> getMembersWithKeys( 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, void updateUserKeys(const std::string &sync_token,
const mtx::responses::QueryKeys &keyQuery); const mtx::responses::QueryKeys &keyQuery);
void markUserKeysOutOfDate(lmdb::txn &txn, void markUserKeysOutOfDate(lmdb::txn &txn,

View file

@ -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 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; std::map<std::string, std::vector<std::string>> sendSessionTo;
mtx::crypto::OutboundGroupSessionPtr session = nullptr; mtx::crypto::OutboundGroupSessionPtr session = nullptr;

View file

@ -90,8 +90,6 @@ UserSettings::load(std::optional<QString> profile)
decryptSidebar_ = settings.value("user/decrypt_sidebar", true).toBool(); decryptSidebar_ = settings.value("user/decrypt_sidebar", true).toBool();
privacyScreen_ = settings.value("user/privacy_screen", false).toBool(); privacyScreen_ = settings.value("user/privacy_screen", false).toBool();
privacyScreenTimeout_ = settings.value("user/privacy_screen_timeout", 0).toInt(); 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(); mobileMode_ = settings.value("user/mobile_mode", false).toBool();
emojiFont_ = settings.value("user/emoji_font_family", "default").toString(); emojiFont_ = settings.value("user/emoji_font_family", "default").toString();
baseFontSize_ = settings.value("user/font_size", QFont().pointSizeF()).toDouble(); baseFontSize_ = settings.value("user/font_size", QFont().pointSizeF()).toDouble();
@ -123,6 +121,12 @@ UserSettings::load(std::optional<QString> profile)
userId_ = settings.value(prefix + "auth/user_id", "").toString(); userId_ = settings.value(prefix + "auth/user_id", "").toString();
deviceId_ = settings.value(prefix + "auth/device_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_ = disableCertificateValidation_ =
settings.value("disable_certificate_validation", false).toBool(); settings.value("disable_certificate_validation", false).toBool();
@ -401,6 +405,17 @@ UserSettings::setUseStunServer(bool useStunServer)
save(); save();
} }
void
UserSettings::setOnlyShareKeysWithVerifiedUsers(bool shareKeys)
{
if (shareKeys == onlyShareKeysWithVerifiedUsers_)
return;
onlyShareKeysWithVerifiedUsers_ = shareKeys;
emit onlyShareKeysWithVerifiedUsersChanged(shareKeys);
save();
}
void void
UserSettings::setShareKeysWithTrustedUsers(bool shareKeys) UserSettings::setShareKeysWithTrustedUsers(bool shareKeys)
{ {
@ -610,8 +625,6 @@ UserSettings::save()
settings.setValue("decrypt_sidebar", decryptSidebar_); settings.setValue("decrypt_sidebar", decryptSidebar_);
settings.setValue("privacy_screen", privacyScreen_); settings.setValue("privacy_screen", privacyScreen_);
settings.setValue("privacy_screen_timeout", privacyScreenTimeout_); settings.setValue("privacy_screen_timeout", privacyScreenTimeout_);
settings.setValue("automatically_share_keys_with_trusted_users",
shareKeysWithTrustedUsers_);
settings.setValue("mobile_mode", mobileMode_); settings.setValue("mobile_mode", mobileMode_);
settings.setValue("font_size", baseFontSize_); settings.setValue("font_size", baseFontSize_);
settings.setValue("typing_notifications", typingNotifications_); settings.setValue("typing_notifications", typingNotifications_);
@ -650,6 +663,11 @@ UserSettings::save()
settings.setValue(prefix + "auth/user_id", userId_); settings.setValue(prefix + "auth/user_id", userId_);
settings.setValue(prefix + "auth/device_id", deviceId_); 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.setValue("disable_certificate_validation", disableCertificateValidation_);
settings.sync(); settings.sync();
@ -708,6 +726,7 @@ UserSettingsPage::UserSettingsPage(QSharedPointer<UserSettings> settings, QWidge
avatarCircles_ = new Toggle{this}; avatarCircles_ = new Toggle{this};
decryptSidebar_ = new Toggle(this); decryptSidebar_ = new Toggle(this);
privacyScreen_ = new Toggle{this}; privacyScreen_ = new Toggle{this};
onlyShareKeysWithVerifiedUsers_ = new Toggle(this);
shareKeysWithTrustedUsers_ = new Toggle(this); shareKeysWithTrustedUsers_ = new Toggle(this);
groupViewToggle_ = new Toggle{this}; groupViewToggle_ = new Toggle{this};
timelineButtonsToggle_ = new Toggle{this}; timelineButtonsToggle_ = new Toggle{this};
@ -738,6 +757,7 @@ UserSettingsPage::UserSettingsPage(QSharedPointer<UserSettings> settings, QWidge
avatarCircles_->setChecked(settings_->avatarCircles()); avatarCircles_->setChecked(settings_->avatarCircles());
decryptSidebar_->setChecked(settings_->decryptSidebar()); decryptSidebar_->setChecked(settings_->decryptSidebar());
privacyScreen_->setChecked(settings_->privacyScreen()); privacyScreen_->setChecked(settings_->privacyScreen());
onlyShareKeysWithVerifiedUsers_->setChecked(settings_->onlyShareKeysWithVerifiedUsers());
shareKeysWithTrustedUsers_->setChecked(settings_->shareKeysWithTrustedUsers()); shareKeysWithTrustedUsers_->setChecked(settings_->shareKeysWithTrustedUsers());
groupViewToggle_->setChecked(settings_->groupView()); groupViewToggle_->setChecked(settings_->groupView());
timelineButtonsToggle_->setChecked(settings_->buttonsInTimeline()); timelineButtonsToggle_->setChecked(settings_->buttonsInTimeline());
@ -1008,10 +1028,14 @@ UserSettingsPage::UserSettingsPage(QSharedPointer<UserSettings> settings, QWidge
formLayout_->addRow(new HorizontalLine{this}); formLayout_->addRow(new HorizontalLine{this});
boxWrap(tr("Device ID"), deviceIdValue_); boxWrap(tr("Device ID"), deviceIdValue_);
boxWrap(tr("Device Fingerprint"), deviceFingerprintValue_); boxWrap(tr("Device Fingerprint"), deviceFingerprintValue_);
boxWrap( boxWrap(tr("Send encrypted messages to verified users only"),
tr("Share keys with verified users and devices"), 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_, shareKeysWithTrustedUsers_,
tr("Automatically replies to key requests from other users, if they are verified.")); 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(new HorizontalLine{this});
formLayout_->addRow(sessionKeysLabel, sessionKeysLayout); formLayout_->addRow(sessionKeysLabel, sessionKeysLayout);
formLayout_->addRow(crossSigningKeysLabel, crossSigningKeysLayout); 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) { connect(shareKeysWithTrustedUsers_, &Toggle::toggled, this, [this](bool enabled) {
settings_->setShareKeysWithTrustedUsers(enabled); settings_->setShareKeysWithTrustedUsers(enabled);
}); });
@ -1271,6 +1299,7 @@ UserSettingsPage::showEvent(QShowEvent *)
groupViewToggle_->setState(settings_->groupView()); groupViewToggle_->setState(settings_->groupView());
decryptSidebar_->setState(settings_->decryptSidebar()); decryptSidebar_->setState(settings_->decryptSidebar());
privacyScreen_->setState(settings_->privacyScreen()); privacyScreen_->setState(settings_->privacyScreen());
onlyShareKeysWithVerifiedUsers_->setState(settings_->onlyShareKeysWithVerifiedUsers());
shareKeysWithTrustedUsers_->setState(settings_->shareKeysWithTrustedUsers()); shareKeysWithTrustedUsers_->setState(settings_->shareKeysWithTrustedUsers());
avatarCircles_->setState(settings_->avatarCircles()); avatarCircles_->setState(settings_->avatarCircles());
typingNotifications_->setState(settings_->typingNotifications()); typingNotifications_->setState(settings_->typingNotifications());

View file

@ -88,6 +88,8 @@ class UserSettings : public QObject
setScreenShareHideCursor NOTIFY screenShareHideCursorChanged) setScreenShareHideCursor NOTIFY screenShareHideCursorChanged)
Q_PROPERTY( Q_PROPERTY(
bool useStunServer READ useStunServer WRITE setUseStunServer NOTIFY useStunServerChanged) 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 Q_PROPERTY(bool shareKeysWithTrustedUsers READ shareKeysWithTrustedUsers WRITE
setShareKeysWithTrustedUsers NOTIFY shareKeysWithTrustedUsersChanged) setShareKeysWithTrustedUsers NOTIFY shareKeysWithTrustedUsersChanged)
Q_PROPERTY(QString profile READ profile WRITE setProfile NOTIFY profileChanged) Q_PROPERTY(QString profile READ profile WRITE setProfile NOTIFY profileChanged)
@ -152,6 +154,7 @@ public:
void setScreenShareRemoteVideo(bool state); void setScreenShareRemoteVideo(bool state);
void setScreenShareHideCursor(bool state); void setScreenShareHideCursor(bool state);
void setUseStunServer(bool state); void setUseStunServer(bool state);
void setOnlyShareKeysWithVerifiedUsers(bool state);
void setShareKeysWithTrustedUsers(bool state); void setShareKeysWithTrustedUsers(bool state);
void setProfile(QString profile); void setProfile(QString profile);
void setUserId(QString userId); void setUserId(QString userId);
@ -208,6 +211,7 @@ public:
bool screenShareHideCursor() const { return screenShareHideCursor_; } bool screenShareHideCursor() const { return screenShareHideCursor_; }
bool useStunServer() const { return useStunServer_; } bool useStunServer() const { return useStunServer_; }
bool shareKeysWithTrustedUsers() const { return shareKeysWithTrustedUsers_; } bool shareKeysWithTrustedUsers() const { return shareKeysWithTrustedUsers_; }
bool onlyShareKeysWithVerifiedUsers() const { return onlyShareKeysWithVerifiedUsers_; }
QString profile() const { return profile_; } QString profile() const { return profile_; }
QString userId() const { return userId_; } QString userId() const { return userId_; }
QString accessToken() const { return accessToken_; } QString accessToken() const { return accessToken_; }
@ -252,6 +256,7 @@ signals:
void screenShareRemoteVideoChanged(bool state); void screenShareRemoteVideoChanged(bool state);
void screenShareHideCursorChanged(bool state); void screenShareHideCursorChanged(bool state);
void useStunServerChanged(bool state); void useStunServerChanged(bool state);
void onlyShareKeysWithVerifiedUsersChanged(bool state);
void shareKeysWithTrustedUsersChanged(bool state); void shareKeysWithTrustedUsersChanged(bool state);
void profileChanged(QString profile); void profileChanged(QString profile);
void userIdChanged(QString userId); void userIdChanged(QString userId);
@ -284,6 +289,7 @@ private:
bool privacyScreen_; bool privacyScreen_;
int privacyScreenTimeout_; int privacyScreenTimeout_;
bool shareKeysWithTrustedUsers_; bool shareKeysWithTrustedUsers_;
bool onlyShareKeysWithVerifiedUsers_;
bool mobileMode_; bool mobileMode_;
int timelineMaxWidth_; int timelineMaxWidth_;
int roomListWidth_; int roomListWidth_;
@ -372,6 +378,7 @@ private:
Toggle *privacyScreen_; Toggle *privacyScreen_;
QSpinBox *privacyScreenTimeout_; QSpinBox *privacyScreenTimeout_;
Toggle *shareKeysWithTrustedUsers_; Toggle *shareKeysWithTrustedUsers_;
Toggle *onlyShareKeysWithVerifiedUsers_;
Toggle *mobileMode_; Toggle *mobileMode_;
QLabel *deviceFingerprintValue_; QLabel *deviceFingerprintValue_;
QLabel *deviceIdValue_; QLabel *deviceIdValue_;