Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

E2EE. Do not generate keypair without user request. #5067

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 0 additions & 18 deletions src/gui/accountmanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
#include <QNetworkAccessManager>
#include <QMessageBox>
#include "clientsideencryption.h"
#include "ui_mnemonicdialog.h"

namespace {
constexpr auto urlC = "url";
Expand Down Expand Up @@ -434,23 +433,6 @@ AccountPtr AccountManager::createAccount()
return acc;
}

void AccountManager::displayMnemonic(const QString& mnemonic)
{
const auto widget = new QDialog;
Ui_Dialog ui;
ui.setupUi(widget);
widget->setWindowTitle(tr("End-to-End encryption mnemonic"));
ui.label->setText(tr("To protect your Cryptographic Identity, we encrypt it with a mnemonic of 12 dictionary words. "
"Please note these down and keep them safe. "
"They will be needed to add other devices to your account (like your mobile phone or laptop)."));
ui.textEdit->setText(mnemonic);
ui.textEdit->focusWidget();
ui.textEdit->selectAll();
ui.textEdit->setAlignment(Qt::AlignCenter);
widget->exec();
widget->resize(widget->sizeHint());
}

void AccountManager::shutdown()
{
const auto accountsCopy = _accounts;
Expand Down
3 changes: 0 additions & 3 deletions src/gui/accountmanager.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,9 +113,6 @@ public slots:
/// Saves account state data, not including the account
void saveAccountState(AccountState *a);

/// Display a Box with the mnemonic so the user can copy it to a safe place.
static void displayMnemonic(const QString& mnemonic);


Q_SIGNALS:
void accountAdded(AccountState *account);
Expand Down
123 changes: 98 additions & 25 deletions src/gui/accountsettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
#include "syncresult.h"
#include "ignorelisttablewidget.h"
#include "wizard/owncloudwizard.h"
#include "ui_mnemonicdialog.h"

#include <cmath>

Expand All @@ -63,6 +64,9 @@
namespace {
constexpr auto propertyFolder = "folder";
constexpr auto propertyPath = "path";
constexpr auto e2eUiActionIdKey = "id";
constexpr auto e2EeUiActionEnableEncryptionId = "enable_encryption";
constexpr auto e2EeUiActionDisplayMnemonicId = "display_mnemonic";
}

namespace OCC {
Expand Down Expand Up @@ -223,20 +227,7 @@ AccountSettings::AccountSettings(AccountState *accountState, QWidget *parent)
_ui->quotaProgressBar->setStyleSheet(QString::fromLatin1(progressBarStyleC).arg(color.name()));*/

// Connect E2E stuff
connect(this, &AccountSettings::requestMnemonic, _accountState->account()->e2e(), &ClientSideEncryption::slotRequestMnemonic);
connect(_accountState->account()->e2e(), &ClientSideEncryption::showMnemonic, this, &AccountSettings::slotShowMnemonic);

connect(_accountState->account()->e2e(), &ClientSideEncryption::mnemonicGenerated, this, &AccountSettings::slotNewMnemonicGenerated);
if (_accountState->account()->e2e()->newMnemonicGenerated()) {
slotNewMnemonicGenerated();
} else {
_ui->encryptionMessage->setText(tr("This account supports End-to-End encryption"));

auto *mnemonic = new QAction(tr("Display mnemonic"), this);
connect(mnemonic, &QAction::triggered, this, &AccountSettings::requestMnemonic);
_ui->encryptionMessage->addAction(mnemonic);
_ui->encryptionMessage->hide();
}
initializeE2eEncryption();

_ui->connectLabel->setText(tr("No account configured."));

Expand All @@ -249,16 +240,34 @@ AccountSettings::AccountSettings(AccountState *accountState, QWidget *parent)
customizeStyle();
}

void AccountSettings::slotNewMnemonicGenerated()
void AccountSettings::slotE2eEncryptionMnemonicReady()
{
auto *const actionDisplayMnemonic = addActionToEncryptionMessage(tr("Display mnemonic"), e2EeUiActionDisplayMnemonicId);
connect(actionDisplayMnemonic, &QAction::triggered, this, [this]() {
displayMnemonic(_accountState->account()->e2e()->_mnemonic);
});
_ui->encryptionMessage->setText(tr("This account supports End-to-End encryption"));
_ui->encryptionMessage->show();

}

auto *mnemonic = new QAction(tr("Enable encryption"), this);
connect(mnemonic, &QAction::triggered, this, &AccountSettings::requestMnemonic);
connect(mnemonic, &QAction::triggered, _ui->encryptionMessage, &KMessageWidget::hide);
void AccountSettings::slotE2eEncryptionGenerateKeys()
{
connect(_accountState->account()->e2e(), &ClientSideEncryption::initializationFinished, this, &AccountSettings::slotE2eEncryptionInitializationFinished);
_accountState->account()->setE2eEncryptionKeysGenerationAllowed(true);
_accountState->account()->e2e()->initialize(_accountState->account());
}

_ui->encryptionMessage->addAction(mnemonic);
_ui->encryptionMessage->show();
void AccountSettings::slotE2eEncryptionInitializationFinished(bool isNewMnemonicGenerated)
{
disconnect(_accountState->account()->e2e(), &ClientSideEncryption::initializationFinished, this, &AccountSettings::slotE2eEncryptionInitializationFinished);
if (!_accountState->account()->e2e()->_mnemonic.isEmpty()) {
removeActionFromEncryptionMessage(e2EeUiActionEnableEncryptionId);
slotE2eEncryptionMnemonicReady();
if (isNewMnemonicGenerated) {
displayMnemonic(_accountState->account()->e2e()->_mnemonic);
}
}
}

void AccountSettings::slotEncryptFolderFinished(int status)
Expand Down Expand Up @@ -310,11 +319,6 @@ void AccountSettings::doExpand()
}
}

void AccountSettings::slotShowMnemonic(const QString &mnemonic)
{
AccountManager::instance()->displayMnemonic(mnemonic);
}

bool AccountSettings::canEncryptOrDecrypt (const FolderStatusModel::SubFolderInfo* info) {
if (info->_folder->syncResult().status() != SyncResult::Status::Success) {
QMessageBox msgBox;
Expand Down Expand Up @@ -965,6 +969,35 @@ void AccountSettings::slotSetSubFolderAvailability(Folder *folder, const QString
folder->scheduleThisFolderSoon();
}

void AccountSettings::displayMnemonic(const QString &mnemonic)
{
auto widget = QDialog(this);
Ui_Dialog ui;
ui.setupUi(&widget);
widget.setWindowTitle(tr("End-to-End encryption mnemonic"));
ui.label->setText(
tr("To protect your Cryptographic Identity, we encrypt it with a mnemonic of 12 dictionary words. "
"Please note these down and keep them safe. "
"They will be needed to add other devices to your account (like your mobile phone or laptop)."));
QFont monoFont(QStringLiteral("Monospace"));
monoFont.setStyleHint(QFont::TypeWriter);
ui.lineEdit->setFont(monoFont);
ui.lineEdit->setText(mnemonic);
ui.lineEdit->setReadOnly(true);

ui.lineEdit->setStyleSheet(QStringLiteral("QLineEdit{ color: black; background: lightgrey; border-style: inset;}"));

ui.lineEdit->focusWidget();
ui.lineEdit->selectAll();
ui.lineEdit->setAlignment(Qt::AlignCenter);

const QFont font(QStringLiteral(""), 0);
QFontMetrics fm(font);
ui.lineEdit->setFixedWidth(fm.horizontalAdvance(mnemonic));
widget.resize(widget.sizeHint());
widget.exec();
}

void AccountSettings::showConnectionLabel(const QString &message, QStringList errors)
{
const auto errStyle = QLatin1String("color:#ffffff; background-color:#bb4d4d;padding:5px;"
Expand Down Expand Up @@ -1417,6 +1450,46 @@ void AccountSettings::customizeStyle()
_ui->quotaProgressBar->setStyleSheet(QString::fromLatin1(progressBarStyleC).arg(color.name()));
}

void AccountSettings::initializeE2eEncryption()
{
if (!_accountState->account()->e2e()->_mnemonic.isEmpty()) {
slotE2eEncryptionMnemonicReady();
} else {
_ui->encryptionMessage->setText(tr("This account supports End-to-End encryption"));
_ui->encryptionMessage->hide();

auto *const actionEnableE2e = addActionToEncryptionMessage(tr("Enable encryption"), e2EeUiActionEnableEncryptionId);
connect(actionEnableE2e, &QAction::triggered, this, &AccountSettings::slotE2eEncryptionGenerateKeys);
}
}

void AccountSettings::removeActionFromEncryptionMessage(const QString &actionId)
{
const auto foundEnableEncryptionActionIt = std::find_if(std::cbegin(_ui->encryptionMessage->actions()), std::cend(_ui->encryptionMessage->actions()), [&actionId](const QAction *action) {
return action->property(e2eUiActionIdKey).toString() == actionId;
});
if (foundEnableEncryptionActionIt != std::cend(_ui->encryptionMessage->actions())) {
_ui->encryptionMessage->removeAction(*foundEnableEncryptionActionIt);
(*foundEnableEncryptionActionIt)->deleteLater();
}
}

QAction *AccountSettings::addActionToEncryptionMessage(const QString &actionTitle, const QString &actionId)
{
for (const auto &action : _ui->encryptionMessage->actions()) {
if (action->property(e2eUiActionIdKey) == actionId) {
return action;
}
}

auto *const action = new QAction(actionTitle, this);
if (!actionId.isEmpty()) {
action->setProperty(e2eUiActionIdKey, actionId);
}
_ui->encryptionMessage->addAction(action);
return action;
}

} // namespace OCC

#include "accountsettings.moc"
10 changes: 8 additions & 2 deletions src/gui/accountsettings.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,21 +104,27 @@ protected slots:
void slotLinkActivated(const QString &link);

// Encryption Related Stuff.
void slotShowMnemonic(const QString &mnemonic);
void slotNewMnemonicGenerated();
void slotE2eEncryptionMnemonicReady();
void slotE2eEncryptionGenerateKeys();
void slotE2eEncryptionInitializationFinished(bool isNewMnemonicGenerated);
void slotEncryptFolderFinished(int status);

void slotSelectiveSyncChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight,
const QVector<int> &roles);

private:
void displayMnemonic(const QString &mnemonic);
void showConnectionLabel(const QString &message,
QStringList errors = QStringList());
bool event(QEvent *) override;
void createAccountToolbox();
void openIgnoredFilesDialog(const QString & absFolderPath);
void customizeStyle();

void initializeE2eEncryption();
void removeActionFromEncryptionMessage(const QString &actionId);
QAction *addActionToEncryptionMessage(const QString &actionTitle, const QString &actionId);

/// Returns the alias of the selected folder, empty string if none
[[nodiscard]] QString selectedFolderAlias() const;

Expand Down
18 changes: 7 additions & 11 deletions src/gui/mnemonicdialog.ui
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<x>0</x>
<y>0</y>
<width>588</width>
<height>214</height>
<height>131</height>
</rect>
</property>
<property name="sizePolicy">
Expand All @@ -31,6 +31,9 @@
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>7</number>
</property>
<property name="sizeConstraint">
<enum>QLayout::SetMinimumSize</enum>
</property>
Expand All @@ -39,7 +42,7 @@
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>50</verstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
Expand Down Expand Up @@ -73,20 +76,13 @@
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QTextEdit" name="textEdit">
<property name="maximumSize">
<size>
<width>16777215</width>
<height>80</height>
</size>
</property>
</widget>
<widget class="QLineEdit" name="lineEdit"/>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
Expand Down
10 changes: 10 additions & 0 deletions src/libsync/account.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -933,4 +933,14 @@ bool Account::trustCertificates() const
return _trustCertificates;
}

void Account::setE2eEncryptionKeysGenerationAllowed(bool allowed)
{
_e2eEncryptionKeysGenerationAllowed = allowed;
}

[[nodiscard]] bool Account::e2eEncryptionKeysGenerationAllowed() const
{
return _e2eEncryptionKeysGenerationAllowed;
}

} // namespace OCC
6 changes: 6 additions & 0 deletions src/libsync/account.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ class OWNCLOUDSYNC_EXPORT Account : public QObject
Q_PROPERTY(QString displayName MEMBER _displayName)
Q_PROPERTY(QString prettyName READ prettyName NOTIFY prettyNameChanged)
Q_PROPERTY(QUrl url MEMBER _url)
Q_PROPERTY(bool e2eEncryptionKeysGenerationAllowed MEMBER _e2eEncryptionKeysGenerationAllowed)

public:
static AccountPtr create();
Expand Down Expand Up @@ -300,6 +301,9 @@ class OWNCLOUDSYNC_EXPORT Account : public QObject
void setTrustCertificates(bool trustCertificates);
[[nodiscard]] bool trustCertificates() const;

void setE2eEncryptionKeysGenerationAllowed(bool allowed);
[[nodiscard]] bool e2eEncryptionKeysGenerationAllowed() const;

public slots:
/// Used when forgetting credentials
void clearQNAMCache();
Expand Down Expand Up @@ -355,6 +359,8 @@ protected Q_SLOTS:

bool _trustCertificates = false;

bool _e2eEncryptionKeysGenerationAllowed = false;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you make it a property registered to Qt metaobject system ?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please fix this and clean history of commits if needed
that said, I approve it works fine !
congratulations


QWeakPointer<Account> _sharedThis;
QString _id;
QString _davUser;
Expand Down
20 changes: 6 additions & 14 deletions src/libsync/clientsideencryption.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1082,11 +1082,6 @@ void ClientSideEncryption::forgetSensitiveData(const AccountPtr &account)
startDeleteJob(user + e2e_mnemonic);
}

void ClientSideEncryption::slotRequestMnemonic()
{
emit showMnemonic(_mnemonic);
}

void ClientSideEncryption::generateKeyPair(const AccountPtr &account)
{
// AES/GCM/NoPadding,
Expand Down Expand Up @@ -1223,11 +1218,8 @@ void ClientSideEncryption::encryptPrivateKey(const AccountPtr &account)
{
QStringList list = WordList::getRandomWords(12);
_mnemonic = list.join(' ');
_newMnemonicGenerated = true;
qCInfo(lcCse()) << "mnemonic Generated:" << _mnemonic;

emit mnemonicGenerated(_mnemonic);

QString passPhrase = list.join(QString()).toLower();
qCInfo(lcCse()) << "Passphrase Generated:" << passPhrase;

Expand All @@ -1246,7 +1238,7 @@ void ClientSideEncryption::encryptPrivateKey(const AccountPtr &account)
writePrivateKey(account);
writeCertificate(account);
writeMnemonic(account);
emit initializationFinished();
emit initializationFinished(true);
break;
default:
qCInfo(lcCse()) << "Store private key failed, return code:" << retCode;
Expand All @@ -1255,11 +1247,6 @@ void ClientSideEncryption::encryptPrivateKey(const AccountPtr &account)
job->start();
}

bool ClientSideEncryption::newMnemonicGenerated() const
{
return _newMnemonicGenerated;
}

void ClientSideEncryption::decryptPrivateKey(const AccountPtr &account, const QByteArray &key) {
QString msg = tr("Please enter your End-to-End encryption passphrase:<br>"
"<br>"
Expand Down Expand Up @@ -1349,6 +1336,11 @@ void ClientSideEncryption::getPublicKeyFromServer(const AccountPtr &account)
fetchAndValidatePublicKeyFromServer(account);
} else if (retCode == 404) {
qCInfo(lcCse()) << "No public key on the server";
if (!account->e2eEncryptionKeysGenerationAllowed()) {
qCInfo(lcCse()) << "User did not allow E2E keys generation.";
emit initializationFinished();
return;
}
generateKeyPair(account);
} else {
qCInfo(lcCse()) << "Error while requesting public key: " << retCode;
Expand Down
Loading