Skip to content

Commit

Permalink
Merge pull request #5067 from nextcloud/bugfix/e2e-do-not-generate-ke…
Browse files Browse the repository at this point in the history
…ys-without-request

E2EE. Do not generate keypair without user request.
  • Loading branch information
allexzander authored Nov 1, 2022
2 parents 2839c95 + 9ab89da commit 3755914
Show file tree
Hide file tree
Showing 9 changed files with 136 additions and 81 deletions.
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;

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

0 comments on commit 3755914

Please sign in to comment.