Skip to content

Commit

Permalink
allow to select and store the certificate to use for e2e
Browse files Browse the repository at this point in the history
Signed-off-by: Matthieu Gallien <[email protected]>
  • Loading branch information
mgallien committed Nov 27, 2023
1 parent 0589c76 commit 72efae4
Show file tree
Hide file tree
Showing 14 changed files with 360 additions and 260 deletions.
12 changes: 8 additions & 4 deletions src/gui/EncryptionTokenSelectionWindow.qml
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,9 @@ import "./tray"
ApplicationWindow {
id: encryptionKeyChooserDialog

required property var tokensInfo
required property var keysInfo
required property var certificatesInfo
required property ClientSideTokenSelector certificateSelector
property string selectedSerialNumber: ''

flags: Qt.Window | Qt.Dialog
visible: true
Expand Down Expand Up @@ -94,18 +95,19 @@ ApplicationWindow {
currentIndex: -1

model: DelegateModel {
model: keysInfo
model: certificatesInfo

delegate: ItemDelegate {
width: tokensListView.contentItem.width

text: modelData.label
text: modelData.subject

highlighted: tokensListView.currentIndex === index

onClicked: function()
{
tokensListView.currentIndex = index
selectedSerialNumber = modelData.serialNumber
}
}
}
Expand All @@ -126,10 +128,12 @@ ApplicationWindow {

onAccepted: function() {
Systray.destroyDialog(encryptionKeyChooserDialog)
certificateSelector.serialNumber = selectedSerialNumber
}

onRejected: function() {
Systray.destroyDialog(encryptionKeyChooserDialog)
certificateSelector.serialNumber = ''
}
}
}
Expand Down
7 changes: 7 additions & 0 deletions src/gui/accountmanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ constexpr auto serverVersionC = "serverVersion";
constexpr auto serverColorC = "serverColor";
constexpr auto serverTextColorC = "serverTextColor";
constexpr auto skipE2eeMetadataChecksumValidationC = "skipE2eeMetadataChecksumValidation";
constexpr auto encryptionCertificateSerialNumberC = "encryptionCertificateSerialNumber";
constexpr auto encryptionCertificateIssuerC = "encryptionCertificateIssuer";
constexpr auto generalC = "General";

constexpr auto dummyAuthTypeC = "dummy";
Expand Down Expand Up @@ -316,6 +318,8 @@ void AccountManager::saveAccountHelper(Account *acc, QSettings &settings, bool s
settings.setValue(QLatin1String(serverVersionC), acc->_serverVersion);
settings.setValue(QLatin1String(serverColorC), acc->_serverColor);
settings.setValue(QLatin1String(serverTextColorC), acc->_serverTextColor);
settings.setValue(QLatin1String(encryptionCertificateSerialNumberC), acc->encryptionCertificateSerialNumber());
settings.setValue(QLatin1String(encryptionCertificateIssuerC), acc->encryptionCertificateIssuer());
if (!acc->_skipE2eeMetadataChecksumValidation) {
settings.remove(QLatin1String(skipE2eeMetadataChecksumValidationC));
} else {
Expand Down Expand Up @@ -442,6 +446,9 @@ AccountPtr AccountManager::loadAccountHelper(QSettings &settings)

acc->setCredentials(CredentialsFactory::create(authType));

acc->setEncryptionCertificateSerialNumber(settings.value(QLatin1String(encryptionCertificateSerialNumberC)).toString());
acc->setEncryptionCertificateIssuer(settings.value(QLatin1String(encryptionCertificateIssuerC)).toString());

// now the server cert, it is in the general group
settings.beginGroup(QLatin1String(generalC));
const auto certs = QSslCertificate::fromData(settings.value(caCertsKeyC).toByteArray());
Expand Down
30 changes: 10 additions & 20 deletions src/gui/accountsettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -269,10 +269,12 @@ void AccountSettings::slotE2eEncryptionMnemonicReady()
disableEncryptionForAccount(_accountState->account());
});

const auto actionDisplayMnemonic = addActionToEncryptionMessage(tr("Display mnemonic"), e2EeUiActionDisplayMnemonicId);
connect(actionDisplayMnemonic, &QAction::triggered, this, [this]() {
displayMnemonic(_accountState->account()->e2e()->getMnemonic());
});
if (!_accountState->account()->e2e()->getMnemonic().isEmpty()) {
const auto actionDisplayMnemonic = addActionToEncryptionMessage(tr("Display mnemonic"), e2EeUiActionDisplayMnemonicId);
connect(actionDisplayMnemonic, &QAction::triggered, this, [this]() {
displayMnemonic(_accountState->account()->e2e()->getMnemonic());
});
}

_ui->encryptionMessage->setMessageType(KMessageWidget::Positive);
_ui->encryptionMessage->setText(tr("End-to-end encryption has been enabled for this account"));
Expand All @@ -283,16 +285,14 @@ void AccountSettings::slotE2eEncryptionMnemonicReady()
void AccountSettings::slotE2eEncryptionGenerateKeys()
{
connect(_accountState->account()->e2e(), &ClientSideEncryption::initializationFinished, this, &AccountSettings::slotE2eEncryptionInitializationFinished);
connect(_accountState->account()->e2e(), &ClientSideEncryption::displayTokenInitDialog, this, &AccountSettings::slotDisplayTokenInitDialog);
_accountState->account()->setE2eEncryptionKeysGenerationAllowed(true);
_accountState->account()->setAskUserForMnemonic(true);
_accountState->account()->e2e()->initialize(_accountState->account());
_accountState->account()->e2e()->initialize(this, _accountState->account());
}

void AccountSettings::slotE2eEncryptionInitializationFinished(bool isNewMnemonicGenerated)
{
disconnect(_accountState->account()->e2e(), &ClientSideEncryption::initializationFinished, this, &AccountSettings::slotE2eEncryptionInitializationFinished);
disconnect(_accountState->account()->e2e(), &ClientSideEncryption::displayTokenInitDialog, this, &AccountSettings::slotDisplayTokenInitDialog);
if (_accountState->account()->e2e()->isInitialized()) {
removeActionFromEncryptionMessage(e2EeUiActionEnableEncryptionId);
slotE2eEncryptionMnemonicReady();
Expand All @@ -303,14 +303,6 @@ void AccountSettings::slotE2eEncryptionInitializationFinished(bool isNewMnemonic
_accountState->account()->setAskUserForMnemonic(false);
}

void AccountSettings::slotDisplayTokenInitDialog()
{
disconnect(_accountState->account()->e2e(), &ClientSideEncryption::initializationFinished, this, &AccountSettings::slotE2eEncryptionInitializationFinished);
disconnect(_accountState->account()->e2e(), &ClientSideEncryption::displayTokenInitDialog, this, &AccountSettings::slotDisplayTokenInitDialog);
Systray::instance()->createTokenInitDialog(_accountState->account()->e2e()->discoveredTokens(),
_accountState->account()->e2e()->discoveredKeys());
}

void AccountSettings::slotEncryptFolderFinished(int status)
{
qCInfo(lcAccountSettings) << "Current folder encryption status code:" << status;
Expand Down Expand Up @@ -376,7 +368,7 @@ bool AccountSettings::canEncryptOrDecrypt(const FolderStatusModel::SubFolderInfo
return false;
}

if (!_accountState->account()->e2e() || _accountState->account()->e2e()->isInitialized()) {
if (!_accountState->account()->e2e() || !_accountState->account()->e2e()->isInitialized()) {
QMessageBox msgBox;
msgBox.setText(tr("End-to-end encryption is not configured on this device. "
"Once it is configured, you will be able to encrypt this folder.\n"
Expand Down Expand Up @@ -1624,9 +1616,7 @@ void AccountSettings::initializeE2eEncryption()
connect(_accountState->account()->e2e(), &ClientSideEncryption::initializationFinished, this, &AccountSettings::slotPossiblyUnblacklistE2EeFoldersAndRestartSync);

if (_accountState->account()->e2e()->isInitialized()) {
if (!_accountState->account()->e2e()->getMnemonic().isEmpty()) {
slotE2eEncryptionMnemonicReady();
}
slotE2eEncryptionMnemonicReady();
} else {
initializeE2eEncryptionSettingsMessage();

Expand All @@ -1640,7 +1630,7 @@ void AccountSettings::initializeE2eEncryption()
}
});
_accountState->account()->setE2eEncryptionKeysGenerationAllowed(false);
_accountState->account()->e2e()->initialize(_accountState->account());
_accountState->account()->e2e()->initialize(this, _accountState->account());
}
}

Expand Down
1 change: 0 additions & 1 deletion src/gui/accountsettings.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,6 @@ protected slots:
void slotE2eEncryptionMnemonicReady();
void slotE2eEncryptionGenerateKeys();
void slotE2eEncryptionInitializationFinished(bool isNewMnemonicGenerated);
void slotDisplayTokenInitDialog();
void slotEncryptFolderFinished(int status);

void slotSelectiveSyncChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight,
Expand Down
2 changes: 1 addition & 1 deletion src/gui/connectionvalidator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ void ConnectionValidator::slotUserFetched(UserInfo *userInfo)

#ifndef TOKEN_AUTH_ONLY
connect(_account->e2e(), &ClientSideEncryption::initializationFinished, this, &ConnectionValidator::reportConnected);
_account->e2e()->initialize(_account);
_account->e2e()->initialize(nullptr, _account);
#else
reportResult(Connected);
#endif
Expand Down
1 change: 1 addition & 0 deletions src/gui/owncloudgui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ ownCloudGui::ownCloudGui(Application *parent)
qmlRegisterUncreatableType<UnifiedSearchResultsListModel>("com.nextcloud.desktopclient", 1, 0, "UnifiedSearchResultsListModel", "UnifiedSearchResultsListModel");
qmlRegisterUncreatableType<UserStatus>("com.nextcloud.desktopclient", 1, 0, "UserStatus", "Access to Status enum");
qmlRegisterUncreatableType<Sharee>("com.nextcloud.desktopclient", 1, 0, "Sharee", "Access to Type enum");
qmlRegisterUncreatableType<ClientSideTokenSelector>("com.nextcloud.desktopclient", 1, 0, "ClientSideTokenSelector", "Access to the certificate selector");

qRegisterMetaTypeStreamOperators<Emoji>();

Expand Down
46 changes: 2 additions & 44 deletions src/gui/systray.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "configfile.h"
#include "accessmanager.h"
#include "callstatechecker.h"
#include "clientsidetokenselector.h"

#include <QCursor>
#include <QGuiApplication>
Expand All @@ -35,6 +36,7 @@
#include <QMenu>
#include <QGuiApplication>
#include <QQuickView>
#include <QMessageBox>

#ifdef USE_FDO_NOTIFICATIONS
#include <QDBusConnection>
Expand Down Expand Up @@ -413,50 +415,6 @@ void Systray::createFileActivityDialog(const QString &localPath)
Q_EMIT showFileDetailsPage(localPath, FileDetailsPage::Activity);
}

void Systray::createTokenInitDialog(const QVariantList &tokensInfo,
const QVariantList &keysInfo)
{
if(_tokenInitDialog) {
destroyDialog(_tokenInitDialog);
_tokenInitDialog = nullptr;
}

qCDebug(lcSystray) << "Opening new token init dialog with " << tokensInfo.size() << "possible tokens";

if (!_trayEngine) {
qCWarning(lcSystray) << "Could not open token init dialog as no tray engine was available";
return;
}

const QVariantMap initialProperties{
{"tokensInfo", tokensInfo},
{"keysInfo", keysInfo}
};

QQmlComponent encryptionTokenDialog(_trayEngine, QStringLiteral("qrc:/qml/src/gui/EncryptionTokenSelectionWindow.qml"));

if (!encryptionTokenDialog.isError()) {
const auto createdDialog = encryptionTokenDialog.createWithInitialProperties(initialProperties);
const auto dialog = qobject_cast<QQuickWindow*>(createdDialog);

if(!dialog) {
qCWarning(lcSystray) << "File details dialog window resulted in creation of object that was not a window!";
return;
}

_tokenInitDialog = dialog;

Q_EMIT hideSettingsDialog();

dialog->show();
dialog->raise();
dialog->requestActivate();

} else {
qCWarning(lcSystray) << encryptionTokenDialog.errorString();
}
}

void Systray::presentShareViewInTray(const QString &localPath)
{
const auto folder = FolderMan::instance()->folderForPath(localPath);
Expand Down
4 changes: 2 additions & 2 deletions src/gui/systray.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ class QGuiApplication;

namespace OCC {

class ClientSideTokenSelector;

class AccessManagerFactory : public QQmlNetworkAccessManagerFactory
{
public:
Expand Down Expand Up @@ -147,8 +149,6 @@ public slots:

void createShareDialog(const QString &localPath);
void createFileActivityDialog(const QString &localPath);
void createTokenInitDialog(const QVariantList &tokensInfo,
const QVariantList &keysInfo);

void presentShareViewInTray(const QString &localPath);

Expand Down
34 changes: 34 additions & 0 deletions src/libsync/account.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1035,6 +1035,40 @@ QString Account::encryptionHardwareTokenDriverPath() const
return {};
}

QString Account::encryptionCertificateSerialNumber() const
{
return _encryptionCertificateSerialNumber;
}

void Account::setEncryptionCertificateSerialNumber(const QString &serialNumber)
{
if (_encryptionCertificateSerialNumber == serialNumber) {
return;
}

_encryptionCertificateSerialNumber = serialNumber;
_e2e.usbTokenInformation()->setSerialNumber(serialNumber);
Q_EMIT encryptionCertificateSerialNumberChanged();
Q_EMIT wantsAccountSaved(this);
}

QString Account::encryptionCertificateIssuer() const
{
return _encryptionCertificateIssuer;
}

void Account::setEncryptionCertificateIssuer(const QString &issuer)
{
if (_encryptionCertificateIssuer == issuer) {
return;
}

_encryptionCertificateIssuer = issuer;
_e2e.usbTokenInformation()->setIssuer(issuer);
Q_EMIT encryptionCertificateIssuerChanged();
Q_EMIT wantsAccountSaved(this);
}

void Account::setAskUserForMnemonic(const bool ask)
{
_e2eAskUserForMnemonic = ask;
Expand Down
17 changes: 17 additions & 0 deletions src/libsync/account.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ class OWNCLOUDSYNC_EXPORT Account : public QObject
Q_PROPERTY(bool askUserForMnemonic READ askUserForMnemonic WRITE setAskUserForMnemonic NOTIFY askUserForMnemonicChanged)
Q_PROPERTY(bool enforceUseHardwareTokenEncryption READ enforceUseHardwareTokenEncryption NOTIFY enforceUseHardwareTokenEncryptionChanged)
Q_PROPERTY(QString encryptionHardwareTokenDriverPath READ encryptionHardwareTokenDriverPath NOTIFY encryptionHardwareTokenDriverPathChanged)
Q_PROPERTY(QString encryptionCertificateSerialNumber READ encryptionCertificateSerialNumber WRITE setEncryptionCertificateSerialNumber NOTIFY encryptionCertificateSerialNumberChanged)
Q_PROPERTY(QString encryptionCertificateIssuer READ encryptionCertificateIssuer WRITE setEncryptionCertificateIssuer NOTIFY encryptionCertificateIssuerChanged)

public:
static AccountPtr create();
Expand Down Expand Up @@ -332,6 +334,14 @@ class OWNCLOUDSYNC_EXPORT Account : public QObject

[[nodiscard]] QString encryptionHardwareTokenDriverPath() const;

[[nodiscard]] QString encryptionCertificateSerialNumber() const;

void setEncryptionCertificateSerialNumber(const QString &serialNumber);

[[nodiscard]] QString encryptionCertificateIssuer() const;

void setEncryptionCertificateIssuer(const QString &issuer);

public slots:
/// Used when forgetting credentials
void clearQNAMCache();
Expand Down Expand Up @@ -378,6 +388,9 @@ public slots:
void lockFileSuccess();
void lockFileError(const QString&);

void encryptionCertificateSerialNumberChanged();
void encryptionCertificateIssuerChanged();

protected Q_SLOTS:
void slotCredentialsFetched();
void slotCredentialsAsked();
Expand Down Expand Up @@ -451,6 +464,10 @@ private slots:

QHash<QString, QVector<SyncFileItem::LockStatus>> _lockStatusChangeInprogress;

QString _encryptionCertificateSerialNumber;

QString _encryptionCertificateIssuer;

/* IMPORTANT - remove later - FIXME MS@2019-12-07 -->
* TODO: For "Log out" & "Remove account": Remove client CA certs and KEY!
*
Expand Down
Loading

0 comments on commit 72efae4

Please sign in to comment.