From e56c16f27b5e867e685464a138b02557d7ce0b91 Mon Sep 17 00:00:00 2001 From: Quentin Rouland Date: Mon, 3 Feb 2025 18:45:25 +0100 Subject: [PATCH] Fix rnp passphrase provider version --- clickable.yaml | 4 +- plugins/Pass/CMakeLists.txt | 20 +- plugins/Pass/pass.cpp | 22 +- plugins/Pass/pass.h | 7 +- .../{passkeymodel.h => passkeyringmodel.h} | 6 +- plugins/Pass/passphraseprovider.h | 190 ++++++++++++++++++ plugins/Pass/passphraseprovider2.h | 132 ------------ plugins/Pass/passphraseprovider_tobedeleted.h | 139 ------------- po/utpass.qrouland.pot | 2 +- 9 files changed, 221 insertions(+), 301 deletions(-) rename plugins/Pass/{passkeymodel.h => passkeyringmodel.h} (98%) create mode 100644 plugins/Pass/passphraseprovider.h delete mode 100644 plugins/Pass/passphraseprovider2.h delete mode 100644 plugins/Pass/passphraseprovider_tobedeleted.h diff --git a/clickable.yaml b/clickable.yaml index e30f61d..af6b237 100644 --- a/clickable.yaml +++ b/clickable.yaml @@ -30,7 +30,7 @@ libraries: - libbz2-dev - zlib1g-dev - libjson-c-dev - build_args: -DBUILD_SHARED_LIBS=on -DBUILD_TESTING=off -DCRYPTO_BACKEND=botan + build_args: -DBUILD_TESTING=off -DCRYPTO_BACKEND=botan install_lib: @@ -41,6 +41,4 @@ install_lib: - "libhttp_parser.so*" - "libssh2.so*" - "libquazip5.so*" -- "librnp.so*" -- "libbotan-2.so*" diff --git a/plugins/Pass/CMakeLists.txt b/plugins/Pass/CMakeLists.txt index 511bc8f..99db636 100644 --- a/plugins/Pass/CMakeLists.txt +++ b/plugins/Pass/CMakeLists.txt @@ -5,8 +5,8 @@ set( SRC plugin.cpp pass.cpp - passkeymodel.h - passphraseprovider2.h + passkeyringmodel.h + passphraseprovider.h jobs/rmjob.cpp jobs/rnpjob.cpp jobs/getkeysjob.cpp @@ -32,22 +32,22 @@ qt5_use_modules(${PLUGIN} Qml Quick DBus) set(RNP_INSTALL_DIR "${CMAKE_SOURCE_DIR}/build/${ARCH_TRIPLET}/rnp/install") +set(BOTAN_INSTALL_DIR "${CMAKE_SOURCE_DIR}/build/${ARCH_TRIPLET}/botan/install") -find_package(OpenSSL REQUIRED) find_package(JSON-C 0.11) INCLUDE_DIRECTORIES(${RNP_INSTALL_DIR}/include) -# add_library(rnp STATIC IMPORTED) -# set_property(TARGET rnp PROPERTY IMPORTED_LOCATION "${RNP_BUILD_DIR}/lib/librnp.a") +add_library(rnp STATIC IMPORTED) +set_property(TARGET rnp PROPERTY IMPORTED_LOCATION "${RNP_INSTALL_DIR}/lib/librnp.a") -# add_library(sexpp STATIC IMPORTED) -# set_property(TARGET sexpp PROPERTY IMPORTED_LOCATION "${RNP_BUILD_DIR}/lib/libsexpp.a") +add_library(sexpp STATIC IMPORTED) +set_property(TARGET sexpp PROPERTY IMPORTED_LOCATION "${RNP_INSTALL_DIR}/lib/libsexpp.a") -add_library(rnp SHARED IMPORTED) -set_property(TARGET rnp PROPERTY IMPORTED_LOCATION "${RNP_INSTALL_DIR}/lib/librnp.so") +add_library(botan STATIC IMPORTED) +set_property(TARGET botan PROPERTY IMPORTED_LOCATION "${BOTAN_INSTALL_DIR}/lib/libbotan-2.a") -target_link_libraries(${PLUGIN} rnp OpenSSL::Crypto JSON-C::JSON-C) +target_link_libraries(${PLUGIN} rnp sexpp botan JSON-C::JSON-C) set(QT_IMPORTS_DIR "/lib/${ARCH_TRIPLET}") install(TARGETS ${PLUGIN} DESTINATION ${QT_IMPORTS_DIR}/${PLUGIN}/) diff --git a/plugins/Pass/pass.cpp b/plugins/Pass/pass.cpp index f6edadb..5bc61b3 100644 --- a/plugins/Pass/pass.cpp +++ b/plugins/Pass/pass.cpp @@ -6,8 +6,7 @@ #include "jobs/getkeysjob.h" #include "jobs/importkeyjob.h" #include "pass.h" -#include "passphraseprovider2.h" -//#include "passphraseprovider2.h" +#include "passphraseprovider.h" @@ -18,12 +17,15 @@ Pass::Pass(): QStandardPaths::AppDataLocation).append("/.rnp")), m_passphrase_provider(&UTPassphraseProvider::get_pass_provider), m_sem(std::unique_ptr(new QSemaphore(1))) -{} - -void Pass::initialize(QObject *window) { this->initGpgHome(); this->initPasswordStore(); + QObject::connect(this, &Pass::responsePassphraseDialogPropagate, + &UTPassphraseProvider::instance(), &UTPassphraseProvider::handleResponse); +} + +void Pass::initialize(QObject *window) +{ if (!window) { qWarning("[Pass] Window should be null only for testing"); } else { @@ -202,8 +204,8 @@ void Pass::slotGetAllGPGKeysSucceed(QList result) this->m_sem->release(1); } -// void Pass::responsePassphraseDialog(bool cancel, QString passphrase) -// { -// qDebug() << "Propagate responsePassphraseDialog"; -// emit responsePassphraseDialogPropagate(cancel, passphrase); -// } +void Pass::responsePassphraseDialog(bool cancel, QString passphrase) +{ + qDebug() << "Propagate responsePassphraseDialog"; + emit responsePassphraseDialogPropagate(cancel, passphrase); +} diff --git a/plugins/Pass/pass.h b/plugins/Pass/pass.h index d06bbb8..e047048 100644 --- a/plugins/Pass/pass.h +++ b/plugins/Pass/pass.h @@ -1,15 +1,17 @@ #ifndef PASS_H #define PASS_H -#include "passkeymodel.h" + #include #include #include #include #include +#include extern "C" { #include } +#include "passkeyringmodel.h" /** * @class Pass * @brief A class for managing password storage using GPG encryption. @@ -144,8 +146,7 @@ signals: private: QString m_password_store; /**< The path to the password store. */ QString m_gpg_home; /**< The path to the gpg home. */ - std::unique_ptr - m_keyring_model; /**< Meta data on the keyring uid, name, secrecy ... of the availble keys. */ + std::unique_ptr m_keyring_model; /**< Meta data on the keyring uid, name, secrecy ... of the availble keys. */ rnp_password_cb m_passphrase_provider; /**< Pointer on passphrase povider for operations using secret keys. */ std::unique_ptr m_sem; /**< Semaphore for managing concurrent operations. */ diff --git a/plugins/Pass/passkeymodel.h b/plugins/Pass/passkeyringmodel.h similarity index 98% rename from plugins/Pass/passkeymodel.h rename to plugins/Pass/passkeyringmodel.h index eb1c994..17f768b 100644 --- a/plugins/Pass/passkeymodel.h +++ b/plugins/Pass/passkeyringmodel.h @@ -1,5 +1,5 @@ -#ifndef PASSKEYMODEL_H -#define PASSKEYMODEL_H +#ifndef PASSKEYRINGMODEL_H +#define PASSKEYRINGMODEL_H #include #include @@ -126,4 +126,4 @@ public: } }; -#endif +#endif // PASSKEYRINGMODEL_H diff --git a/plugins/Pass/passphraseprovider.h b/plugins/Pass/passphraseprovider.h new file mode 100644 index 0000000..31fd3a2 --- /dev/null +++ b/plugins/Pass/passphraseprovider.h @@ -0,0 +1,190 @@ +#ifndef UTPASSPHRASEPROVIDER_H +#define UTPASSPHRASEPROVIDER_H + +#include +#include +#include +#include +#include +#include +#include +extern "C" { +#include +} + +/** + * @class UTPassphraseProvider + * @brief A passphrase provider for GPG operations that interacts with a QML dialog. + * + * This class is used to prompt the user for a passphrase through a QML-based dialog. It manages + * the passphrase entry process and signals whether the user has provided a passphrase or canceled + * the operation. + */ +class UTPassphraseProvider : public QObject +{ + Q_OBJECT + +public slots: + /** + * @brief Slot to handle the user's response from the passphrase dialog. + * + * This slot is called when the user provides a passphrase or cancels the passphrase entry. + * If the user provides a passphrase, it is stored; if the user cancels, a cancellation flag + * is set. + * + * @param canceled Indicates whether the user canceled the passphrase entry. + * @param passphrase The passphrase entered by the user (if not canceled). + */ + void handleResponse(bool canceled, QString passphrase) + { + qDebug() << "[UTPassphraseProvider] Call handleResponse"; + if (!canceled) { + this->m_canceled = false; + this->m_passphrase = passphrase; + } + unlockEventLoop(); + }; + +signals: + /** + * @brief Signal to unlock the event loop. + * + * This signal is emitted when the passphrase has been entered or the operation has been canceled, + * causing the event loop waiting for the response to exit. + */ + void unlockEventLoop(); + + +private: + /** + * @brief Private constructor for singleton pattern. + * + * Initializes the passphrase provider with a semaphore to manage access, and a flag to indicate + * whether the operation was canceled. + * + * @param parent Parent QObject (default is nullptr). + */ + explicit UTPassphraseProvider(QObject * parent = nullptr) + : m_sem(std::make_unique(1)), + m_passphrase(QString::Null()), + m_canceled(true) + {} + + QObject *m_window; /**< The window object that triggers the QML dialog. */ + std::unique_ptr m_sem; /**< Semaphore for managing access to the passphrase entry process. */ + QString m_passphrase; /**< The passphrase provided by the user. */ + bool m_canceled; /**< Flag indicating whether the passphrase operation was canceled. */ + +public: + ~UTPassphraseProvider() = default; + + /** + * @brief Gets the singleton instance of UTPassphraseProvider. + * + * This method ensures that only one instance of the passphrase provider exists throughout the application. + * + * @return The singleton instance of UTPassphraseProvider. + */ + static UTPassphraseProvider& instance() + { + static UTPassphraseProvider instance; + return instance; + } + + UTPassphraseProvider(UTPassphraseProvider const &) = delete; /**< Prevents copying of the instance. */ + void operator=(UTPassphraseProvider const &) = delete; /**< Prevents assignment of the instance. */ + + /** + * @brief Callback function to retrieve the passphrase for GPG operations. + * + * This static method is called by the GPG library when it requires a passphrase for a specific key operation. + * It triggers a QML dialog to prompt the user for the passphrase and waits for a response. + * + * @param ffi The RNP FFI instance. + * @param app_ctx provided by application + * @param key the key, if any, for which the password is being requested. + * Note: this key handle should not be held by the application, + * it is destroyed after the callback. It should only be used to + * retrieve information like the userids, grip, etc. + * @param pgp_context a descriptive string on why the password is being + * requested, may have one of the following values: + * - "add subkey": add subkey to the encrypted secret key + * - "add userid": add userid to the encrypted secret key + * - "sign": sign data + * - "decrypt": decrypt data using the encrypted secret key + * - "unlock": temporary unlock secret key (decrypting its fields), so it may be used + * later without need to decrypt + * - "protect": encrypt secret key fields + * - "unprotect": decrypt secret key fields, leaving those in a raw format + * - "decrypt (symmetric)": decrypt data, using the password + * - "encrypt (symmetric)": encrypt data, using the password + * @param buf to which the callback should write the returned password, NULL terminated. + * @param buf_len the size of buf + * + * @return true if a password was provided, false otherwise + */ + static bool + get_pass_provider( rnp_ffi_t ffi, + void * app_ctx, + rnp_key_handle_t key, + const char * pgp_context, + char buf[], + size_t buf_len) + { + qDebug() << "[UTPassphraseProvider] Call the getPassphrase"; + + if (!UTPassphraseProvider::instance().m_window) { + qWarning() << "[UTPassphraseProvider] Aborting : window is not set"; + return false; + } + + if (!UTPassphraseProvider::instance().m_sem->tryAcquire(1, 500)) + { + qWarning() << "[UTPassphraseProvider] Aborting : Cannot acquire UTPassphraseProvider semaphore"; + return false; + } + + UTPassphraseProvider::instance().m_passphrase = QString::Null(); + UTPassphraseProvider::instance().m_canceled = true; + + qDebug() << "[UTPassphraseProvider] Call the QML Dialog Passphrase Provider"; + QMetaObject::invokeMethod( + UTPassphraseProvider::instance().m_window, "callPassphraseDialog", + Q_ARG(QVariant, "useridHint"), // TODO + Q_ARG(QVariant, "description"), // TODO + Q_ARG(QVariant, "previousWasBad") // TODO + ); + + qDebug() << "[UTPassphraseProvider] Waiting for response"; + + QEventLoop loop; + QObject::connect(&UTPassphraseProvider::instance(), &UTPassphraseProvider::unlockEventLoop, &loop, &QEventLoop::quit); + loop.exec(); + + qDebug() << "[UTPassphraseProvider] Prepare Returns"; + auto ret = false; + if(!UTPassphraseProvider::instance().m_canceled) { + strncpy(buf, UTPassphraseProvider::instance().m_passphrase.toLocal8Bit().data(), buf_len); + ret = true; + }; + + qDebug() << "[UTPassphraseProvider] Clean Up"; + UTPassphraseProvider::instance().m_passphrase = QString::Null(); + UTPassphraseProvider::instance().m_canceled = true; + UTPassphraseProvider::instance().m_sem->release(1); + return ret; + } + + /** + * @brief Sets the window object that triggers the passphrase dialog. + * + * This method allows the passphrase provider to know which window should invoke the QML dialog. + * + * @param window The window object to set. + */ + void setWindow(QObject* window){ + this->m_window = window; + } +}; + +#endif // UTPASSPHRASEPROVIDER_H diff --git a/plugins/Pass/passphraseprovider2.h b/plugins/Pass/passphraseprovider2.h deleted file mode 100644 index b648013..0000000 --- a/plugins/Pass/passphraseprovider2.h +++ /dev/null @@ -1,132 +0,0 @@ -#ifndef UTPASSPHRASEPROVIDER2_H -#define UTPASSPHRASEPROVIDER2_H - -#include -#include -#include -#include -#include -#include -#include -extern "C" { -#include -} - -/** - * @class UTPassphraseProvider - * @brief A passphrase provider for GPG operations that interacts with a QML dialog. - */ - -class UTPassphraseProvider : public QObject -{ - Q_OBJECT - -public slots: - /** - * @brief Slot to handle the user's response from the passphrase dialog. - * - * This method processes the response from the passphrase dialog. If the user provides a passphrase, - * it is stored; if the operation is canceled, a flag is set. - * - * @param canceled Whether the user canceled the passphrase entry. - * @param passphrase The passphrase entered by the user. - */ - void handleResponse(bool canceled, QString passphrase) - { - qDebug() << "call handleResponse"; - if (!canceled) - this->m_passphrase = passphrase; - else - m_canceled = true; - emit unlockEventLoop(); - }; - -signals: - /** - * @brief Signal to unlock the event loop. - * - * This signal is emitted when the passphrase has been entered or the operation has been canceled, - * unlocking the event loop waiting for the response. - */ - void unlockEventLoop(); - - -private: - explicit UTPassphraseProvider(QObject * parent = nullptr) - : m_sem(std::make_unique(1)), - m_passphrase(QString::Null()), - m_canceled(false) - {} - QObject *m_window; /**< The window object that triggers the QML dialog. */ - std::unique_ptr m_sem; /**< Semaphore for managing access. */ - QString m_passphrase; /**< The passphrase provided by the user. */ - bool m_canceled; /**< Flag indicating whether the passphrase operation was canceled. */ - -public: - ~UTPassphraseProvider() = default; - - static UTPassphraseProvider& instance() - { - static UTPassphraseProvider instance; - return instance; - } - UTPassphraseProvider(UTPassphraseProvider const &) = delete; - void operator=(UTPassphraseProvider const &) = delete; - - static bool - get_pass_provider(rnp_ffi_t ffi, - void * app_ctx, - rnp_key_handle_t key, - const char * pgp_context, - char buf[], - size_t buf_len) - { - qDebug() << "Call the getPassphrase"; - - if (!UTPassphraseProvider::instance().m_sem->tryAcquire(1, 500)) - { - qWarning() << "Cannot acquire UTPassphraseProvider semaphore."; - UTPassphraseProvider::instance().m_canceled = true; - return false; - } - - UTPassphraseProvider::instance().m_passphrase = nullptr; - UTPassphraseProvider::instance().m_canceled = false; - - qDebug() << "Call the QML Dialog Passphrase Provider"; - QMetaObject::invokeMethod( - UTPassphraseProvider::instance().m_window, "callPassphraseDialog", - Q_ARG(QVariant, "useridHint"), // TODO - Q_ARG(QVariant, "description"), // TODO - Q_ARG(QVariant, "previousWasBad") // TODO - ); - - qDebug() << "Waiting for response"; - - QEventLoop loop; - QObject::connect(&UTPassphraseProvider::instance(), &UTPassphraseProvider::unlockEventLoop, &loop, &QEventLoop::quit); - loop.exec(); - - qDebug() << "Prepare Returns"; - auto ret = false; - if(!UTPassphraseProvider::instance().m_canceled) { - strncpy(buf, UTPassphraseProvider::instance().m_passphrase.toLocal8Bit().data(), buf_len); - ret = true; - }; - - qDebug() << "Clean"; - if (UTPassphraseProvider::instance().m_passphrase.isNull()) - { - UTPassphraseProvider::instance().m_passphrase = QString::Null(); - } - UTPassphraseProvider::instance().m_canceled = false; - UTPassphraseProvider::instance().m_sem->release(1); - return ret; - } - - void setWindow(QObject* window){ - this->m_window = window; - } -}; - -#endif diff --git a/plugins/Pass/passphraseprovider_tobedeleted.h b/plugins/Pass/passphraseprovider_tobedeleted.h deleted file mode 100644 index c3e6545..0000000 --- a/plugins/Pass/passphraseprovider_tobedeleted.h +++ /dev/null @@ -1,139 +0,0 @@ -#ifndef UTPASSPHRASEPROVIDER_H -#define UTPASSPHRASEPROVIDER_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace GpgME; - -/** - * @class UTPassphraseProvider - * @brief A passphrase provider for GPG operations that interacts with a QML dialog. - * - * This class implements the `PassphraseProvider` interface from GPGME and is responsible for - * obtaining passphrases for GPG operations. - */ -class UTPassphraseProvider : public QObject, public GpgME::PassphraseProvider -{ - Q_OBJECT - -public slots: - /** - * @brief Slot to handle the user's response from the passphrase dialog. - * - * This method processes the response from the passphrase dialog. If the user provides a passphrase, - * it is stored; if the operation is canceled, a flag is set. - * - * @param canceled Whether the user canceled the passphrase entry. - * @param passphrase The passphrase entered by the user. - */ - void handleResponse(bool canceled, QString passphrase) - { - qDebug() << "call handleResponse"; - if (!canceled) - gpgrt_asprintf(&m_passphrase, "%s", passphrase.toUtf8().constData()); - else - m_canceled = true; - emit unlockEventLoop(); - }; - -signals: - /** - * @brief Signal to unlock the event loop. - * - * This signal is emitted when the passphrase has been entered or the operation has been canceled, - * unlocking the event loop waiting for the response. - */ - void unlockEventLoop(); - -private: - std::unique_ptr m_sem; /**< Semaphore for managing access. */ - char *m_passphrase; /**< The passphrase provided by the user. */ - bool m_canceled; /**< Flag indicating whether the passphrase operation was canceled. */ - QObject *m_window; /**< The window object that triggers the QML dialog. */ - -public: - /** - * @brief Constructs a UTPassphraseProvider. - * - * Initializes the semaphore, passphrase, and canceled flag. Sets the window object that will - * trigger the passphrase dialog. - * - * @param window The QObject representing the window that interacts with QML. - */ - UTPassphraseProvider(QObject* window) - : m_sem(std::make_unique(1)), - m_passphrase(nullptr), - m_canceled(false), - m_window(window) - { - qDebug() << "Initialize UTPassphraseProvider"; - } - - /** - * @brief Implements the PassphraseProvider's `getPassphrase` method. - * - * This method is called by GPGME to retrieve the passphrase needed for GPG operations. It triggers - * a QML dialog for the user to input their passphrase. The method waits for the response and returns - * the passphrase if successful, or null if canceled. - * - * @param useridHint A hint for the user ID to which the passphrase corresponds. - * @param description A description of the passphrase request. - * @param previousWasBad Flag indicating whether the previous passphrase attempt was incorrect. - * @param canceled Reference to a boolean flag that will be set if the operation is canceled. - * - * @return The passphrase as a `char *` or `nullptr` if canceled. - */ - char *getPassphrase(const char *useridHint, - const char *description, - bool previousWasBad, - bool &canceled) Q_DECL_OVERRIDE { - qDebug() << "Call the getPassphrase"; - if (!this->m_sem->tryAcquire(1, 500)) - { - qWarning() << "Cannot acquire UTPassphraseProvider semaphore."; - canceled = true; - return nullptr; - } - - this->m_passphrase = nullptr; - this->m_canceled = false; - - qDebug() << "Call the QML Dialog Passphrase Provider"; - QMetaObject::invokeMethod( - this->m_window, "callPassphraseDialog", - Q_ARG(QVariant, useridHint), - Q_ARG(QVariant, description), - Q_ARG(QVariant, previousWasBad) - ); - - qDebug() << "Waiting for response"; - - QEventLoop loop; - QObject::connect(this, &UTPassphraseProvider::unlockEventLoop, &loop, &QEventLoop::quit); - loop.exec(); - - qDebug() << "Prepare Returns"; - char *ret; - gpgrt_asprintf(&ret, "%s", m_passphrase); - canceled = this->m_canceled; - - qDebug() << "Clean"; - if (this->m_passphrase) - { - free(m_passphrase); - } - this->m_canceled = false; - this->m_sem->release(1); - return ret; - }; -}; - -#endif diff --git a/po/utpass.qrouland.pot b/po/utpass.qrouland.pot index 7fdaf64..9f5f147 100644 --- a/po/utpass.qrouland.pot +++ b/po/utpass.qrouland.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: utpass.qrouland\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2025-02-03 16:44+0000\n" +"POT-Creation-Date: 2025-02-03 19:54+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n"