Skip to content

Commit

Permalink
allow user to check and detect its usb token for e2e encryption
Browse files Browse the repository at this point in the history
Signed-off-by: Matthieu Gallien <[email protected]>
  • Loading branch information
mgallien committed Nov 15, 2023
1 parent e307cb5 commit d2a9b54
Show file tree
Hide file tree
Showing 18 changed files with 584 additions and 15 deletions.
2 changes: 2 additions & 0 deletions NEXTCLOUD.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -80,3 +80,5 @@ endif()
if (APPLE)
option( BUILD_FILE_PROVIDER_MODULE "Build the macOS virtual files File Provider module" OFF )
endif()

set (CLIENTSIDEENCRYPTION_ENFORCE_USB_TOKEN true)
2 changes: 2 additions & 0 deletions config.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,6 @@

#cmakedefine CFAPI_SHELL_EXTENSIONS_LIB_NAME "@CFAPI_SHELL_EXTENSIONS_LIB_NAME@"

#cmakedefine CLIENTSIDEENCRYPTION_ENFORCE_USB_TOKEN @CLIENTSIDEENCRYPTION_ENFORCE_USB_TOKEN@

#endif
1 change: 1 addition & 0 deletions resources.qrc
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
<file>src/gui/PredefinedStatusButton.qml</file>
<file>src/gui/BasicComboBox.qml</file>
<file>src/gui/ErrorBox.qml</file>
<file>src/gui/EncryptionTokenSelectionWindow.qml</file>
<file>src/gui/filedetails/FileActivityView.qml</file>
<file>src/gui/filedetails/FileDetailsPage.qml</file>
<file>src/gui/filedetails/FileDetailsView.qml</file>
Expand Down
1 change: 1 addition & 0 deletions src/gui/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ set(client_SRCS
syncrunfilelog.cpp
systray.h
systray.cpp
EncryptionTokenSelectionWindow.qml
thumbnailjob.h
thumbnailjob.cpp
userinfo.h
Expand Down
142 changes: 142 additions & 0 deletions src/gui/EncryptionTokenSelectionWindow.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
/*
* Copyright (C) 2023 by Matthieu Gallien <[email protected]>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/

import QtQuick 2.15
import QtQuick.Layouts 1.15
import QtQuick.Controls 2.15
import QtQml.Models 2.15

import com.nextcloud.desktopclient 1.0
import Style 1.0

import "./tray"

ApplicationWindow {
id: encryptionKeyChooserDialog

required property var tokensInfo
required property var keysInfo

flags: Qt.Window | Qt.Dialog
visible: true
modality: Qt.ApplicationModal

width: 400
height: 600
minimumWidth: 400
minimumHeight: 600

title: qsTr('Token Encryption Key Chooser')

// TODO: Rather than setting all these palette colours manually,
// create a custom style and do it for all components globally
palette {
text: Style.ncTextColor
windowText: Style.ncTextColor
buttonText: Style.ncTextColor
brightText: Style.ncTextBrightColor
highlight: Style.lightHover
highlightedText: Style.ncTextColor
light: Style.lightHover
midlight: Style.ncSecondaryTextColor
mid: Style.darkerHover
dark: Style.menuBorder
button: Style.buttonBackgroundColor
window: Style.backgroundColor
base: Style.backgroundColor
toolTipBase: Style.backgroundColor
toolTipText: Style.ncTextColor
}

onClosing: function(close) {
Systray.destroyDialog(self);
close.accepted = true
}

ColumnLayout {
anchors.fill: parent
anchors.leftMargin: 20
anchors.rightMargin: 20
anchors.bottomMargin: 20
anchors.topMargin: 20
spacing: 15
z: 2

EnforcedPlainTextLabel {
text: qsTr("Available Keys for end-to-end Encryption:")
font.bold: true
font.pixelSize: Style.bigFontPixelSizeResolveConflictsDialog
Layout.fillWidth: true
}

ScrollView {
Layout.fillWidth: true
Layout.fillHeight: true

clip: true

ScrollBar.horizontal.policy: ScrollBar.AlwaysOff

ListView {
id: tokensListView

currentIndex: -1

model: DelegateModel {
model: keysInfo

delegate: ItemDelegate {
width: tokensListView.contentItem.width

text: modelData.label

highlighted: tokensListView.currentIndex === index

onClicked: function()
{
tokensListView.currentIndex = index
}
}
}
}
}

DialogButtonBox {
Layout.fillWidth: true

Button {
text: qsTr("Choose")
DialogButtonBox.buttonRole: DialogButtonBox.AcceptRole
}
Button {
text: qsTr("Cancel")
DialogButtonBox.buttonRole: DialogButtonBox.RejectRole
}

onAccepted: function() {
Systray.destroyDialog(encryptionKeyChooserDialog)
}

onRejected: function() {
Systray.destroyDialog(encryptionKeyChooserDialog)
}
}
}

Rectangle {
color: Style.backgroundColor
anchors.fill: parent
z: 1
}
}
10 changes: 10 additions & 0 deletions src/gui/accountsettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,7 @@ 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());
Expand All @@ -291,6 +292,7 @@ void AccountSettings::slotE2eEncryptionGenerateKeys()
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 @@ -301,6 +303,14 @@ 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
3 changes: 2 additions & 1 deletion src/gui/accountsettings.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ class AccountSettings : public QWidget
~AccountSettings() override;
[[nodiscard]] QSize sizeHint() const override { return ownCloudGui::settingsDialogSize(); }
bool canEncryptOrDecrypt(const FolderStatusModel::SubFolderInfo* folderInfo);
[[nodiscard]] OCC::AccountState *accountsState() const { return _accountState; }

signals:
void folderChanged();
Expand All @@ -72,7 +73,6 @@ public slots:
void slotUpdateQuota(qint64 total, qint64 used);
void slotAccountStateChanged();
void slotStyleChanged();
OCC::AccountState *accountsState() { return _accountState; }
void slotHideSelectiveSyncWidget();

protected slots:
Expand Down Expand Up @@ -106,6 +106,7 @@ 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
4 changes: 4 additions & 0 deletions src/gui/owncloudgui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -571,6 +571,10 @@ void ownCloudGui::slotShowSettings()
if (_settingsDialog.isNull()) {
_settingsDialog = new SettingsDialog(this);
_settingsDialog->setAttribute(Qt::WA_DeleteOnClose, true);

connect(_tray.data(), &Systray::hideSettingsDialog,
_settingsDialog.data(), &SettingsDialog::close);

_settingsDialog->show();
}
raiseDialog(_settingsDialog.data());
Expand Down
8 changes: 4 additions & 4 deletions src/gui/settingsdialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -137,10 +137,6 @@ SettingsDialog::SettingsDialog(ownCloudGui *gui, QWidget *parent)
_actionGroupWidgets.insert(generalAction, generalSettings);
_actionGroupWidgets.insert(networkAction, networkSettings);

foreach(auto ai, AccountManager::instance()->accounts()) {
accountAdded(ai.data());
}

QTimer::singleShot(1, this, &SettingsDialog::showFirstPage);

auto *showLogWindow = new QAction(this);
Expand Down Expand Up @@ -215,6 +211,10 @@ void SettingsDialog::slotSwitchPage(QAction *action)

void SettingsDialog::showFirstPage()
{
foreach(auto ai, AccountManager::instance()->accounts()) {
accountAdded(ai.data());
}

QList<QAction *> actions = _toolBar->actions();
if (!actions.empty()) {
actions.first()->trigger();
Expand Down
45 changes: 45 additions & 0 deletions src/gui/systray.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include <QScreen>
#include <QMenu>
#include <QGuiApplication>
#include <QQuickView>

#ifdef USE_FDO_NOTIFICATIONS
#include <QDBusConnection>
Expand Down Expand Up @@ -412,6 +413,50 @@ 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
9 changes: 7 additions & 2 deletions src/gui/systray.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@
#ifndef SYSTRAY_H
#define SYSTRAY_H

#include <QSystemTrayIcon>

#include "accountmanager.h"
#include "tray/usermodel.h"

#include <QSystemTrayIcon>
#include <QQuickImageProvider>
#include <QQmlNetworkAccessManagerFactory>

class QScreen;
Expand Down Expand Up @@ -112,6 +112,8 @@ class Systray
void syncIsPausedChanged();
void isOpenChanged();

void hideSettingsDialog();

public slots:
void setTrayEngine(QQmlApplicationEngine *trayEngine);
void create();
Expand Down Expand Up @@ -145,6 +147,8 @@ 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 Expand Up @@ -185,6 +189,7 @@ private slots:
QSet<qlonglong> _callsAlreadyNotified;
QPointer<QObject> _editFileLocallyLoadingDialog;
QVector<QQuickWindow*> _fileDetailDialogs;
QQuickWindow* _tokenInitDialog = nullptr;
};

} // namespace OCC
Expand Down
2 changes: 2 additions & 0 deletions src/libsync/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@ set(libsync_SRCS
clientsideencryption.cpp
clientsideencryptionjobs.h
clientsideencryptionjobs.cpp
clientsidetokenselector.h
clientsidetokenselector.cpp
datetimeprovider.h
datetimeprovider.cpp
ocsuserstatusconnector.h
Expand Down
6 changes: 4 additions & 2 deletions src/libsync/account.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
#include "clientsideencryption.h"
#include "ocsuserstatusconnector.h"

#include "config.h"

#include <QLoggingCategory>
#include <QNetworkReply>
#include <QNetworkAccessManager>
Expand Down Expand Up @@ -1023,9 +1025,9 @@ bool Account::askUserForMnemonic() const
return _e2eAskUserForMnemonic;
}

bool Account::useHardwareTokenEncryption() const
bool Account::enforceUseHardwareTokenEncryption() const
{
return !encryptionHardwareTokenDriverPath().isEmpty();
return CLIENTSIDEENCRYPTION_ENFORCE_USB_TOKEN;
}

QString Account::encryptionHardwareTokenDriverPath() const
Expand Down
Loading

0 comments on commit d2a9b54

Please sign in to comment.