Add menu option to enable encryption in a private room

This commit is contained in:
Konstantinos Sideris 2018-06-12 09:45:26 +03:00
parent 626c680911
commit 36cb62748b
6 changed files with 142 additions and 15 deletions

View file

@ -342,6 +342,8 @@ public:
//! Mark a room that uses e2e encryption. //! Mark a room that uses e2e encryption.
void setEncryptedRoom(const std::string &room_id); void setEncryptedRoom(const std::string &room_id);
bool isRoomEncrypted(const std::string &room_id);
//! Save the public keys for a device. //! Save the public keys for a device.
void saveDeviceKeys(const std::string &device_id); void saveDeviceKeys(const std::string &device_id);
void getDeviceKeys(const std::string &device_id); void getDeviceKeys(const std::string &device_id);

View file

@ -5,16 +5,17 @@
#include "Cache.h" #include "Cache.h"
class FlatButton;
class TextField;
class QHBoxLayout;
class Avatar; class Avatar;
class QPixmap; class FlatButton;
class QLayout;
class QLabel;
class QComboBox; class QComboBox;
class TextField; class QHBoxLayout;
class QLabel; class QLabel;
class QLabel;
class QLayout;
class QPixmap;
class TextField;
class TextField;
class Toggle;
template<class T> template<class T>
class QSharedPointer; class QSharedPointer;
@ -84,6 +85,7 @@ public:
signals: signals:
void closing(); void closing();
void enableEncryptionError(const QString &msg);
protected: protected:
void paintEvent(QPaintEvent *event) override; void paintEvent(QPaintEvent *event) override;
@ -98,13 +100,15 @@ private:
void setupEditButton(); void setupEditButton();
//! Retrieve the current room information from cache. //! Retrieve the current room information from cache.
void retrieveRoomInfo(); void retrieveRoomInfo();
void enableEncryption();
//! Whether the user would be able to change the name or the topic of the room. //! Whether the user would be able to change the name or the topic of the room.
bool hasEditRights_ = true; bool hasEditRights_ = true;
bool usesEncryption_ = false;
QHBoxLayout *editLayout_; QHBoxLayout *editLayout_;
// Button section // Button section
FlatButton *saveBtn_; FlatButton *okBtn_;
FlatButton *cancelBtn_; FlatButton *cancelBtn_;
FlatButton *editFieldsBtn_; FlatButton *editFieldsBtn_;
@ -116,6 +120,7 @@ private:
TopSection *topSection_; TopSection *topSection_;
QComboBox *accessCombo; QComboBox *accessCombo;
Toggle *encryptionToggle_;
}; };
} // dialogs } // dialogs

View file

@ -60,7 +60,7 @@ constexpr auto DEVICES_DB("devices");
//! device_id -> device keys //! device_id -> device keys
constexpr auto DEVICE_KEYS_DB("device_keys"); constexpr auto DEVICE_KEYS_DB("device_keys");
//! room_ids that have encryption enabled. //! room_ids that have encryption enabled.
// constexpr auto ENCRYPTED_ROOMS_DB("encrypted_rooms"); constexpr auto ENCRYPTED_ROOMS_DB("encrypted_rooms");
//! MegolmSessionIndex -> pickled OlmInboundGroupSession //! MegolmSessionIndex -> pickled OlmInboundGroupSession
constexpr auto INBOUND_MEGOLM_SESSIONS_DB("inbound_megolm_sessions"); constexpr auto INBOUND_MEGOLM_SESSIONS_DB("inbound_megolm_sessions");
@ -184,6 +184,30 @@ Cache::setup()
txn.commit(); txn.commit();
} }
void
Cache::setEncryptedRoom(const std::string &room_id)
{
log::db()->info("mark room {} as encrypted", room_id);
auto txn = lmdb::txn::begin(env_);
auto db = lmdb::dbi::open(txn, ENCRYPTED_ROOMS_DB, MDB_CREATE);
lmdb::dbi_put(txn, db, lmdb::val(room_id), lmdb::val("0"));
txn.commit();
}
bool
Cache::isRoomEncrypted(const std::string &room_id)
{
lmdb::val unused;
auto txn = lmdb::txn::begin(env_);
auto db = lmdb::dbi::open(txn, ENCRYPTED_ROOMS_DB, MDB_CREATE);
auto res = lmdb::dbi_get(txn, db, lmdb::val(room_id), unused);
txn.commit();
return res;
}
// //
// Device Management // Device Management
// //

View file

@ -245,6 +245,10 @@ ChatPage::ChatPage(QSharedPointer<UserSettings> userSettings, QWidget *parent)
return; return;
typingRefresher_->stop(); typingRefresher_->stop();
if (current_room_.isEmpty())
return;
http::v2::client()->stop_typing( http::v2::client()->stop_typing(
current_room_.toStdString(), [](mtx::http::RequestErr err) { current_room_.toStdString(), [](mtx::http::RequestErr err) {
if (err) { if (err) {

View file

@ -1,16 +1,20 @@
#include "Avatar.h" #include "Avatar.h"
#include "ChatPage.h"
#include "Config.h" #include "Config.h"
#include "FlatButton.h" #include "FlatButton.h"
#include "Logging.hpp"
#include "MatrixClient.h" #include "MatrixClient.h"
#include "Painter.h" #include "Painter.h"
#include "TextField.h" #include "TextField.h"
#include "Theme.h" #include "Theme.h"
#include "Utils.h" #include "Utils.h"
#include "dialogs/RoomSettings.hpp" #include "dialogs/RoomSettings.hpp"
#include "ui/ToggleButton.h"
#include <QApplication> #include <QApplication>
#include <QComboBox> #include <QComboBox>
#include <QLabel> #include <QLabel>
#include <QMessageBox>
#include <QPainter> #include <QPainter>
#include <QPixmap> #include <QPixmap>
#include <QSettings> #include <QSettings>
@ -188,8 +192,8 @@ RoomSettings::RoomSettings(const QString &room_id, QWidget *parent)
layout->setSpacing(15); layout->setSpacing(15);
layout->setMargin(20); layout->setMargin(20);
saveBtn_ = new FlatButton("SAVE", this); okBtn_ = new FlatButton(tr("OK"), this);
saveBtn_->setFontSize(conf::btn::fontSize); okBtn_->setFontSize(conf::btn::fontSize);
cancelBtn_ = new FlatButton(tr("CANCEL"), this); cancelBtn_ = new FlatButton(tr("CANCEL"), this);
cancelBtn_->setFontSize(conf::btn::fontSize); cancelBtn_->setFontSize(conf::btn::fontSize);
@ -197,7 +201,7 @@ RoomSettings::RoomSettings(const QString &room_id, QWidget *parent)
btnLayout->setSpacing(0); btnLayout->setSpacing(0);
btnLayout->setMargin(0); btnLayout->setMargin(0);
btnLayout->addStretch(1); btnLayout->addStretch(1);
btnLayout->addWidget(saveBtn_); btnLayout->addWidget(okBtn_);
btnLayout->addWidget(cancelBtn_); btnLayout->addWidget(cancelBtn_);
auto notifOptionLayout_ = new QHBoxLayout; auto notifOptionLayout_ = new QHBoxLayout;
@ -236,6 +240,61 @@ RoomSettings::RoomSettings(const QString &room_id, QWidget *parent)
accessOptionLayout->addWidget(accessLabel); accessOptionLayout->addWidget(accessLabel);
accessOptionLayout->addWidget(accessCombo); accessOptionLayout->addWidget(accessCombo);
auto encryptionOptionLayout = new QHBoxLayout;
encryptionOptionLayout->setMargin(SettingsMargin);
auto encryptionLabel = new QLabel(tr("Encryption"), this);
encryptionLabel->setStyleSheet("font-size: 15px;");
encryptionToggle_ = new Toggle(this);
connect(encryptionToggle_, &Toggle::toggled, this, [this](bool isOn) {
if (isOn)
return;
QFont font;
font.setPixelSize(conf::fontSize);
QMessageBox msgBox;
msgBox.setIcon(QMessageBox::Question);
msgBox.setFont(font);
msgBox.setWindowTitle(tr("End-to-End Encryption"));
msgBox.setText(tr(
"Encryption is currently experimental and things might break unexpectedly. <br>"
"Please take note that it can't be disabled afterwards."));
msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
msgBox.setDefaultButton(QMessageBox::Save);
int ret = msgBox.exec();
switch (ret) {
case QMessageBox::Ok: {
encryptionToggle_->setState(false);
encryptionToggle_->setEnabled(false);
enableEncryption();
break;
}
default: {
encryptionToggle_->setState(true);
encryptionToggle_->setEnabled(true);
break;
}
}
});
encryptionOptionLayout->addWidget(encryptionLabel);
encryptionOptionLayout->addWidget(encryptionToggle_, 0, Qt::AlignBottom | Qt::AlignRight);
// Disable encryption button.
if (usesEncryption_) {
encryptionToggle_->setState(false);
encryptionToggle_->setEnabled(false);
} else {
encryptionToggle_->setState(true);
}
// Hide encryption option for public rooms.
if (!usesEncryption_ && (info_.join_rule == JoinRule::Public)) {
encryptionToggle_->hide();
encryptionLabel->hide();
}
QFont font; QFont font;
font.setPixelSize(18); font.setPixelSize(18);
font.setWeight(70); font.setWeight(70);
@ -255,10 +314,18 @@ RoomSettings::RoomSettings(const QString &room_id, QWidget *parent)
layout->addLayout(editLayout_); layout->addLayout(editLayout_);
layout->addLayout(notifOptionLayout_); layout->addLayout(notifOptionLayout_);
layout->addLayout(accessOptionLayout); layout->addLayout(accessOptionLayout);
layout->addLayout(encryptionOptionLayout);
layout->addLayout(btnLayout); layout->addLayout(btnLayout);
connect(cancelBtn_, &QPushButton::clicked, this, &RoomSettings::closing); connect(cancelBtn_, &QPushButton::clicked, this, &RoomSettings::closing);
connect(saveBtn_, &QPushButton::clicked, this, &RoomSettings::saveSettings); connect(okBtn_, &QPushButton::clicked, this, &RoomSettings::saveSettings);
connect(this, &RoomSettings::enableEncryptionError, this, [this](const QString &msg) {
encryptionToggle_->setState(true);
encryptionToggle_->setEnabled(true);
emit ChatPage::instance()->showNotification(msg);
});
} }
void void
@ -308,6 +375,7 @@ void
RoomSettings::retrieveRoomInfo() RoomSettings::retrieveRoomInfo()
{ {
try { try {
usesEncryption_ = cache::client()->isRoomEncrypted(room_id_.toStdString());
info_ = cache::client()->singleRoomInfo(room_id_.toStdString()); info_ = cache::client()->singleRoomInfo(room_id_.toStdString());
setAvatar(QImage::fromData(cache::client()->image(info_.avatar_url))); setAvatar(QImage::fromData(cache::client()->image(info_.avatar_url)));
} catch (const lmdb::error &e) { } catch (const lmdb::error &e) {
@ -339,6 +407,28 @@ RoomSettings::saveSettings()
closing(); closing();
} }
void
RoomSettings::enableEncryption()
{
const auto room_id = room_id_.toStdString();
http::v2::client()->enable_encryption(
room_id, [room_id, this](const mtx::responses::EventId &, mtx::http::RequestErr err) {
if (err) {
int status_code = static_cast<int>(err->status_code);
log::net()->warn("failed to enable encryption in room ({}): {} {}",
room_id,
err->matrix_error.error,
status_code);
emit enableEncryptionError(
tr("Failed to enable encryption: %1")
.arg(QString::fromStdString(err->matrix_error.error)));
return;
}
log::net()->info("enabled encryption on room ({})", room_id);
});
}
void void
RoomSettings::paintEvent(QPaintEvent *) RoomSettings::paintEvent(QPaintEvent *)
{ {

View file

@ -284,6 +284,8 @@ TimelineView::parseMessageEvent(const mtx::events::collections::TimelineEvents &
auto decrypted = auto decrypted =
parseEncryptedEvent(mpark::get<EncryptedEvent<msg::Encrypted>>(event)); parseEncryptedEvent(mpark::get<EncryptedEvent<msg::Encrypted>>(event));
return parseMessageEvent(decrypted, direction); return parseMessageEvent(decrypted, direction);
} else if (mpark::holds_alternative<StateEvent<state::Encryption>>(event)) {
cache::client()->setEncryptedRoom(room_id_.toStdString());
} }
return nullptr; return nullptr;