diff --git a/CMakeLists.txt b/CMakeLists.txt index 6ebb068..dbf2338 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,9 +39,13 @@ if(NOT TESTS_PATH) set(TESTS_PATH "./tests") endif() -configure_file(main.in.cpp main.cpp) +if(TESTS_RUNNER) + configure_file(tests.in.cpp tests.cpp) + add_executable(${PROJECT_NAME} tests.cpp) +else() + add_executable(${PROJECT_NAME} main.cpp) +endif() -add_executable(${PROJECT_NAME} main.cpp) qt5_use_modules(${PROJECT_NAME} Gui Qml Quick QuickTest) if(TESTS_RUNNER) diff --git a/main.in.cpp b/main.cpp similarity index 80% rename from main.in.cpp rename to main.cpp index baac230..3711bf5 100644 --- a/main.in.cpp +++ b/main.cpp @@ -6,10 +6,6 @@ #include -#ifdef TEST_RUNNER -#include -#endif - int main(int argc, char *argv[]) { qDebug() << "Starting app from main.cpp"; @@ -17,7 +13,6 @@ int main(int argc, char *argv[]) QGuiApplication::setApplicationName("utpass.qrouland"); -#ifndef TEST_RUNNER auto *view = new QQuickView(); view->setSource(QUrl(QStringLiteral("qml/Main.qml"))); view->setResizeMode(QQuickView::SizeRootObjectToView); @@ -28,7 +23,4 @@ int main(int argc, char *argv[]) Q_ARG(QVariant, QVariant::fromValue(mainView)) ); return QGuiApplication::exec(); -#else - return quick_test_main(argc, argv, "@TESTS_PATH@", "@TESTS_PATH@"); -#endif } diff --git a/plugins/Git/jobs/gitjob.h b/plugins/Git/jobs/gitjob.h index 46eb2a1..8f0fe10 100644 --- a/plugins/Git/jobs/gitjob.h +++ b/plugins/Git/jobs/gitjob.h @@ -1,7 +1,7 @@ #ifndef GITJOB_H #define GITJOB_H -#include "qthread.h" +#include extern "C" { #include } diff --git a/plugins/Pass/CMakeLists.txt b/plugins/Pass/CMakeLists.txt index 26554b6..cca72cc 100644 --- a/plugins/Pass/CMakeLists.txt +++ b/plugins/Pass/CMakeLists.txt @@ -5,10 +5,10 @@ set( SRC plugin.cpp pass.cpp - gpg.cpp passkeymodel.h - passphraseprovider.h jobs/rmjob.cpp + jobs/rnpjob.cpp + jobs/importkeyjob.cpp ) set(CMAKE_AUTOMOC ON) @@ -31,11 +31,16 @@ qt5_use_modules(${PLUGIN} Qml Quick DBus) set(RNP_BUILD_DIR "${CMAKE_SOURCE_DIR}/build/${ARCH_TRIPLET}/rnp/install") +find_package(OpenSSL REQUIRED) + INCLUDE_DIRECTORIES(${RNP_BUILD_DIR}/include) add_library(rnp STATIC IMPORTED) set_property(TARGET rnp PROPERTY IMPORTED_LOCATION "${RNP_BUILD_DIR}/lib/librnp.a") +add_library(sexpp STATIC IMPORTED) +set_property(TARGET sexpp PROPERTY IMPORTED_LOCATION "${RNP_BUILD_DIR}/lib/libsexpp.a") + add_library(gpgerror SHARED IMPORTED) set_property(TARGET gpgerror PROPERTY IMPORTED_LOCATION "/usr/lib/${ARCH_TRIPLET}/libgpg-error.so.0.28.0") @@ -52,8 +57,7 @@ add_library(libqgpgme SHARED IMPORTED) set_property(TARGET libqgpgme PROPERTY IMPORTED_LOCATION "/usr/lib/${ARCH_TRIPLET}/libqgpgme.so") -target_link_libraries(${PLUGIN} rnp gpgerror libassuan libgpgme libgpgmepp libqgpgme) - +target_link_libraries(${PLUGIN} rnp sexpp gpgerror libassuan libgpgme libgpgmepp libqgpgme OpenSSL::Crypto) set(QT_IMPORTS_DIR "/lib/${ARCH_TRIPLET}") install(TARGETS ${PLUGIN} DESTINATION ${QT_IMPORTS_DIR}/${PLUGIN}/) diff --git a/plugins/Pass/gpg.cpp b/plugins/Pass/gpg.cpp deleted file mode 100644 index 8f6c1fb..0000000 --- a/plugins/Pass/gpg.cpp +++ /dev/null @@ -1,301 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - - -#include "gpg.h" -#include "passphraseprovider.h" - - - - - -using namespace GpgME; -using namespace QGpgME; - -Gpg::Gpg(QObject* windows) -{ - this->m_passphrase_provider = new UTPassphraseProvider(windows); - - Gpg::initGpgConfig(); - - auto error = checkEngine(OpenPGP); - if (error) { - qDebug() << "Code Error : " << error.code(); - qDebug() << "Error str : " << error.asString(); - qFatal("GNUPG Engine check Fail"); - } - - qDebug() << "GNUPG Engine Version is :" << engineInfo(OpenPGP).version(); - qDebug() << "GNUPG Executable is :" << engineInfo(OpenPGP).fileName(); - qDebug() << "GNUPG Home is :" << engineInfo(OpenPGP).homeDirectory(); -} - -Gpg::~Gpg() -{ - delete this->m_passphrase_provider; -} - - -QString Gpg::initGpgHome() -{ - QString path = QStandardPaths::writableLocation( - QStandardPaths::AppDataLocation).append("/.gpghome"); - QDir dir(path); - if (!dir.exists()) { - dir.mkpath("."); - } - return path; -} - - -QString Gpg::findCommandPath(const QString &command) -{ - // Retrieve the PATH environment variable - QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); - QString pathEnv = env.value("PATH"); - - // Split the PATH by colon - QStringList pathDirs = pathEnv.split(":", QString::SkipEmptyParts); - - // Check each directory in the PATH - foreach (const QString &dir, pathDirs) { - QFileInfo fileInfo(QDir(dir).filePath(command)); - - // If the file exists and is executable, return the path - if (fileInfo.exists() && fileInfo.isExecutable()) { - return fileInfo.absoluteFilePath(); - } - } - - return QString::null; -} - -QString Gpg::initGpgExec() -{ - QString path = findCommandPath("gpg"); - if (path.isNull()) { - qFatal("No valid gpg exec found !"); - } - return path; -} - - -void Gpg::initGpgConfig() -{ - initializeLibrary(); - gpgme_set_global_flag("disable-gpgconf", "1"); - - QString home = initGpgHome(); - qDebug() << "Gpg home is " << home; - QString exec = initGpgExec(); - qDebug() << "Gpg exec is " << exec; - - QFile agentConf(home + QStringLiteral("/gpg-agent.conf")); - agentConf.remove(); - agentConf.open(QIODevice::WriteOnly); - agentConf.write("allow-loopback-pinentry\n"); - agentConf.close(); - - auto err = gpgme_set_engine_info ( - GPGME_PROTOCOL_OpenPGP, - exec.toLocal8Bit().data(), - home.toLocal8Bit().data() - ); - if (err != GPG_ERR_NO_ERROR) { - qDebug() << "Error code : " << err; - qDebug() << "Error str : " << gpg_strerror(err); - qFatal("GPGME set engine info failed !"); - } -} - - -Error Gpg::decrypt(QByteArray cipher_text) -{ - auto job = openpgp()->decryptJob(); - - auto ctx = DecryptJob::context(job); - - ctx->setPassphraseProvider(this->m_passphrase_provider); - ctx->setPinentryMode(Context::PinentryLoopback); - - QObject::connect(job, &DecryptJob::result, - this, &Gpg::decryptResultSlot); - - return job->start(cipher_text); -} - -Error Gpg::decryptFromFile(QString path) -{ - qDebug() << "Decrypt from " << path; - QFile file(path); - if (!file.open(QIODevice::ReadOnly)) { - qWarning() << "Can't open the File"; - return Error(); - } - QByteArray cipherText = file.readAll(); - file.close(); - return decrypt(cipherText); -} - - - -void Gpg::decryptResultSlot(const GpgME::DecryptionResult &result, const QByteArray &plainText, - const QString &auditLogAsHtml, const GpgME::Error &auditLogError) -{ - if (result.error()) { - qWarning() << "Something gone wrong on decrypt"; - qDebug() << "Code Error : " << result.error().code(); - qDebug() << "Error str : " << result.error().asString(); - } - qDebug() << "Cancelled : " << result.error().isCanceled(); - emit decryptResult(result.error(), QString::fromUtf8(plainText)); -} - - -// QPair Gpg::encrypt(QString str, QString uid, bool ascii_armor, bool text_mode) -// { - -// qDebug() << "Encrypt to QByteArray"; -// auto keys = getKeys(uid); -// if (keys.first) { -// return QPair(keys.first, QByteArray()); -// } - -// auto job = std::unique_ptr(openpgp()->encryptJob(ascii_armor, text_mode)); - -// QByteArray cipherText; -// auto result = job->exec(keys.second, str.toUtf8(), Context::AlwaysTrust, cipherText); - -// qDebug() << "Encrypted to QByteArray"; -// return QPair(result.error(), cipherText); -// } - - -// Error Gpg::encryptToFile(QString str, QString path, QString uid, bool ascii_armor, -// bool text_mode) -// { -// qDebug() << "Encrypting to file " << path; -// QFile file(path); -// if (!file.open(QIODevice::WriteOnly)) { -// qWarning() << "Can't open the file to write it" ; -// return Error(); -// } -// auto encrypt_ret = encrypt(str, uid, ascii_armor, text_mode); -// if (encrypt_ret.first) { -// file.write(encrypt_ret.second); -// } -// qDebug() << "Encrypting to file " << path; -// return encrypt_ret.first; -// } - - -Error Gpg::getAllKeys ( bool remote, const bool include_sigs, - bool validate ) -{ - return getKeys(QString(""), remote, include_sigs, validate); -} - -Error Gpg::getKeys(QString pattern_uid, bool remote, bool include_sigs, - bool validate) -{ - qDebug() << "Getting the keys " << pattern_uid; - auto job = openpgp()->keyListJob(remote, include_sigs, validate); - - QObject::connect(job, &KeyListJob::result, - this, &Gpg::getKeysJobResultSlot); - - return job->start(QStringList() << pattern_uid, false); -} - -void Gpg::getKeysJobResultSlot(const GpgME::KeyListResult &result, const std::vector &keys, - const QString &auditLogAsHtml, const GpgME::Error &auditLogError) -{ - if (result.error()) { - qWarning() << "Something gone wrong on getKeys"; - qDebug() << "Code Error : " << result.error().code(); - qDebug() << "Error str : " << result.error().asString(); - } - emit getKeysResult(result.error(), keys); -} - -Error Gpg::importKeysFromFile(QString path) -{ - qDebug() << "Importing the key file" << path; - qDebug() << "Decrypt from " << path; - QFile file(path); - if (!file.open(QIODevice::ReadOnly)) { - qWarning() << "Can't open the File"; - return Error(); - } - auto data = file.readAll(); - file.close(); - - auto job = openpgp()->importJob(); - - QObject::connect(job, &ImportJob::result, - this, &Gpg::importKeysFromFileSlot); - - - return job->start(data); -} - -void Gpg::importKeysFromFileSlot(const GpgME::ImportResult &result, const QString &auditLogAsHtml, - const GpgME::Error &auditLogError) -{ - qDebug() << "numImported" << result.numImported(); - qDebug() << "numSecretKeysImported" << result.numSecretKeysImported(); - qDebug() << "numSecretKeysConsidered" << result.numSecretKeysConsidered(); - qDebug() << "numSecretKeysUnchanged" << result.numSecretKeysUnchanged(); - qDebug() << "numUnchanged" << result.numUnchanged(); - - - if (result.error()) { - qWarning() << "Something gone wrong on decrypt"; - qDebug() << "Code Error : " << result.error().code(); - qDebug() << "Error str : " << result.error().asString(); - } - emit importKeysFromFileResult(result.error()); -} - -Error Gpg::deleteKey(const Key key) -{ - auto job = openpgp()->deleteJob(); - - QObject::connect(job, &DeleteJob::result, - this, &Gpg::deleteKeySlot); - - return job->start(key, true); -} - -void Gpg::deleteKeySlot(const GpgME::Error &error, const QString &auditLogAsHtml, const GpgME::Error &auditLogError) -{ - if (error) { - qWarning() << "Something gone wrong on deleteKey"; - qDebug() << "Code Error : " << error.code(); - qDebug() << "Error str : " << error.asString(); - } - emit deleteKeyResult(error); -} - diff --git a/plugins/Pass/gpg.h b/plugins/Pass/gpg.h deleted file mode 100644 index 83b9f73..0000000 --- a/plugins/Pass/gpg.h +++ /dev/null @@ -1,227 +0,0 @@ -#ifndef GPG_H -#define GPG_H - -#include "passkeymodel.h" -#include "passphraseprovider.h" -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - - -using namespace GpgME; -using namespace QGpgME; - -/** - * @class Gpg - * @brief A class for managing GPG key operations such as key import, decryption, and deletion. - * - * This class integrates with the GPGME (GnuPG Made Easy) library to provide functionalities - * for interacting with GPG keys, including decrypting messages, importing keys from files, - * listing keys, and deleting keys. - */ -class Gpg: public QObject -{ - Q_OBJECT - Q_PROPERTY(UTPassphraseProvider* passphrase_provider READ passphrase_provider MEMBER m_passphrase_provider ) - -private slots: - /** - * @brief Slot to handle the result of a decryption operation. - * @param result The result of the decryption operation. - * @param plain_text The decrypted text. - * @param auditLogAsHtml The HTML formatted audit log for the operation. - * @param auditLogError The error associated with the audit log, if any. - */ - void decryptResultSlot( - const DecryptionResult &result, - const QByteArray &plain_text, - const QString &auditLogAsHtml, - const Error &auditLogError - ); - - /** - * @brief Slot to handle the result of a key retrieval operation. - * @param result The result of the key retrieval operation. - * @param keys A vector of keys retrieved. - * @param auditLogAsHtml The HTML formatted audit log for the operation, if any. - * @param auditLogError The error associated with the audit log, if any. - */ - void getKeysJobResultSlot( - const GpgME::KeyListResult &result, - const std::vector &keys, - const QString &auditLogAsHtml, - const GpgME::Error &auditLogError - ); - - /** - * @brief Slot to handle the result of a key import operation. - * @param result The result of the import operation. - * @param auditLogAsHtml The HTML formatted audit log for the operation, if any. - * @param auditLogError The error associated with the audit log, if any. - */ - void importKeysFromFileSlot( - const GpgME::ImportResult &result, - const QString &auditLogAsHtml, - const GpgME::Error &auditLogError - ); - - /** - * @brief Slot to handle the result of a key deletion operation. - * @param result The error result of the deletion operation. - * @param auditLogAsHtml The HTML formatted audit log for the operation, if any. - * @param auditLogError The error associated with the audit log, if any. - */ - void deleteKeySlot( - const GpgME::Error &result, - const QString &auditLogAsHtml, - const GpgME::Error &auditLogError - ); - -signals: - /** - * @brief Signal emitted when keys are imported from a file. - * @param err The error that occurred during the import operation, if any. - */ - void importKeysFromFileResult(Error err); - - /** - * @brief Signal emitted when keys are retrieved. - * @param err The error that occurred during the retrieval operation, if any. - * @param keys A vector of keys retrieved. - */ - void getKeysResult(Error err, std::vector keys); - - /** - * @brief Signal emitted when a key is deleted. - * @param err The error that occurred during the deletion operation, if any. - */ - void deleteKeyResult(Error err); - - /** - * @brief Signal emitted when a decryption operation completes. - * @param err The error that occurred during decryption, if any. - * @param plain_text The decrypted message. - */ - void decryptResult(Error err, QString plain_text); - -private: - UTPassphraseProvider *m_passphrase_provider; /**< The passphrase provider used for authentication. */ - - /** - * @brief Finds the path of a command in the system's environment. - * @param command The name of the command to find. - * @return The full path to the command. - */ - QString findCommandPath(const QString &command); - - /** - * @brief Initializes the GPG home directory. - * @return The path to the GPG home directory. - */ - QString initGpgHome(); - - /** - * @brief Initializes the GPG executable path. - * @return The path to the GPG executable. - */ - QString initGpgExec(); - - /** - * @brief Initializes the GPG configuration. - */ - void initGpgConfig(); - - /** - * @brief Retrieves a GPG key by UID. - * @param uid The UID of the key to retrieve. - * @param remote Whether to fetch the key from a remote keyserver (default: false). - * @param include_sigs Whether to include signatures (default: false). - * @param validate Whether to validate the key (default: false). - * @return The error result of the operation. - */ - Error getKey(QString uid, bool remote = false, bool include_sigs = false, bool validate = false); - -public: - /** - * @brief Constructs a Gpg object and initializes necessary resources. - * @param window The window object for interacting with the user interface. - */ - Gpg(QObject* window); - - /** - * @brief Destroys the Gpg object and cleans up resources. - */ - ~Gpg(); - - /** - * @brief Gets the passphrase provider used for GPG authentication. - * @return The passphrase provider. - */ - UTPassphraseProvider *passphrase_provider() const - { - return m_passphrase_provider; - } - - - /** - * @brief Imports GPG keys from a file. - * @param path The path to the file containing the keys. - * @return The error result of the import operation. - */ - Error importKeysFromFile(const QString path); - - /** - * @brief Retrieves keys matching the provided UID pattern. - * @param pattern_uid The UID pattern to search for. - * @param remote Whether to fetch the key from a remote keyserver (default: false). - * @param include_sigs Whether to include signatures (default: false). - * @param validate Whether to validate the key (default: false). - * @return The error result of the operation. - */ - Error getKeys(const QString pattern_uid, bool remote = false, bool include_sigs = false, bool validate = false); - - /** - * @brief Retrieves all keys from the GPG keyring. - * @param remote Whether to fetch the keys from a remote keyserver (default: false). - * @param include_sigs Whether to include signatures (default: false). - * @param validate Whether to validate the keys (default: false). - * @return The error result of the operation. - */ - Error getAllKeys(bool remote = false, bool include_sigs = false, bool validate = false); - - /** - * @brief Deletes a specified GPG key. - * @param key The key to delete. - * @return The error result of the deletion operation. - */ - Error deleteKey(const Key key); - - /** - * @brief Decrypts a given ciphertext. - * @param cipher_text The ciphertext to decrypt. - * @return The error result of the decryption operation. - */ - Error decrypt(const QByteArray cipher_text); - - /** - * @brief Decrypts the contents of a file. - * @param path The path to the file to decrypt. - * @return The error result of the decryption operation. - */ - Error decryptFromFile(const QString path); - - // Error encrypt (QString str, QString uid, bool ascii_armor = true, bool text_mode = true); -}; - -#endif diff --git a/plugins/Pass/jobs/decryptjob.cpp b/plugins/Pass/jobs/decryptjob.cpp new file mode 100644 index 0000000..b135147 --- /dev/null +++ b/plugins/Pass/jobs/decryptjob.cpp @@ -0,0 +1,14 @@ +#include "decryptjob.h" + +DecryptJob::DecryptJob(QString path, QString keyfile): + m_path(path) +{ + this->setObjectName("DecryptJob"); +} + + +void DecryptJob::run() +{ + rnp_input_from_path(&keyfile, "secring.pgp")); + qFatal("To be implemented !") +} diff --git a/plugins/Pass/jobs/decryptjob.h b/plugins/Pass/jobs/decryptjob.h new file mode 100644 index 0000000..2094fd0 --- /dev/null +++ b/plugins/Pass/jobs/decryptjob.h @@ -0,0 +1,47 @@ +#ifndef DECRYPTJOB_H +#define DECRYPTJOB_H + +#include +#include + +/** + * @class DecryptJob + * @brief A class to handle decrypt a file in a separate thread. + * + */ +class DecryptJob : public QThread +{ + Q_OBJECT + + /** + * @brief The main function that performs the decrypt operation. + * + * Handles the process of removing recursively a target path. + */ + void run() override; + +signals: + /** + * @brief Signal emitted when the decrypt operation is complete. + * + * @param err A boolean indicating whether an error occurred during removing. + * `true` if an error occurred, `false` if the clone was successful. + */ + void resultReady(const bool err); + +private: + QString m_encryped_file_path; ///< The path of the encrypted file. + QString m_keyfile_path; ///< The path of the key file. + +public: + /** + * @brief Constructor for the RmJob class. + * + * Initializes the DecryptJob with the specified file to decrypt. + * + * @param path Path of the file to decrypt. + */ + DecryptJob(QString path); +}; + +#endif // DECRYPTJO_H diff --git a/plugins/Pass/jobs/importkeyjob.cpp b/plugins/Pass/jobs/importkeyjob.cpp new file mode 100644 index 0000000..7d4bf24 --- /dev/null +++ b/plugins/Pass/jobs/importkeyjob.cpp @@ -0,0 +1,46 @@ +#include +#include "importkeyjob.h" +extern "C" { +#include +#include +} + +ImportKeyJob::ImportKeyJob(QDir rnp_homedir, QString key_file_path): + RnpJob(rnp_homedir), + m_key_file_path(key_file_path) +{ + this->setObjectName("DecryptJob"); +} + + +void ImportKeyJob::run() +{ + qDebug() << "ImportKeyJob Starting "; + rnp_input_t input = NULL; + auto ret = rnp_input_from_path(&input, this->m_key_file_path.toLocal8Bit().constData()); + if(ret == RNP_SUCCESS) { + ret = rnp_load_keys(this->m_ffi, + "GPG", + input, + RNP_LOAD_SAVE_PUBLIC_KEYS | RNP_LOAD_SAVE_SECRET_KEYS); + } + rnp_input_destroy(input); + terminateWithError(ret); + + rnp_output_t output = NULL; + ret = rnp_output_to_file(&output, this->pubringPath().toLocal8Bit().constData(), RNP_OUTPUT_FILE_RANDOM); + if(ret == RNP_SUCCESS) { + ret = rnp_save_keys(this->m_ffi, RNP_KEYSTORE_GPG, output, RNP_LOAD_SAVE_SECRET_KEYS); + } + rnp_output_destroy(output); + terminateWithError(ret); + + ret = rnp_output_to_file(&output, this->secringPath().toLocal8Bit().constData(), RNP_OUTPUT_FILE_OVERWRITE); + if(ret == RNP_SUCCESS) { + ret = rnp_save_keys(this->m_ffi, RNP_KEYSTORE_GPG, output, RNP_LOAD_SAVE_SECRET_KEYS); + } + rnp_output_destroy(output); + terminateWithError(ret); + emit resultSuccess(); + qDebug() << "ImportKeyJob Finished Successfully "; +} diff --git a/plugins/Pass/jobs/importkeyjob.h b/plugins/Pass/jobs/importkeyjob.h new file mode 100644 index 0000000..2fe8531 --- /dev/null +++ b/plugins/Pass/jobs/importkeyjob.h @@ -0,0 +1,38 @@ +#ifndef IMPORTKEYJOB_H +#define IMPORTKEYJOB_H + + + +#include "rnpjob.h" +/** + * @class ImportKeyJob + * @brief A class to handle import a key file in a separate thread. + * + */ +class ImportKeyJob : public RnpJob +{ + Q_OBJECT + + /** + * @brief The main function that performs the import operation. + * + * Handles the process of removing recursively a target path. + */ + void run() override; + + +private: + QString m_key_file_path; ///< The path of the key file to import. + +public: + /** + * @brief Constructor for the RmJob class. + * + * Initializes the ImportKeyJob with the file to import. + * + * @param path Path of the key file to import. + */ + ImportKeyJob(QDir rnp_homedir, QString key_file_path); +}; + +#endif // IMPORTKEYJOB_H diff --git a/plugins/Pass/jobs/rnpjob.cpp b/plugins/Pass/jobs/rnpjob.cpp new file mode 100644 index 0000000..478f617 --- /dev/null +++ b/plugins/Pass/jobs/rnpjob.cpp @@ -0,0 +1,42 @@ +#include + +#include "rnpjob.h" +extern "C" { +#include +#include +} + +RnpJob::RnpJob(QDir rnp_homedir): + m_rnp_homedir(rnp_homedir) +{ + auto ret = rnp_ffi_create(&this->m_ffi, + RNP_KEYSTORE_GPG, + RNP_KEYSTORE_GPG); + if(ret != RNP_SUCCESS) { + qDebug() << "Err : " << ret; + qFatal("Error on rnp ffi init!"); + } +} + +RnpJob::~RnpJob(){ + auto ret = rnp_ffi_destroy(this->m_ffi); + if(ret != RNP_SUCCESS) { + qDebug() << "Err : " << ret; + qFatal("Something go wrong on rnp ffi detroy"); + } +} + +bool RnpJob::passProvider(rnp_ffi_t ffi, + void * app_ctx, + rnp_key_handle_t key, + const char * pgp_context, + char buf[], + size_t buf_len) +{ + if (strcmp(pgp_context, "protect")) { + return false; + } + + strncpy(buf, "password", buf_len); + return true; +} diff --git a/plugins/Pass/jobs/rnpjob.h b/plugins/Pass/jobs/rnpjob.h new file mode 100644 index 0000000..c6058eb --- /dev/null +++ b/plugins/Pass/jobs/rnpjob.h @@ -0,0 +1,82 @@ +#ifndef RNPJOB_H +#define RNPJOB_H + +#include +#include +extern "C" { +#include +} +#include + + +#define terminateWithError(ret) \ +if(ret != RNP_SUCCESS) { \ + qDebug() << "Err : " << ret; \ + qDebug() << "Err Msg : " << rnp_result_to_string(ret); \ + emit resultError(ret); \ + return; \ +} \ + +/** + * @class RmpJob + * @brief A class that manages Git-related tasks using libgit2. + * + * The GitJob class is used abstraction class to perform rnp (opengpg) operations, + * such as decrypt, encrypt, key managments operations + */ +class RnpJob : public QThread +{ + Q_OBJECT + +signals: + void resultError(const rnp_result_t err); + void resultSuccess(); + +private: + static bool passProvider(rnp_ffi_t ffi, + void * app_ctx, + rnp_key_handle_t key, + const char * pgp_context, + char buf[], + size_t buf_len); + QDir m_rnp_homedir; ///< rmp ffi. + +protected: + rnp_ffi_t m_ffi; ///< rmp ffi. + + /** + * @brief Get the path to public keys keyring. + * + * @return The path to public keys keyring + */ + QString pubringPath() { + return this->m_rnp_homedir.filePath("pubring.pgp"); + } + + /** + * @brief Get the path to secret keys keyring. + * + * @return The path to secret keys keyring + */ + QString secringPath() { + return this->m_rnp_homedir.filePath("secring.pgp"); + } + + +public: + /** + * @brief Constructor for the RnpJob class. + * + * Initializes the RnpJob instance. + */ + RnpJob(QDir rnp_homedir); + + /** + * @brief Destructor for the RnpJob class. + * + * Cleans up any resources used by the RnpJob. + */ + ~RnpJob(); +}; + +#endif // RNPJOB_H diff --git a/plugins/Pass/pass.cpp b/plugins/Pass/pass.cpp index 87a80bb..1ed7bfc 100644 --- a/plugins/Pass/pass.cpp +++ b/plugins/Pass/pass.cpp @@ -2,34 +2,36 @@ #include #include -#include "jobs/rmjob.h" +#include "jobs/importkeyjob.h" #include "pass.h" -#include "gpg.h" -#include "passkeymodel.h" Pass::Pass(): m_password_store (QStandardPaths::writableLocation( QStandardPaths::AppDataLocation).append("/.password-store")), + m_gpg_home (QStandardPaths::writableLocation( + QStandardPaths::AppDataLocation).append("/.rnp")), m_sem(std::unique_ptr(new QSemaphore(1))), m_show_filename(QString()) -{} +{ + qRegisterMetaType("rnp_result_t"); +} void Pass::initialize(QObject *window) { if (!window) { - qFatal("window is invalid. Abording."); + qWarning("Window should not be null unless your in testing"); } - this->m_gpg = std::unique_ptr(new Gpg(window)); + // this->m_gpg = std::unique_ptr(new Gpg(window)); + // UTPassphraseProvider *passphrase_provider = dynamic_cast(this->m_gpg->passphrase_provider()); + // QObject::connect(this, &Pass::responsePassphraseDialogPropagate, passphrase_provider, + // &UTPassphraseProvider::handleResponse); - QObject::connect(this, &Pass::responsePassphraseDialogPropagate, this->m_gpg->passphrase_provider(), - &UTPassphraseProvider::handleResponse); - QObject::connect(this->m_gpg.get(), &Gpg::importKeysFromFileResult, this, &Pass::importGPGKeyResult); - QObject::connect(this->m_gpg.get(), &Gpg::getKeysResult, this, &Pass::getAllGPGKeysResult); - QObject::connect(this->m_gpg.get(), &Gpg::deleteKeyResult, this, &Pass::deleteGPGKeyResult); - QObject::connect(this->m_gpg.get(), &Gpg::decryptResult, this, &Pass::showResult); + // QObject::connect(this->m_gpg.get(), &Gpg::getKeysResult, this, &Pass::getAllGPGKeysResult); + // QObject::connect(this->m_gpg.get(), &Gpg::deleteKeyResult, this, &Pass::deleteGPGKeyResult); + // QObject::connect(this->m_gpg.get(), &Gpg::decryptResult, this, &Pass::showResult); QDir dir(m_password_store); if (!dir.exists()) { @@ -38,135 +40,142 @@ void Pass::initialize(QObject *window) qInfo() << "Password Store is :" << m_password_store; } -bool Pass::show(QUrl url) +// bool Pass::show(QUrl url) +// { +// if (!this->m_sem->tryAcquire(1, 500)) { +// return false; +// } +// auto path = url.toLocalFile(); +// qInfo() << "Pass show " << path; +// QFileInfo file_info(path); +// this->m_show_filename = file_info.completeBaseName(); +// return this->m_gpg->decryptFromFile(path); +// } + + +// void Pass::showResult(Error err, QString plain_text) +// { +// qDebug() << "Pass show Result"; +// if (err) { +// qInfo() << "Pass show Failed"; +// emit showFailed(err.asString()); + +// } else if (err.isCanceled()) { +// qInfo() << "Pass show Cancelled"; +// emit showCancelled(); +// } else { +// qInfo() << "Pass show Succeed"; +// emit showSucceed(this->m_show_filename, plain_text); +// } +// this->m_show_filename = QString(); +// this->m_sem->release(1); +// } + +// bool Pass::deletePasswordStore() +// { +// if (!this->m_sem->tryAcquire(1, 500)) { +// return false; +// } +// qInfo() << "Pass delete Password Store"; +// auto job = new RmJob(this->password_store()); +// qDebug() << "Delete Password Store at " << this->password_store(); +// connect(job, &RmJob::resultReady, this, &Pass::deletePasswordStoreResult); +// connect(job, &RmJob::finished, job, &QObject::deleteLater); +// job->start(); +// return true; +// } + +// void Pass::deletePasswordStoreResult(bool err) +// { + +// qDebug() << "Pass delete Password StoreResult"; +// if (err) { //dir.removeRecursively()) { +// qInfo() << "Pass delete Password Store Failed"; +// emit deletePasswordStoreFailed("failed to delete password store"); + +// } else { +// qInfo() << "Pass delete Password Store Succeed"; +// emit deletePasswordStoreSucceed(); +// } +// this->m_sem->release(1); +// } + + +// bool Pass::deleteGPGKey(PassKeyModel* key) +// { +// if (!this->m_sem->tryAcquire(1, 500)) { +// return false; +// } +// qInfo() << "Delete Key " << key->uid(); +// return this->m_gpg->deleteKey(key->key()); +// } + +// void Pass::deleteGPGKeyResult(Error err) +// { +// qDebug() << "Delete Ke yResult"; +// if (err) { +// qInfo() << "Delete Key Failed"; +// emit deleteGPGKeyFailed(err.asString()); +// } else { +// qInfo() << "Delete Key Succeed"; +// emit deleteGPGKeySucceed(); +// } +// this->m_sem->release(1); +// } + +bool Pass::importGPGKey(QUrl url) { + qInfo() << "Import GPG Key from " << url; if (!this->m_sem->tryAcquire(1, 500)) { + qInfo() << "A job is already running"; return false; } - auto path = url.toLocalFile(); - qInfo() << "Pass show " << path; - QFileInfo file_info(path); - this->m_show_filename = file_info.completeBaseName(); - return this->m_gpg->decryptFromFile(path); -} - - -void Pass::showResult(Error err, QString plain_text) -{ - qDebug() << "Pass show Result"; - if (err) { - qInfo() << "Pass show Failed"; - emit showFailed(err.asString()); - - } else if (err.isCanceled()) { - qInfo() << "Pass show Cancelled"; - emit showCancelled(); - } else { - qInfo() << "Pass show Succeed"; - emit showSucceed(this->m_show_filename, plain_text); - } - this->m_show_filename = QString(); - this->m_sem->release(1); -} - -bool Pass::deletePasswordStore() -{ - if (!this->m_sem->tryAcquire(1, 500)) { - return false; - } - qInfo() << "Pass delete Password Store"; - auto job = new RmJob(this->password_store()); - qDebug() << "Delete Password Store at " << this->password_store(); - connect(job, &RmJob::resultReady, this, &Pass::deletePasswordStoreResult); - connect(job, &RmJob::finished, job, &QObject::deleteLater); + auto job = new ImportKeyJob(this->m_gpg_home, url.toLocalFile()); + QObject::connect(job, &ImportKeyJob::resultError, this, &Pass::slotImportGPGKeyError); + QObject::connect(job, &ImportKeyJob::resultSuccess, this, &Pass::slotImportGPGKeySucceed); + connect(job, &ImportKeyJob::finished, job, &QObject::deleteLater); job->start(); return true; } -void Pass::deletePasswordStoreResult(bool err) +void Pass::slotImportGPGKeyError(rnp_result_t err) { - - qDebug() << "Pass delete Password StoreResult"; - if (err) { //dir.removeRecursively()) { - qInfo() << "Pass delete Password Store Failed"; - emit deletePasswordStoreFailed("failed to delete password store"); - - } else { - qInfo() << "Pass delete Password Store Succeed"; - emit deletePasswordStoreSucceed(); - } + qDebug() << "Import GPG Key Failed"; + emit importGPGKeyFailed(rnp_result_to_string(err)); this->m_sem->release(1); } - -bool Pass::deleteGPGKey(PassKeyModel* key) +void Pass::slotImportGPGKeySucceed() { - if (!this->m_sem->tryAcquire(1, 500)) { - return false; - } - qInfo() << "Delete Key " << key->uid(); - return this->m_gpg->deleteKey(key->key()); -} - -void Pass::deleteGPGKeyResult(Error err) -{ - qDebug() << "Delete Ke yResult"; - if (err) { - qInfo() << "Delete Key Failed"; - emit deleteGPGKeyFailed(err.asString()); - } else { - qInfo() << "Delete Key Succeed"; - emit deleteGPGKeySucceed(); - } + qDebug() << "Import GPG Key Failed"; + emit importGPGKeySucceed(); this->m_sem->release(1); } -bool Pass::importGPGKey(QUrl url) -{ - if (!this->m_sem->tryAcquire(1, 500)) { - return false; - } - qInfo() << "Import GPG Key from " << url; - return this->m_gpg->importKeysFromFile(url.toLocalFile()); -} +// bool Pass::getAllGPGKeys() +// { +// if (!this->m_sem->tryAcquire(1, 500)) { +// return false; +// } +// qInfo() << "Get GPG keys"; +// return this->m_gpg->getAllKeys(); +// } -void Pass::importGPGKeyResult(Error err) -{ - qDebug() << "Import GPG Key Result"; - if (err) { - qInfo() << "Delete Key Failed"; - emit importGPGKeyFailed(err.asString()); - } else { - qInfo() << "Delete Key Succeed"; - emit importGPGKeySucceed(); - } - this->m_sem->release(1); -} +// void Pass::getAllGPGKeysResult(Error err, std::vector keys_info) +// { +// qDebug() << "Get GPG keys Result"; +// if (err) { +// qInfo() << "Get GPG Failed"; +// emit getAllGPGKeysFailed(err.asString()); +// } else { +// qInfo() << "Get GPG Succeed"; +// emit getAllGPGKeysSucceed(QVariant::fromValue(PassKeyModel::keysToPassKey(keys_info))); +// } +// this->m_sem->release(1); +// } -bool Pass::getAllGPGKeys() -{ - if (!this->m_sem->tryAcquire(1, 500)) { - return false; - } - qInfo() << "Get GPG keys"; - return this->m_gpg->getAllKeys(); -} - -void Pass::getAllGPGKeysResult(Error err, std::vector keys_info) -{ - qDebug() << "Get GPG keys Result"; - if (err) { - qInfo() << "Get GPG Failed"; - emit getAllGPGKeysFailed(err.asString()); - } else { - qInfo() << "Get GPG Succeed"; - emit getAllGPGKeysSucceed(QVariant::fromValue(PassKeyModel::keysToPassKey(keys_info))); - } - 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 5db6f29..fcf176e 100644 --- a/plugins/Pass/pass.h +++ b/plugins/Pass/pass.h @@ -1,12 +1,16 @@ #ifndef PASS_H #define PASS_H +#include "passkeymodel.h" +#include #include #include #include #include - -#include "gpg.h" +#include +extern "C" { +#include +} using namespace GpgME; @@ -20,7 +24,8 @@ using namespace GpgME; class Pass : public QObject { Q_OBJECT - Q_PROPERTY(QString password_store READ password_store MEMBER m_password_store CONSTANT) + Q_PROPERTY(QString password_store MEMBER m_password_store READ password_store WRITE set_password_store ) + Q_PROPERTY(QString gpg_home MEMBER m_gpg_home READ gpg_home WRITE set_gpg_home ) private slots: /** @@ -37,11 +42,16 @@ private slots: void deleteGPGKeyResult(Error err); /** - * @brief Slot to handle the result of a GPG key import operation. + * @brief Slot to handle the error result of a GPG key import operation. * @param err The error that occurred during the operation. */ - void importGPGKeyResult(Error err); + void slotImportGPGKeyError(rnp_result_t err); + /** + * @brief Slot to handle the succeed result of a GPG key import operation. + * @param err The error that occurred during the operation. + */ + void slotImportGPGKeySucceed(); /** * @brief Slot to handle the result of retrieving all GPG keys. * @param err The error that occurred during the operation. @@ -131,7 +141,8 @@ signals: private: QString m_password_store; /**< The path to the password store. */ - std::unique_ptr m_gpg; /**< The GPG instance used for encryption/decryption. */ + QString m_gpg_home; /**< The path to the gpg home. */ + PassphraseProvider* m_passphrase_provider; /**< Semaphore for managing concurrent operations. */ std::unique_ptr m_sem; /**< Semaphore for managing concurrent operations. */ QString m_show_filename; /**< The filename associated with the password to show. */ @@ -147,9 +158,50 @@ public: */ QString password_store() const { - return m_password_store; + return this->m_password_store; }; + /** + * @brief Set the path to the password store. + * @param The path to the password store. + */ + void set_password_store(QString password_store) + { + qInfo() << "Password Store changed to :" << password_store; + this->m_password_store = password_store; + }; + + /** + * @brief Gets the path to the gpg home. + * @return The path to the gpg home. + */ + QString gpg_home() const + { + return this->m_gpg_home; + }; + + /** + * @brief Set the path to the gpg hom. + * @param The path to the gpg hom + */ + void set_gpg_home(QString gpg_home) + { + qInfo() << "GNUPG Home changed to :" << gpg_home; + this->m_gpg_home = gpg_home; + }; + + /** + * @brief Sets the window passphrase provider used for GPG authentication. + * + * PassphraseProvider will be deleted with destructor. + * + * @param The window used by passphrase provider. + */ + void set_passphrase_provider(PassphraseProvider* passphrase_provider) + { + this->m_passphrase_provider = passphrase_provider; + } + /** * @brief Initializes the Pass object with the given window. * @param window The QObject window to interact with. diff --git a/plugins/Pass/passphraseprovider.h b/plugins/Pass/passphraseprovider.h index c63b93a..c3e6545 100644 --- a/plugins/Pass/passphraseprovider.h +++ b/plugins/Pass/passphraseprovider.h @@ -2,13 +2,16 @@ #define UTPASSPHRASEPROVIDER_H #include +#include +#include #include #include #include #include #include #include -#include "gpg.h" + +using namespace GpgME; /** * @class UTPassphraseProvider @@ -17,7 +20,7 @@ * This class implements the `PassphraseProvider` interface from GPGME and is responsible for * obtaining passphrases for GPG operations. */ -class UTPassphraseProvider : public QObject, public PassphraseProvider +class UTPassphraseProvider : public QObject, public GpgME::PassphraseProvider { Q_OBJECT diff --git a/po/utpass.qrouland.pot b/po/utpass.qrouland.pot index 71c26a4..12ea997 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-01-28 12:44+0100\n" +"POT-Creation-Date: 2025-01-29 16:33+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" diff --git a/tests.in.cpp b/tests.in.cpp new file mode 100644 index 0000000..45f1dbe --- /dev/null +++ b/tests.in.cpp @@ -0,0 +1,20 @@ +#include +#include +#include +#include +#include +#include + + +#include + + +int main(int argc, char *argv[]) +{ + qDebug() << "Starting app from tests.cpp"; + new QGuiApplication(argc, argv); + + QGuiApplication::setApplicationName("utpass.qrouland"); + + return quick_test_main(argc, argv, @TESTS_PATH@, @TESTS_PATH@); +} diff --git a/tests/assets/gpg/test_key_invalid.gpg b/tests/assets/gpg/test_key_invalid.gpg new file mode 100644 index 0000000..19a2146 Binary files /dev/null and b/tests/assets/gpg/test_key_invalid.gpg differ diff --git a/tests/plugins/TestsUtils/CMakeLists.txt b/tests/plugins/TestsUtils/CMakeLists.txt index f475fff..d53056b 100644 --- a/tests/plugins/TestsUtils/CMakeLists.txt +++ b/tests/plugins/TestsUtils/CMakeLists.txt @@ -5,6 +5,7 @@ set( SRC plugin.cpp utils.cpp + passphraseprovider.h ) set(CMAKE_AUTOMOC ON) @@ -22,6 +23,31 @@ endif() add_library(${PLUGIN} MODULE ${SRC}) set_target_properties(${PLUGIN} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${PLUGIN}) qt5_use_modules(${PLUGIN} Qml Quick DBus) +set(RNP_BUILD_DIR "${CMAKE_SOURCE_DIR}/build/${ARCH_TRIPLET}/rnp/install") + +INCLUDE_DIRECTORIES(${RNP_BUILD_DIR}/include) + +add_library(rnp STATIC IMPORTED) +set_property(TARGET rnp PROPERTY IMPORTED_LOCATION "${RNP_BUILD_DIR}/lib/librnp.a") + +add_library(gpgerror SHARED IMPORTED) +set_property(TARGET gpgerror PROPERTY IMPORTED_LOCATION "/usr/lib/${ARCH_TRIPLET}/libgpg-error.so.0.28.0") + +add_library(libassuan SHARED IMPORTED) +set_property(TARGET libassuan PROPERTY IMPORTED_LOCATION "/usr/lib/${ARCH_TRIPLET}/libassuan.so") + +add_library(libgpgme SHARED IMPORTED) +set_property(TARGET libgpgme PROPERTY IMPORTED_LOCATION "/usr/lib/${ARCH_TRIPLET}/libgpgme.so") + +add_library(libgpgmepp SHARED IMPORTED) +set_property(TARGET libgpgmepp PROPERTY IMPORTED_LOCATION "/usr/lib/${ARCH_TRIPLET}/libgpgmepp.so") + +add_library(libqgpgme SHARED IMPORTED) +set_property(TARGET libqgpgme PROPERTY IMPORTED_LOCATION "/usr/lib/${ARCH_TRIPLET}/libqgpgme.so") + + +target_link_libraries(${PLUGIN} rnp gpgerror libassuan libgpgme libgpgmepp libqgpgme) + set(QT_IMPORTS_DIR "/lib/${ARCH_TRIPLET}") diff --git a/tests/plugins/TestsUtils/passphraseprovider.h b/tests/plugins/TestsUtils/passphraseprovider.h new file mode 100644 index 0000000..5ebbf29 --- /dev/null +++ b/tests/plugins/TestsUtils/passphraseprovider.h @@ -0,0 +1,24 @@ +#ifndef UTPASSPHRASEPROVIDER_H +#define UTPASSPHRASEPROVIDER_H + +#include +#include +#include + +class TesTPassphraseProvider : public QObject, public GpgME::PassphraseProvider +{ +Q_OBJECT + +public: + char *getPassphrase(const char *useridHint, + const char *description, + bool previousWasBad, + bool &canceled) override { + + char *ret; + gpgrt_asprintf(&ret, "%s", "utpasspassphrase"); + return ret; + }; +}; + +#endif diff --git a/tests/plugins/TestsUtils/plugin.cpp b/tests/plugins/TestsUtils/plugin.cpp index 5a7f324..3413484 100644 --- a/tests/plugins/TestsUtils/plugin.cpp +++ b/tests/plugins/TestsUtils/plugin.cpp @@ -6,5 +6,5 @@ void TestsUtilsPlugin::registerTypes(const char *uri) { //@uri TestUtils - qmlRegisterSingletonType(uri, 1, 0, "TestUtils", [](QQmlEngine *, QJSEngine *) -> QObject * { return new TestsUtils; }); + qmlRegisterSingletonType(uri, 1, 0, "TestsUtils", [](QQmlEngine *, QJSEngine *) -> QObject * { return new TestsUtils; }); } diff --git a/tests/plugins/TestsUtils/qmldir b/tests/plugins/TestsUtils/qmldir index b129367..31ad842 100644 --- a/tests/plugins/TestsUtils/qmldir +++ b/tests/plugins/TestsUtils/qmldir @@ -1,2 +1,2 @@ -module TestUtils -plugin TestUtils +module TestsUtils +plugin TestsUtils diff --git a/tests/plugins/TestsUtils/utils.cpp b/tests/plugins/TestsUtils/utils.cpp index 1176d1d..57003f7 100644 --- a/tests/plugins/TestsUtils/utils.cpp +++ b/tests/plugins/TestsUtils/utils.cpp @@ -3,17 +3,21 @@ #include #include #include +#include #include +#include "passphraseprovider.h" #include "utils.h" +TestsUtils::TestsUtils(): +m_passphrase_povider(std::unique_ptr(new TesTPassphraseProvider())) +{} + QString TestsUtils::getTempPath() { - qFatal("yp"); // Get the system's temporary directory - QString tempDir = QStandardPaths::writableLocation(QStandardPaths::CacheLocation); - qDebug() << "TempDir : " << tempDir; + QString tempDir = QStandardPaths::writableLocation(QStandardPaths::TempLocation); // Generate a unique UUID QString uuid = QUuid::createUuid().toString(QUuid::WithoutBraces); @@ -22,17 +26,16 @@ QString TestsUtils::getTempPath() QString newTempDir = tempDir + "/" + uuid; QDir dir; - if (!dir.exists(newTempDir)) { - // Create the directory - if (dir.mkpath(newTempDir)) { - return newTempDir; // Return the path if successful - } else { - return "Failed to create directory"; // Return an error message - } - } else { - return newTempDir; // If the directory already exists, return its path - } + dir.mkpath(newTempDir); + + qDebug() << "TempDir : " << newTempDir; + return newTempDir; } +QObject* TestsUtils::getTestPassphraseProvider() +{ + return this->m_passphrase_povider.get(); +} + diff --git a/tests/plugins/TestsUtils/utils.h b/tests/plugins/TestsUtils/utils.h index ceb0ceb..43fb66c 100644 --- a/tests/plugins/TestsUtils/utils.h +++ b/tests/plugins/TestsUtils/utils.h @@ -1,19 +1,25 @@ #ifndef TESTSUTILS_H #define TESTSUTILS_H +#include "passphraseprovider.h" #include #include #include +#include class TestsUtils : public QObject { Q_OBJECT +private: + std::unique_ptr m_passphrase_povider; + public: - TestsUtils() = default; + TestsUtils(); ~TestsUtils() override = default; Q_INVOKABLE QString getTempPath(); + Q_INVOKABLE QObject* getTestPassphraseProvider(); }; #endif diff --git a/tests/unit/tst_git.qml b/tests/unit/tst_git.qml deleted file mode 100644 index 1f47773..0000000 --- a/tests/unit/tst_git.qml +++ /dev/null @@ -1,11 +0,0 @@ -import Git 1.0 -import QtQuick 2.9 -import QtTest 1.2 - -TestCase { - function test_git_clone() { - verify(Git.clone("", "")); - } - - name: "git" -} diff --git a/tests/unit/tst_pass.qml b/tests/unit/tst_pass.qml deleted file mode 100644 index 1f47773..0000000 --- a/tests/unit/tst_pass.qml +++ /dev/null @@ -1,11 +0,0 @@ -import Git 1.0 -import QtQuick 2.9 -import QtTest 1.2 - -TestCase { - function test_git_clone() { - verify(Git.clone("", "")); - } - - name: "git" -} diff --git a/tests/units/pass/PassTestCase.qml b/tests/units/pass/PassTestCase.qml new file mode 100644 index 0000000..823db22 --- /dev/null +++ b/tests/units/pass/PassTestCase.qml @@ -0,0 +1,13 @@ +import QtQuick 2.9 +import QtTest 1.2 +import TestsUtils 1.0 +import Pass 1.0 + +TestCase { + function init() { + Pass.initialize(null); + Pass.gpg_home = TestsUtils.getTempPath(); + Pass.password_store = TestsUtils.getTempPath(); + Pass.passphrase_provider = TestsUtils.getTestPassphraseProvider(); + } +} diff --git a/tests/units/pass/tst_import_key.qml b/tests/units/pass/tst_import_key.qml new file mode 100644 index 0000000..ab0fb3f --- /dev/null +++ b/tests/units/pass/tst_import_key.qml @@ -0,0 +1,47 @@ +import QtQuick 2.9 +import QtTest 1.2 +import TestsUtils 1.0 +import Pass 1.0 + +PassTestCase { + function init_data() { + return [ + { file: Qt.resolvedUrl("../../assets/gpg/test_key.gpg"), spy: importGPGKeySucceed, signal: Pass.importGPGKeySucceed, err_msg : null } + , { file: Qt.resolvedUrl("../../assets/gpg/test_key_do_not_exist.gpg"), spy: importGPGKeyFailed, signal: Pass.importGPGKeyFailed, err_msg : "Error reading file" } + , { file: Qt.resolvedUrl("../../assets/gpg/test_key_invalid.gpg"), spy: importGPGKeyFailed, signal: Pass.importGPGKeyFailed, err_msg : "Bad format" } + ]; + } + + SignalSpy { + id: importGPGKeySucceed + target: Pass + signalName: "importGPGKeySucceed" + } + + SignalSpy { + id: importGPGKeyFailed + target: Pass + signalName: "importGPGKeyFailed" + } + + SignalSpy { + id: importGPGKeyCancelled + target: Pass + signalName: "importGPGKeyCancelled" + } + + function test_import_key(data) { + var err_msg; + + data.signal.connect(function(message) { + err_msg = message; + }); + + Pass.importGPGKey(data.file); + + data.spy.wait(); + if(data.err_msg) { + verify(err_msg === data.err_msg, "Should return arg msg %1 but return %2".arg(data.err_msg).arg(err_msg)); + } + } +} diff --git a/tests/units/tst_git.qml b/tests/units/tst_git.qml new file mode 100644 index 0000000..7d4c30a --- /dev/null +++ b/tests/units/tst_git.qml @@ -0,0 +1,13 @@ +import Pass 1.0 +import QtQuick 2.9 +import QtTest 1.2 + +TestCase { + function test_import_key(){ + var homedir = TestUtils.getTempPath(); + Pass + verify(false); + } + + name: "git" +} diff --git a/tests/unit/tst_utils.qml b/tests/units/tst_utils.qml similarity index 94% rename from tests/unit/tst_utils.qml rename to tests/units/tst_utils.qml index c8f0f4b..96ff61e 100644 --- a/tests/unit/tst_utils.qml +++ b/tests/units/tst_utils.qml @@ -1,6 +1,6 @@ import QtQuick 2.9 import QtTest 1.2 -import TestUtils 1.0 +import TestsUtils 1.0 import Utils 1.0 TestCase {