From 6bcada6a9b4b6fe83793796afc09b9f827f047ef Mon Sep 17 00:00:00 2001 From: Matthieu Gallien Date: Thu, 30 Nov 2023 15:28:57 +0100 Subject: [PATCH] avoid blocking and show a busy dialog when discovering token content use a secondary thread to do discovery of the USB token display a busy dialog while we discover the list of certificates to get user to understand that the client is busy Signed-off-by: Matthieu Gallien --- resources.qrc | 1 + src/gui/accountsettings.cpp | 5 + src/gui/systray.cpp | 28 ++ src/gui/systray.h | 3 + .../tray/EncryptionTokenDiscoveryDialog.qml | 89 ++++++ src/libsync/clientsideencryption.cpp | 275 +++++++++--------- src/libsync/clientsideencryption.h | 6 +- .../clientsideencryptiontokenselector.cpp | 82 ++++-- .../clientsideencryptiontokenselector.h | 5 +- 9 files changed, 338 insertions(+), 156 deletions(-) create mode 100644 src/gui/tray/EncryptionTokenDiscoveryDialog.qml diff --git a/resources.qrc b/resources.qrc index 10d0d0ccc3523..ea4f081b072ca 100644 --- a/resources.qrc +++ b/resources.qrc @@ -48,6 +48,7 @@ src/gui/tray/TalkReplyTextField.qml src/gui/tray/CallNotificationDialog.qml src/gui/tray/EditFileLocallyLoadingDialog.qml + src/gui/tray/EncryptionTokenDiscoveryDialog.qml src/gui/tray/NCBusyIndicator.qml src/gui/tray/NCIconWithBackgroundImage.qml src/gui/tray/NCToolTip.qml diff --git a/src/gui/accountsettings.cpp b/src/gui/accountsettings.cpp index fa46ce27d15c4..44959b6925bf6 100644 --- a/src/gui/accountsettings.cpp +++ b/src/gui/accountsettings.cpp @@ -260,6 +260,11 @@ AccountSettings::AccountSettings(AccountState *accountState, QWidget *parent) this, &AccountSettings::slotUpdateQuota); customizeStyle(); + + connect(_accountState->account()->e2e(), &ClientSideEncryption::startingDiscoveryEncryptionUsbToken, + Systray::instance(), &Systray::createEncryptionTokenDiscoveryDialog); + connect(_accountState->account()->e2e(), &ClientSideEncryption::finishedDiscoveryEncryptionUsbToken, + Systray::instance(), &Systray::destroyEncryptionTokenDiscoveryDialog); } void AccountSettings::slotE2eEncryptionMnemonicReady() diff --git a/src/gui/systray.cpp b/src/gui/systray.cpp index 2b137273e71bf..22d3b1f573363 100644 --- a/src/gui/systray.cpp +++ b/src/gui/systray.cpp @@ -318,6 +318,34 @@ void Systray::createResolveConflictsDialog(const OCC::ActivityList &allConflicts dialog.take(); } +void Systray::createEncryptionTokenDiscoveryDialog() +{ + if (_encryptionTokenDiscoveryDialog) { + return; + } + + qCDebug(lcSystray) << "Opening an encryption token discovery dialog..."; + + const auto encryptionTokenDiscoveryDialog = new QQmlComponent(_trayEngine, QStringLiteral("qrc:/qml/src/gui/tray/EncryptionTokenDiscoveryDialog.qml")); + + if (encryptionTokenDiscoveryDialog->isError()) { + qCWarning(lcSystray) << encryptionTokenDiscoveryDialog->errorString(); + return; + } + + _encryptionTokenDiscoveryDialog = encryptionTokenDiscoveryDialog->createWithInitialProperties(QVariantMap{}); +} + +void Systray::destroyEncryptionTokenDiscoveryDialog() +{ + if (!_encryptionTokenDiscoveryDialog) { + return; + } + qCDebug(lcSystray) << "Closing an encryption token discovery dialog..."; + _encryptionTokenDiscoveryDialog->deleteLater(); + _encryptionTokenDiscoveryDialog = nullptr; +} + bool Systray::raiseDialogs() { return raiseFileDetailDialogs(); diff --git a/src/gui/systray.h b/src/gui/systray.h index 9d424a0a9c0be..e904719f12f2f 100644 --- a/src/gui/systray.h +++ b/src/gui/systray.h @@ -129,6 +129,8 @@ public slots: void createEditFileLocallyLoadingDialog(const QString &fileName); void destroyEditFileLocallyLoadingDialog(); void createResolveConflictsDialog(const OCC::ActivityList &allConflicts); + void createEncryptionTokenDiscoveryDialog(); + void destroyEncryptionTokenDiscoveryDialog(); void slotCurrentUserChanged(); @@ -188,6 +190,7 @@ private slots: QSet _callsAlreadyNotified; QPointer _editFileLocallyLoadingDialog; + QPointer _encryptionTokenDiscoveryDialog; QVector _fileDetailDialogs; QQuickWindow* _tokenInitDialog = nullptr; }; diff --git a/src/gui/tray/EncryptionTokenDiscoveryDialog.qml b/src/gui/tray/EncryptionTokenDiscoveryDialog.qml new file mode 100644 index 0000000000000..123cc750f7aa3 --- /dev/null +++ b/src/gui/tray/EncryptionTokenDiscoveryDialog.qml @@ -0,0 +1,89 @@ +import QtQuick 2.15 +import QtQuick.Window 2.15 +import Style 1.0 +import com.nextcloud.desktopclient 1.0 +import QtQuick.Layouts 1.15 +import QtQuick.Controls 2.15 + +ApplicationWindow { + id: root + flags: Qt.Dialog | Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint + + color: "transparent" + + width: 320 + height: contentLayout.implicitHeight + modality: Qt.ApplicationModal + + readonly property real fontPixelSize: Style.topLinePixelSize * 1.5 + readonly property real iconWidth: fontPixelSize * 2 + + // 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 + } + + Component.onCompleted: { + Systray.forceWindowInit(root); + x = Screen.width / 2 - width / 2 + y = Screen.height / 2 - height / 2 + root.show(); + root.raise(); + root.requestActivate(); + } + + Rectangle { + id: windowBackground + color: Style.backgroundColor + radius: Style.trayWindowRadius + border.color: palette.dark + anchors.fill: parent + } + + ColumnLayout { + id: contentLayout + anchors.left: parent.left + anchors.right: parent.right + anchors.leftMargin: Style.standardSpacing + anchors.rightMargin: Style.standardSpacing + spacing: Style.standardSpacing + + NCBusyIndicator { + id: busyIndicator + Layout.topMargin: Style.standardSpacing + Layout.alignment: Qt.AlignHCenter + Layout.preferredWidth: root.iconWidth + Layout.preferredHeight: root.iconWidth + imageSourceSizeHeight: root.iconWidth + imageSourceSizeWidth: root.iconWidth + padding: 0 + color: palette.windowText + running: true + } + EnforcedPlainTextLabel { + id: labelMessage + Layout.alignment: Qt.AlignHCenter + Layout.fillWidth: true + Layout.bottomMargin: Style.standardSpacing + text: qsTr("Discovering the certificates stored on your USB token") + elide: Text.ElideRight + font.pixelSize: root.fontPixelSize + horizontalAlignment: Text.AlignHCenter + } + } +} diff --git a/src/libsync/clientsideencryption.cpp b/src/libsync/clientsideencryption.cpp index a8746e3e662a9..5c2b55823ad59 100644 --- a/src/libsync/clientsideencryption.cpp +++ b/src/libsync/clientsideencryption.cpp @@ -45,6 +45,7 @@ #include #include #include +#include #include #include @@ -664,7 +665,7 @@ namespace internals { const QByteArray& binaryData); [[nodiscard]] std::optional encryptStringAsymmetricWithToken(ENGINE *sslEngine, - EVP_PKEY *publicKey, + PKCS11_KEY *publicKey, const QByteArray& binaryData); [[nodiscard]] std::optional decryptStringAsymmetric(ENGINE *sslEngine, @@ -688,7 +689,7 @@ std::optional encryptStringAsymmetric(const ClientSideEncryption &en } auto encryptedBase64Result = internals::encryptStringAsymmetricWithToken(encryptionEngine.sslEngine(), - PKCS11_get_public_key(encryptionEngine.getTokenPublicKey()), + encryptionEngine.getTokenPublicKey(), binaryData); if (!encryptedBase64Result) { @@ -733,6 +734,11 @@ std::optional encryptStringAsymmetric(const ClientSideEncryption &en std::optional decryptStringAsymmetric(const ClientSideEncryption &encryptionEngine, const QByteArray &base64Data) { + if (!encryptionEngine.isInitialized()) { + qCWarning(lcCse()) << "end-to-end encryption is disabled"; + return {}; + } + if (encryptionEngine.useTokenBasedEncryption()) { const auto decryptBase64Result = internals::decryptStringAsymmetricWithToken(encryptionEngine.sslEngine(), encryptionEngine.getTokenPrivateKey(), @@ -973,10 +979,10 @@ void debugOpenssl() namespace internals { std::optional encryptStringAsymmetricWithToken(ENGINE *sslEngine, - EVP_PKEY *publicKey, + PKCS11_KEY *publicKey, const QByteArray& binaryData) { - return encryptStringAsymmetric(sslEngine, publicKey, RSA_PKCS1_PADDING, binaryData); + return encryptStringAsymmetric(sslEngine, PKCS11_get_public_key(publicKey), RSA_PKCS1_PADDING, binaryData); } std::optional decryptStringAsymmetricWithToken(ENGINE *sslEngine, @@ -993,8 +999,6 @@ std::optional decryptStringAsymmetricWithToken(ENGINE *sslEngine, ClientSideEncryption::ClientSideEncryption() { - connect(&_usbTokenInformation, &ClientSideEncryptionTokenSelector::discoveredCertificatesChanged, - this, &ClientSideEncryption::completeHardwareTokenInitialization); } bool ClientSideEncryption::isInitialized() const @@ -1073,12 +1077,16 @@ void ClientSideEncryption::initialize(QWidget *settingsDialog, if (_usbTokenInformation.isSetup()) { initializeHardwareTokenEncryption(settingsDialog, account); } else if (account->e2eEncryptionKeysGenerationAllowed() && account->askUserForMnemonic()) { - _usbTokenInformation.searchForCertificates(account); - if (_usbTokenInformation.isSetup()) { - initializeHardwareTokenEncryption(settingsDialog, account); - } else { - emit initializationFinished(); - } + Q_EMIT startingDiscoveryEncryptionUsbToken(); + auto futureTokenDiscoveryResult = new QFutureWatcher(this); + auto tokenDiscoveryResult = _usbTokenInformation.searchForCertificates(account); + futureTokenDiscoveryResult->setFuture(tokenDiscoveryResult); + connect(futureTokenDiscoveryResult, &QFutureWatcher::finished, + this, [this, settingsDialog, account, futureTokenDiscoveryResult] () { + completeHardwareTokenInitialization(settingsDialog, account); + delete futureTokenDiscoveryResult; + Q_EMIT finishedDiscoveryEncryptionUsbToken(); + }); } else { emit initializationFinished(); } @@ -1099,151 +1107,163 @@ void ClientSideEncryption::initializeHardwareTokenEncryption(QWidget *settingsDi return; } - auto nslots = 0u; + auto tokensCount = 0u; PKCS11_SLOT *tokenSlots = nullptr; /* get information on all slots */ - if (PKCS11_enumerate_slots(ctx, &tokenSlots, &nslots) < 0) { + if (PKCS11_enumerate_slots(ctx, &tokenSlots, &tokensCount) < 0) { qCWarning(lcCse()) << "no slots available" << ERR_reason_error_string(ERR_get_error()); failedToInitialize(account); return; } - /* get first slot with a token */ - auto slot = PKCS11_find_token(ctx, tokenSlots, nslots); - if (slot == NULL || slot->token == NULL) { - qCWarning(lcCse()) << "no token available" << ERR_reason_error_string(ERR_get_error()); + auto currentSlot = static_cast(nullptr); + for(auto i = 0u; i < tokensCount; ++i) { + currentSlot = PKCS11_find_next_token(ctx, tokenSlots, tokensCount, currentSlot); + if (currentSlot == nullptr || currentSlot->token == nullptr) { + break; + } - failedToInitialize(account); - return; - } - qCInfo(lcCse()) << "Slot manufacturer......:" << slot->manufacturer; - qCInfo(lcCse()) << "Slot description.......:" << slot->description; - qCInfo(lcCse()) << "Slot token label.......:" << slot->token->label; - qCInfo(lcCse()) << "Slot token manufacturer:" << slot->token->manufacturer; - qCInfo(lcCse()) << "Slot token model.......:" << slot->token->model; - qCInfo(lcCse()) << "Slot token serialnr....:" << slot->token->serialnr; + qCDebug(lcCse()) << "Slot manufacturer......:" << currentSlot->manufacturer; + qCDebug(lcCse()) << "Slot description.......:" << currentSlot->description; + qCDebug(lcCse()) << "Slot token label.......:" << currentSlot->token->label; + qCDebug(lcCse()) << "Slot token manufacturer:" << currentSlot->token->manufacturer; + qCDebug(lcCse()) << "Slot token model.......:" << currentSlot->token->model; + qCDebug(lcCse()) << "Slot token serialnr....:" << currentSlot->token->serialnr; - auto logged_in = 0; - if (PKCS11_is_logged_in(slot, 0, &logged_in) != 0) { - qCWarning(lcCse()) << "PKCS11_is_logged_in failed" << ERR_reason_error_string(ERR_get_error()); + auto logged_in = 0; + if (PKCS11_is_logged_in(currentSlot, 0, &logged_in) != 0) { + qCWarning(lcCse()) << "PKCS11_is_logged_in failed" << ERR_reason_error_string(ERR_get_error()); - failedToInitialize(account); - return; - } + failedToInitialize(account); + return; + } - while (true) { - auto pinHasToBeCached = false; - auto newPin = _cachedPin; + while (true) { + auto pinHasToBeCached = false; + auto newPin = _cachedPin; + + if (newPin.isEmpty()) { + /* perform pkcs #11 login */ + bool ok; + newPin = QInputDialog::getText(settingsDialog, + tr("PIN needed to login to token"), + tr("Enter Certificate USB Token PIN:"), + QLineEdit::Password, + {}, + &ok); + if (!ok || newPin.isEmpty()) { + qCWarning(lcCse()) << "an USER pin is required"; + + Q_EMIT initializationFinished(); + return; + } + + pinHasToBeCached = true; + } + + const auto newPinData = newPin.toLatin1(); + if (PKCS11_login(currentSlot, 0, newPinData.data()) != 0) { + QMessageBox::warning(settingsDialog, + tr("Invalid PIN. Login failed"), + tr("Login to the token failed after providing the user PIN. It may be invalid or wrong. Please try again !"), + QMessageBox::Ok); + _cachedPin.clear(); + continue; + } - if (newPin.isEmpty()) { - /* perform pkcs #11 login */ - bool ok; - newPin = QInputDialog::getText(settingsDialog, - tr("PIN needed to login to token"), - tr("Enter Certificate USB Token PIN:"), - QLineEdit::Password, - {}, - &ok); - if (!ok || newPin.isEmpty()) { - qCWarning(lcCse()) << "an USER pin is required"; + /* check if user is logged in */ + if (PKCS11_is_logged_in(currentSlot, 0, &logged_in) != 0) { + qCWarning(lcCse()) << "PKCS11_is_logged_in failed" << ERR_reason_error_string(ERR_get_error()); + _cachedPin.clear(); failedToInitialize(account); return; } + if (!logged_in) { + qCWarning(lcCse()) << "PKCS11_is_logged_in says user is not logged in, expected to be logged in"; - pinHasToBeCached = true; - } - - const auto newPinData = newPin.toLatin1(); - if (PKCS11_login(slot, 0, newPinData.data()) != 0) { - QMessageBox::warning(settingsDialog, - tr("Invalid PIN. Login failed"), - tr("Login to the token failed after providing the user PIN. It may be invalid or wrong. Please try again !"), - QMessageBox::Ok); - _cachedPin.clear(); - continue; - } + _cachedPin.clear(); + failedToInitialize(account); + return; + } - /* check if user is logged in */ - if (PKCS11_is_logged_in(slot, 0, &logged_in) != 0) { - qCWarning(lcCse()) << "PKCS11_is_logged_in failed" << ERR_reason_error_string(ERR_get_error()); + if (pinHasToBeCached) { + cacheTokenPin(newPin); + } - _cachedPin.clear(); - failedToInitialize(account); - return; + break; } - if (!logged_in) { - qCWarning(lcCse()) << "PKCS11_is_logged_in says user is not logged in, expected to be logged in"; - _cachedPin.clear(); - failedToInitialize(account); + auto keysCount = 0u; + auto certificatesFromToken = static_cast(nullptr); + if (PKCS11_enumerate_certs(currentSlot->token, &certificatesFromToken, &keysCount)) { + qCWarning(lcCse()) << "PKCS11_enumerate_certs failed" << ERR_reason_error_string(ERR_get_error()); + + Q_EMIT failedToInitialize(account); return; } - if (pinHasToBeCached) { - cacheTokenPin(newPin); - } + for (auto certificateIndex = 0u; certificateIndex < keysCount; ++certificateIndex) { + const auto currentCertificate = &certificatesFromToken[certificateIndex]; + qCInfo(lcCse()) << "certificate metadata:" + << "label:" << currentCertificate->label; - break; - } + const auto certificateId = QByteArray{reinterpret_cast(currentCertificate->id), static_cast(currentCertificate->id_len)}; + qCInfo(lcCse()) << "new certificate ID:" << certificateId.toBase64(); - auto privateKeysCount = 0u; - auto tokenPrivateKeys = static_cast(nullptr); - if (PKCS11_enumerate_keys(slot->token, &tokenPrivateKeys, &privateKeysCount)) { - qCWarning(lcCse()) << "PKCS11_enumerate_keys failed" << ERR_reason_error_string(ERR_get_error()); + Bio out; + const auto ret = PEM_write_bio_X509(out, currentCertificate->x509); + if (ret <= 0){ + qCWarning(lcCse()) << "PEM_write_bio_X509 failed" << ERR_reason_error_string(ERR_get_error()); - failedToInitialize(account); - return; - } - if (privateKeysCount <= 0) { - qCWarning(lcCse()) << "no keys found"; - - failedToInitialize(account); - return; - } + Q_EMIT failedToInitialize(account); + return; + } - qCInfo(lcCse()) << "hardware token has" << privateKeysCount << "private keys"; + const auto result = BIO2ByteArray(out); + const auto sslCertificate = QSslCertificate{result, QSsl::Pem}; + if (sslCertificate.issuerDisplayName() != _usbTokenInformation.issuer() || + sslCertificate.serialNumber() != _usbTokenInformation.serialNumber()) { + qCInfo(lcCse()) << "skipping certificate from" << sslCertificate.issuerDisplayName() << "with serial number" << sslCertificate.serialNumber(); + continue; + } - _tokenPrivateKey = &tokenPrivateKeys[0]; - qCInfo(lcCse()) << "key metadata:" - << "type:" << (_tokenPrivateKey->isPrivate ? "is private" : "is public") - << "label:" << _tokenPrivateKey->label - << "need login:" << (_tokenPrivateKey->needLogin ? "true" : "false"); + const auto certificateKey = PKCS11_find_key(currentCertificate); + if (!certificateKey) { + qCWarning(lcCse()) << "PKCS11_find_key failed" << ERR_reason_error_string(ERR_get_error()); - auto publicKeysCount = 0u; - auto tokenPublicKeys = static_cast(nullptr); - if (PKCS11_enumerate_public_keys(slot->token, &tokenPublicKeys, &publicKeysCount)) { - qCWarning(lcCse()) << "PKCS11_enumerate_keys failed" << ERR_reason_error_string(ERR_get_error()); + Q_EMIT failedToInitialize(account); + return; + } - failedToInitialize(account); - return; - } - if (publicKeysCount <= 0) { - qCWarning(lcCse()) << "no keys found"; + _tokenPrivateKey = certificateKey; + qCInfo(lcCse()) << "key metadata:" + << "type:" << (_tokenPrivateKey->isPrivate ? "is private" : "is public") + << "label:" << _tokenPrivateKey->label + << "need login:" << (_tokenPrivateKey->needLogin ? "true" : "false"); - failedToInitialize(account); - return; - } + _tokenPublicKey = certificateKey; + qCInfo(lcCse()) << "key metadata:" + << "type:" << (_tokenPublicKey->isPrivate ? "is private" : "is public") + << "label:" << _tokenPublicKey->label + << "need login:" << (_tokenPublicKey->needLogin ? "true" : "false"); - qCInfo(lcCse()) << "hardware token has" << publicKeysCount << "public keys"; + if (!checkEncryptionIsWorking(account)) { + qCWarning(lcCse()) << "encryption is not properly setup"; - _tokenPublicKey = &tokenPublicKeys[0]; - qCInfo(lcCse()) << "key metadata:" - << "type:" << (_tokenPublicKey->isPrivate ? "is private" : "is public") - << "label:" << _tokenPublicKey->label - << "need login:" << (_tokenPublicKey->needLogin ? "true" : "false"); + failedToInitialize(account); + return; + } - if (!checkEncryptionIsWorking(account)) { - qCWarning(lcCse()) << "encryption is not properly setup"; + saveCertificateIdentification(account); - failedToInitialize(account); - return; + emit initializationFinished(); + return; + } } - saveCertificateIdentification(account); - - emit initializationFinished(); + failedToInitialize(account); } void ClientSideEncryption::fetchCertificateFromKeyChain(const AccountPtr &account) @@ -1529,20 +1549,13 @@ void ClientSideEncryption::writeCertificate(const AccountPtr &account) job->start(); } -void ClientSideEncryption::completeHardwareTokenInitialization() +void ClientSideEncryption::completeHardwareTokenInitialization(QWidget *settingsDialog, + const AccountPtr &account) { - for (const auto &oneCertificate : _usbTokenInformation.discoveredCertificates()) { - const auto certificateData = oneCertificate.toMap(); - const auto sslCertificate = certificateData[QStringLiteral("certificate")].value(); - if (sslCertificate.isNull()) { - qCDebug(lcCse()) << "null certificate"; - continue; - } - const auto sslErrors = QSslCertificate::verify({sslCertificate}); - for (const auto &oneError : sslErrors) { - qCInfo(lcCse()) << oneError; - } - qCInfo(lcCse()) << "certificate is valid" << certificateData[QStringLiteral("serialNumber")] << certificateData[QStringLiteral("issuer")]; + if (_usbTokenInformation.isSetup()) { + initializeHardwareTokenEncryption(settingsDialog, account); + } else { + emit initializationFinished(); } } diff --git a/src/libsync/clientsideencryption.h b/src/libsync/clientsideencryption.h index 0f46434e7dbd1..b89f4db28720d 100644 --- a/src/libsync/clientsideencryption.h +++ b/src/libsync/clientsideencryption.h @@ -175,6 +175,9 @@ class OWNCLOUDSYNC_EXPORT ClientSideEncryption : public QObject { void mnemonicDeleted(); void publicKeyDeleted(); + void startingDiscoveryEncryptionUsbToken(); + void finishedDiscoveryEncryptionUsbToken(); + public slots: void initialize(QWidget *settingsDialog, const OCC::AccountPtr &account); @@ -207,7 +210,8 @@ private slots: void writePrivateKey(const OCC::AccountPtr &account); void writeCertificate(const OCC::AccountPtr &account); - void completeHardwareTokenInitialization(); + void completeHardwareTokenInitialization(QWidget *settingsDialog, + const AccountPtr &account); private: void generateMnemonic(); diff --git a/src/libsync/clientsideencryptiontokenselector.cpp b/src/libsync/clientsideencryptiontokenselector.cpp index aae82e17c4c7d..d327393e42ed8 100644 --- a/src/libsync/clientsideencryptiontokenselector.cpp +++ b/src/libsync/clientsideencryptiontokenselector.cpp @@ -20,6 +20,7 @@ #include "account.h" #include +#include #include @@ -53,6 +54,34 @@ class Bio { BIO* _bio; }; +class Pkcs11Context { +public: + Pkcs11Context() + : _pkcsS11Ctx(PKCS11_CTX_new()) + { + } + + ~Pkcs11Context() + { + PKCS11_CTX_free(_pkcsS11Ctx); + } + + operator const PKCS11_CTX*() const + { + return _pkcsS11Ctx; + } + + operator PKCS11_CTX*() + { + return _pkcsS11Ctx; + } + +private: + Q_DISABLE_COPY(Pkcs11Context) + + PKCS11_CTX* _pkcsS11Ctx = nullptr; +}; + static unsigned char* unsignedData(QByteArray& array) { return (unsigned char*)array.data(); @@ -98,9 +127,36 @@ QString ClientSideEncryptionTokenSelector::issuer() const return _issuer; } -void ClientSideEncryptionTokenSelector::searchForCertificates(const AccountPtr &account) +QFuture ClientSideEncryptionTokenSelector::searchForCertificates(const AccountPtr &account) +{ + return QtConcurrent::run([this, account] () -> void { + discoverCertificates(account); + }); +} + +void ClientSideEncryptionTokenSelector::setSerialNumber(const QString &serialNumber) +{ + if (_serialNumber == serialNumber) { + return; + } + + _serialNumber = serialNumber; + Q_EMIT serialNumberChanged(); +} + +void ClientSideEncryptionTokenSelector::setIssuer(const QString &issuer) { - auto ctx = PKCS11_CTX_new(); + if (_issuer == issuer) { + return; + } + + _issuer = issuer; + Q_EMIT issuerChanged(); +} + +void ClientSideEncryptionTokenSelector::discoverCertificates(const AccountPtr &account) +{ + Pkcs11Context ctx; auto rc = PKCS11_CTX_load(ctx, account->encryptionHardwareTokenDriverPath().toLatin1().constData()); if (rc) { @@ -180,7 +236,7 @@ void ClientSideEncryptionTokenSelector::searchForCertificates(const AccountPtr & << "serial number:" << sslCertificate.serialNumber(); if (sslCertificate.isSelfSigned()) { - qCInfo(lcCseSelector()) << "newly found certificate is self signed: goint to ignore it"; + qCDebug(lcCseSelector()) << "newly found certificate is self signed: goint to ignore it"; continue; } @@ -200,26 +256,6 @@ void ClientSideEncryptionTokenSelector::searchForCertificates(const AccountPtr & processDiscoveredCertificates(); } -void ClientSideEncryptionTokenSelector::setSerialNumber(const QString &serialNumber) -{ - if (_serialNumber == serialNumber) { - return; - } - - _serialNumber = serialNumber; - Q_EMIT serialNumberChanged(); -} - -void ClientSideEncryptionTokenSelector::setIssuer(const QString &issuer) -{ - if (_issuer == issuer) { - return; - } - - _issuer = issuer; - Q_EMIT issuerChanged(); -} - void ClientSideEncryptionTokenSelector::processDiscoveredCertificates() { for (const auto &oneCertificate : discoveredCertificates()) { diff --git a/src/libsync/clientsideencryptiontokenselector.h b/src/libsync/clientsideencryptiontokenselector.h index 56fad99e35748..cc95cd94d7547 100644 --- a/src/libsync/clientsideencryptiontokenselector.h +++ b/src/libsync/clientsideencryptiontokenselector.h @@ -19,6 +19,7 @@ #include "owncloudlib.h" #include +#include namespace OCC { @@ -47,7 +48,7 @@ class OWNCLOUDSYNC_EXPORT ClientSideEncryptionTokenSelector : public QObject [[nodiscard]] QString issuer() const; public slots: - void searchForCertificates(const OCC::AccountPtr &account); + QFuture searchForCertificates(const OCC::AccountPtr &account); void setSerialNumber(const QString &serialNumber); @@ -68,6 +69,8 @@ public slots: void failedToInitialize(const OCC::AccountPtr &account); private: + void discoverCertificates(const OCC::AccountPtr &account); + void processDiscoveredCertificates(); QVariantList _discoveredCertificates;