1
0
mirror of https://github.com/QRouland/UTPass.git synced 2025-02-11 15:07:16 +00:00

First draft Rewrite get all key with rnp

This commit is contained in:
Quentin Rouland 2025-01-30 16:25:29 +01:00
parent 2c9d82e0b1
commit 4bec3dcbc9
25 changed files with 558 additions and 122 deletions

View File

@ -12,6 +12,7 @@ dependencies_target:
- libquazip5-dev - libquazip5-dev
- libgpgmepp-dev - libgpgmepp-dev
- libgpgme-dev - libgpgme-dev
- libjson-c-dev
- gpg - gpg
libraries: libraries:

127
cmake/FindJSON-C.cmake Normal file
View File

@ -0,0 +1,127 @@
# Copyright (c) 2018, 2024 Ribose Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#.rst:
# FindJSON-C
# -----------
#
# Find the json-c library.
#
# IMPORTED Targets
# ^^^^^^^^^^^^^^^^
#
# This module defines :prop_tgt:`IMPORTED` targets:
#
# ``JSON-C::JSON-C``
# The json-c library, if found.
#
# Result variables
# ^^^^^^^^^^^^^^^^
#
# This module defines the following variables:
#
# ::
#
# JSON-C_FOUND - true if the headers and library were found
# JSON-C_INCLUDE_DIRS - where to find headers
# JSON-C_LIBRARIES - list of libraries to link
# JSON-C_VERSION - library version that was found, if any
# use pkg-config to get the directories and then use these values
# in the find_path() and find_library() calls
find_package(PkgConfig)
pkg_check_modules(PC_JSON-C QUIET json-c)
# RHEL-based systems may have json-c12
if (NOT PC_JSON-C_FOUND)
pkg_check_modules(PC_JSON-C QUIET json-c12)
endif()
# ..or even json-c13, accompanied by non-develop json-c (RHEL 8 ubi)
if (NOT PC_JSON-C_FOUND)
pkg_check_modules(PC_JSON-C QUIET json-c13)
endif()
# find the headers
find_path(JSON-C_INCLUDE_DIR
NAMES json_c_version.h
HINTS
${PC_JSON-C_INCLUDEDIR}
${PC_JSON-C_INCLUDE_DIRS}
PATH_SUFFIXES json-c json-c12 json-c13
)
# find the library
find_library(JSON-C_LIBRARY
NAMES json-c libjson-c json-c12 libjson-c12 json-c13 libjson-c13
HINTS
${PC_JSON-C_LIBDIR}
${PC_JSON-C_LIBRARY_DIRS}
)
# determine the version
if(PC_JSON-C_VERSION)
set(JSON-C_VERSION ${PC_JSON-C_VERSION})
elseif(JSON-C_INCLUDE_DIR AND EXISTS "${JSON-C_INCLUDE_DIR}/json_c_version.h")
file(STRINGS "${JSON-C_INCLUDE_DIR}/json_c_version.h" _json-c_version_h
REGEX "^#define[\t ]+JSON_C_VERSION[\t ]+\"[^\"]*\"$")
string(REGEX REPLACE ".*#define[\t ]+JSON_C_VERSION[\t ]+\"([^\"]*)\".*"
"\\1" _json-c_version_str "${_json-c_version_h}")
set(JSON-C_VERSION "${_json-c_version_str}"
CACHE INTERNAL "The version of json-c which was detected")
endif()
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(JSON-C
REQUIRED_VARS JSON-C_LIBRARY JSON-C_INCLUDE_DIR JSON-C_VERSION
VERSION_VAR JSON-C_VERSION
)
if (JSON-C_FOUND)
set(JSON-C_INCLUDE_DIRS ${JSON-C_INCLUDE_DIR} ${PC_JSON-C_INCLUDE_DIRS})
set(JSON-C_LIBRARIES ${JSON-C_LIBRARY})
endif()
if (JSON-C_FOUND AND NOT TARGET JSON-C::JSON-C)
# create the new library target
add_library(JSON-C::JSON-C UNKNOWN IMPORTED)
# set the required include dirs for the target
if (JSON-C_INCLUDE_DIRS)
set_target_properties(JSON-C::JSON-C
PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${JSON-C_INCLUDE_DIRS}"
)
endif()
# set the required libraries for the target
if (EXISTS "${JSON-C_LIBRARY}")
set_target_properties(JSON-C::JSON-C
PROPERTIES
IMPORTED_LINK_INTERFACE_LANGUAGES "C"
IMPORTED_LOCATION "${JSON-C_LIBRARY}"
)
endif()
endif()
mark_as_advanced(JSON-C_INCLUDE_DIR JSON-C_LIBRARY)

View File

@ -8,6 +8,7 @@ set(
passkeymodel.h passkeymodel.h
jobs/rmjob.cpp jobs/rmjob.cpp
jobs/rnpjob.cpp jobs/rnpjob.cpp
jobs/getkeysjob.cpp
jobs/importkeyjob.cpp jobs/importkeyjob.cpp
) )
@ -32,6 +33,7 @@ qt5_use_modules(${PLUGIN} Qml Quick DBus)
set(RNP_BUILD_DIR "${CMAKE_SOURCE_DIR}/build/${ARCH_TRIPLET}/rnp/install") set(RNP_BUILD_DIR "${CMAKE_SOURCE_DIR}/build/${ARCH_TRIPLET}/rnp/install")
find_package(OpenSSL REQUIRED) find_package(OpenSSL REQUIRED)
find_package(JSON-C 0.11)
INCLUDE_DIRECTORIES(${RNP_BUILD_DIR}/include) INCLUDE_DIRECTORIES(${RNP_BUILD_DIR}/include)
@ -57,7 +59,7 @@ add_library(libqgpgme SHARED IMPORTED)
set_property(TARGET libqgpgme PROPERTY IMPORTED_LOCATION "/usr/lib/${ARCH_TRIPLET}/libqgpgme.so") set_property(TARGET libqgpgme PROPERTY IMPORTED_LOCATION "/usr/lib/${ARCH_TRIPLET}/libqgpgme.so")
target_link_libraries(${PLUGIN} rnp sexpp gpgerror libassuan libgpgme libgpgmepp libqgpgme OpenSSL::Crypto) target_link_libraries(${PLUGIN} rnp sexpp gpgerror libassuan libgpgme libgpgmepp libqgpgme OpenSSL::Crypto JSON-C::JSON-C)
set(QT_IMPORTS_DIR "/lib/${ARCH_TRIPLET}") set(QT_IMPORTS_DIR "/lib/${ARCH_TRIPLET}")
install(TARGETS ${PLUGIN} DESTINATION ${QT_IMPORTS_DIR}/${PLUGIN}/) install(TARGETS ${PLUGIN} DESTINATION ${QT_IMPORTS_DIR}/${PLUGIN}/)

View File

@ -0,0 +1,29 @@
#include <QDebug>
#include "getkeysjob.h"
#include <QJsonDocument>
#include <QJsonObject>
extern "C" {
#include <rnp/rnp.h>
#include <rnp/rnp_err.h>
}
GetKeysJob::GetKeysJob(QDir rnp_homedir):
RnpJob(rnp_homedir)
{
this->setObjectName("GetKeysJob");
}
void GetKeysJob::run()
{
qDebug() << "[GetKeysJob] Starting";
// Loading keyring
QSet<QString> fingerprints = QSet<QString>();
this->load_full_keyring(&fingerprints);
//Get all infos keys
emit resultSuccess(fingerprints);
qDebug() << "[GetKeysJob] Finished Successfully ";
}

View File

@ -0,0 +1,38 @@
#ifndef GETKEYSJOB_H
#define GETKEYSJOB_H
#include <QJsonDocument>
#include "rnpjob.h"
/**
* @class GetKeysJob
* @brief A class to handle get all gpg keys from rings in a separate thread.
*
*/
class GetKeysJob : public RnpJob
{
Q_OBJECT
/**
* @brief The main function that performs the get all keys operation.
*
* Handles the process of removing recursively a target path.
*/
void run() override;
signals:
void resultError(const rnp_result_t err);
void resultSuccess(const QSet<QString> result);
public:
/**
* @brief Constructor for the GetKeysJob class.
*
* @param rnp_homedir Rnp home dir that contains the keyrings.
*/
GetKeysJob(QDir rnp_homedir);
};
#endif // GETKEYSJOB_H

View File

@ -1,5 +1,8 @@
#include <QDebug> #include <QDebug>
#include <QString>
#include <QJsonDocument>
#include "importkeyjob.h" #include "importkeyjob.h"
extern "C" { extern "C" {
#include <rnp/rnp.h> #include <rnp/rnp.h>
#include <rnp/rnp_err.h> #include <rnp/rnp_err.h>
@ -9,38 +12,52 @@ ImportKeyJob::ImportKeyJob(QDir rnp_homedir, QString key_file_path):
RnpJob(rnp_homedir), RnpJob(rnp_homedir),
m_key_file_path(key_file_path) m_key_file_path(key_file_path)
{ {
this->setObjectName("DecryptJob"); this->setObjectName("ImportKeyJob");
} }
void ImportKeyJob::run() void ImportKeyJob::run()
{ {
qDebug() << "ImportKeyJob Starting "; qDebug() << "[ImportKeyJob] Starting";
rnp_input_t input = NULL; rnp_input_t input = NULL;
auto ret = rnp_input_from_path(&input, this->m_key_file_path.toLocal8Bit().constData()); auto ret = rnp_input_from_path(&input, this->m_key_file_path.toLocal8Bit().constData());
if (ret == RNP_SUCCESS) { if (ret == RNP_SUCCESS) {
ret = rnp_load_keys(this->m_ffi, char *r = NULL;
"GPG", ret = rnp_import_keys(this->m_ffi,
input, input,
RNP_LOAD_SAVE_PUBLIC_KEYS | RNP_LOAD_SAVE_SECRET_KEYS); RNP_LOAD_SAVE_PUBLIC_KEYS | RNP_LOAD_SAVE_SECRET_KEYS,
&r);
qDebug() << "[ImportKeyJob]" << QJsonDocument::fromJson(r);
rnp_buffer_destroy(r);
} }
rnp_input_destroy(input); rnp_input_destroy(input);
terminateWithError(ret); terminateOnError(ret);
rnp_output_t output = NULL; rnp_output_t output = NULL;
ret = rnp_output_to_file(&output, this->pubringPath().toLocal8Bit().constData(), RNP_OUTPUT_FILE_RANDOM); qDebug() << "[ImportKeyJob] Writing pubring to " << this->pubringPath();
ret = rnp_output_to_file(&output, this->pubringPath().toLocal8Bit().constData(), RNP_OUTPUT_FILE_OVERWRITE);
if (ret == RNP_SUCCESS) { if (ret == RNP_SUCCESS) {
ret = rnp_save_keys(this->m_ffi, RNP_KEYSTORE_GPG, output, RNP_LOAD_SAVE_SECRET_KEYS); qDebug() << "[ImportKeyJob] Saving key pubring ";
ret = rnp_save_keys(this->m_ffi, RNP_KEYSTORE_GPG, output, RNP_LOAD_SAVE_PUBLIC_KEYS);
}
if (ret == RNP_SUCCESS) {
ret = rnp_output_finish(output);
} }
rnp_output_destroy(output); rnp_output_destroy(output);
terminateWithError(ret); terminateOnError(ret);
qDebug() << "[ImportKeyJob] Writing secring to " << this->secringPath();
ret = rnp_output_to_file(&output, this->secringPath().toLocal8Bit().constData(), RNP_OUTPUT_FILE_OVERWRITE); ret = rnp_output_to_file(&output, this->secringPath().toLocal8Bit().constData(), RNP_OUTPUT_FILE_OVERWRITE);
if (ret == RNP_SUCCESS) { if (ret == RNP_SUCCESS) {
qDebug() << "[ImportKeyJob] Saving key secring ";
ret = rnp_save_keys(this->m_ffi, RNP_KEYSTORE_GPG, output, RNP_LOAD_SAVE_SECRET_KEYS); ret = rnp_save_keys(this->m_ffi, RNP_KEYSTORE_GPG, output, RNP_LOAD_SAVE_SECRET_KEYS);
} }
rnp_output_destroy(output); rnp_output_destroy(output);
terminateWithError(ret); terminateOnError(ret);
emit resultSuccess(); emit resultSuccess();
qDebug() << "ImportKeyJob Finished Successfully "; qDebug() << "[ImportKeyJob] Finished Successfully ";
} }

View File

@ -20,19 +20,22 @@ class ImportKeyJob : public RnpJob
*/ */
void run() override; void run() override;
signals:
void resultSuccess();
private: private:
QString m_key_file_path; ///< The path of the key file to import. QString m_key_file_path; ///< The path of the key file to import.
public: public:
/** /**
* @brief Constructor for the RmJob class. * @brief Constructor for the ImportKeyJob class.
* *
* Initializes the ImportKeyJob with the file to import. * Initializes the ImportKeyJob with the file to import.
* *
* @param rnp_homedir Rnp home dir that contains the keyrings.
* @param path Path of the key file to import. * @param path Path of the key file to import.
*/ */
ImportKeyJob(QDir rnp_homedir, QString key_file_path); ImportKeyJob(QDir rnp_homedir, QString path);
}; };
#endif // IMPORTKEYJOB_H #endif // IMPORTKEYJOB_H

View File

@ -1,5 +1,8 @@
#include <QDebug> #include <QDebug>
#include <QJsonDocument>
#include <QJsonObject>
#include <QSet>
#include "qjsonarray.h"
#include "rnpjob.h" #include "rnpjob.h"
extern "C" { extern "C" {
#include <rnp/rnp.h> #include <rnp/rnp.h>
@ -9,19 +12,24 @@ extern "C" {
RnpJob::RnpJob(QDir rnp_homedir): RnpJob::RnpJob(QDir rnp_homedir):
m_rnp_homedir(rnp_homedir) m_rnp_homedir(rnp_homedir)
{ {
qRegisterMetaType<rnp_result_t>("rnp_result_t");
qRegisterMetaType<QSet<QString >> ("QSet<QString>");
auto ret = rnp_ffi_create(&this->m_ffi, auto ret = rnp_ffi_create(&this->m_ffi,
RNP_KEYSTORE_GPG, RNP_KEYSTORE_GPG,
RNP_KEYSTORE_GPG); RNP_KEYSTORE_GPG);
if(ret != RNP_SUCCESS) { if(ret != RNP_SUCCESS) {
qDebug() << "Err : " << ret; qDebug() << "[RnpJob] Err : " << ret;
qFatal("Error on rnp ffi init!"); qFatal("Error on rnp ffi init!");
} }
} }
RnpJob::~RnpJob(){ RnpJob::~RnpJob()
{
auto ret = rnp_ffi_destroy(this->m_ffi); auto ret = rnp_ffi_destroy(this->m_ffi);
if(ret != RNP_SUCCESS) { if(ret != RNP_SUCCESS) {
qDebug() << "Err : " << ret; qDebug() << "[RnpJob] Err : " << ret;
qFatal("Something go wrong on rnp ffi detroy"); qFatal("Something go wrong on rnp ffi detroy");
} }
} }
@ -40,3 +48,56 @@ bool RnpJob::passProvider(rnp_ffi_t ffi,
strncpy(buf, "password", buf_len); strncpy(buf, "password", buf_len);
return true; return true;
} }
void RnpJob::load_key_file(QSet<QString> *fingerprints, const QString path, const uint32_t flags)
{
qDebug() << "[RnpJob] load keyring at" << path;
rnp_input_t input = NULL;
if (QFileInfo::exists(this->pubringPath())) {
auto ret = rnp_input_from_path(&input, path.toLocal8Bit().constData());
char *json = NULL;
if (ret == RNP_SUCCESS) {
ret = rnp_import_keys(this->m_ffi,
input,
flags,
&json);
if (ret != RNP_SUCCESS) {
}
}
QJsonDocument json_document = QJsonDocument::fromJson(json);
qDebug() << "[RnpJob] json" << json_document;
foreach (const QJsonValue fingerprint, json_document.object()["keys"].toArray()) {
qDebug() << "[RnpJob] Add fingerprint" << fingerprint["fingerprint"].toString();
fingerprints->insert(fingerprint["fingerprint"].toString());
}
rnp_input_destroy(input);
rnp_buffer_destroy(json);
terminateOnError(ret);
qDebug() << "[RnpJob] keyring loaded successfully";
} else {
qDebug() << "[RnpJob] No keyring" << path << "not found";
}
}
void RnpJob::load_pub_keyring(QSet<QString> *fingerprints)
{
this->load_key_file(fingerprints, this->pubringPath(), RNP_LOAD_SAVE_PUBLIC_KEYS);
qDebug() << "[RnpJob] pub fingerprints" << *fingerprints;
}
void RnpJob::load_sec_keyring(QSet<QString> *fingerprints)
{
this->load_key_file(fingerprints, this->secringPath(), RNP_LOAD_SAVE_SECRET_KEYS);
qDebug() << "[RnpJob] sec fingerprints" << *fingerprints;
}
void RnpJob::load_full_keyring(QSet<QString> *fingerprints)
{
this->load_pub_keyring(fingerprints);
this->load_sec_keyring(fingerprints);
qDebug() << "[RnpJob] full fingerprints" << *fingerprints;
}

View File

@ -9,10 +9,10 @@ extern "C" {
#include <variant> #include <variant>
#define terminateWithError(ret) \ #define terminateOnError(ret) \
if(ret != RNP_SUCCESS) { \ if(ret != RNP_SUCCESS) { \
qDebug() << "Err : " << ret; \ qDebug() << "[RnpJob] Err : " << ret; \
qDebug() << "Err Msg : " << rnp_result_to_string(ret); \ qDebug() << "[RnpJob] Err Msg : " << rnp_result_to_string(ret); \
emit resultError(ret); \ emit resultError(ret); \
return; \ return; \
} \ } \
@ -30,7 +30,6 @@ class RnpJob : public QThread
signals: signals:
void resultError(const rnp_result_t err); void resultError(const rnp_result_t err);
void resultSuccess();
private: private:
static bool passProvider(rnp_ffi_t ffi, static bool passProvider(rnp_ffi_t ffi,
@ -40,6 +39,7 @@ private:
char buf[], char buf[],
size_t buf_len); size_t buf_len);
QDir m_rnp_homedir; ///< rmp ffi. QDir m_rnp_homedir; ///< rmp ffi.
void load_key_file(QSet<QString> *fingerprints, const QString path, const uint32_t flags);
protected: protected:
rnp_ffi_t m_ffi; ///< rmp ffi. rnp_ffi_t m_ffi; ///< rmp ffi.
@ -49,7 +49,8 @@ protected:
* *
* @return The path to public keys keyring * @return The path to public keys keyring
*/ */
QString pubringPath() { QString pubringPath()
{
return this->m_rnp_homedir.filePath("pubring.pgp"); return this->m_rnp_homedir.filePath("pubring.pgp");
} }
@ -58,16 +59,22 @@ protected:
* *
* @return The path to secret keys keyring * @return The path to secret keys keyring
*/ */
QString secringPath() { QString secringPath()
{
return this->m_rnp_homedir.filePath("secring.pgp"); return this->m_rnp_homedir.filePath("secring.pgp");
} }
void load_sec_keyring(QSet<QString> *fingerprints);
void load_pub_keyring(QSet<QString> *fingerprints);
void load_full_keyring(QSet<QString> *fingerprints);
public: public:
/** /**
* @brief Constructor for the RnpJob class. * @brief Constructor for the RnpJob class.
* *
* Initializes the RnpJob instance. * Initializes the RnpJob instance.
*
* @param rnp_homedir Rnp home dir that contains the keyrings.
*/ */
RnpJob(QDir rnp_homedir); RnpJob(QDir rnp_homedir);

View File

@ -2,6 +2,7 @@
#include <QtCore/QStandardPaths> #include <QtCore/QStandardPaths>
#include <QtCore/QDir> #include <QtCore/QDir>
#include "jobs/getkeysjob.h"
#include "jobs/importkeyjob.h" #include "jobs/importkeyjob.h"
#include "pass.h" #include "pass.h"
@ -15,29 +16,42 @@ Pass::Pass():
m_sem(std::unique_ptr<QSemaphore>(new QSemaphore(1))), m_sem(std::unique_ptr<QSemaphore>(new QSemaphore(1))),
m_show_filename(QString()) m_show_filename(QString())
{ {
qRegisterMetaType<rnp_result_t>("rnp_result_t");
} }
void Pass::initialize(QObject *window) void Pass::initialize(QObject *window)
{ {
if (!window) { if (!window) {
qWarning("Window should not be null unless your in testing"); qWarning("[Pass] Window should be null only for testing");
}
this->initGpgHome();
this->initPasswordStore();
} }
// this->m_gpg = std::unique_ptr<Gpg>(new Gpg(window));
// UTPassphraseProvider *passphrase_provider = dynamic_cast<UTPassphraseProvider*>(this->m_gpg->passphrase_provider());
// QObject::connect(this, &Pass::responsePassphraseDialogPropagate, passphrase_provider,
// &UTPassphraseProvider::handleResponse);
// QObject::connect(this->m_gpg.get(), &Gpg::getKeysResult, this, &Pass::getAllGPGKeysResult); void Pass::initGpgHome()
// QObject::connect(this->m_gpg.get(), &Gpg::deleteKeyResult, this, &Pass::deleteGPGKeyResult); {
// QObject::connect(this->m_gpg.get(), &Gpg::decryptResult, this, &Pass::showResult); // delete gpghome from previous version using GPGME
QString path = QStandardPaths::writableLocation(
QStandardPaths::AppDataLocation).append("/.gpghome");
QDir dir(path);
dir.removeRecursively();
QDir dir(m_password_store); // create gpghome for rnp
if (!dir.exists()) { QDir dir_gpg_home(this->m_gpg_home);
dir.mkpath("."); if (!dir_gpg_home.exists()) {
dir_gpg_home.mkpath(".");
} }
qInfo() << "Password Store is :" << m_password_store; qInfo() << "[Pass] GPG Home is :" << m_gpg_home;
}
void Pass::initPasswordStore()
{
QDir dir_password_store(this->m_password_store);
if (!dir_password_store.exists()) {
dir_password_store.mkpath(".");
}
qInfo() << "[Pass] Password Store is :" << m_password_store;
} }
// bool Pass::show(QUrl url) // bool Pass::show(QUrl url)
@ -125,9 +139,9 @@ void Pass::initialize(QObject *window)
bool Pass::importGPGKey(QUrl url) bool Pass::importGPGKey(QUrl url)
{ {
qInfo() << "Import GPG Key from " << url; qInfo() << "[Pass] Import GPG Key from " << url;
if (!this->m_sem->tryAcquire(1, 500)) { if (!this->m_sem->tryAcquire(1, 500)) {
qInfo() << "A job is already running"; qInfo() << "[Pass] A job is already running";
return false; return false;
} }
auto job = new ImportKeyJob(this->m_gpg_home, url.toLocalFile()); auto job = new ImportKeyJob(this->m_gpg_home, url.toLocalFile());
@ -140,26 +154,46 @@ bool Pass::importGPGKey(QUrl url)
void Pass::slotImportGPGKeyError(rnp_result_t err) void Pass::slotImportGPGKeyError(rnp_result_t err)
{ {
qDebug() << "Import GPG Key Failed"; qInfo() << "[Pass] Import GPG Key Failed";
emit importGPGKeyFailed(rnp_result_to_string(err)); emit importGPGKeyFailed(rnp_result_to_string(err));
this->m_sem->release(1); this->m_sem->release(1);
} }
void Pass::slotImportGPGKeySucceed() void Pass::slotImportGPGKeySucceed()
{ {
qDebug() << "Import GPG Key Failed"; qInfo() << "[Pass] Import GPG Key Succesfull";
emit importGPGKeySucceed(); emit importGPGKeySucceed();
this->m_sem->release(1); this->m_sem->release(1);
} }
// bool Pass::getAllGPGKeys() bool Pass::getAllGPGKeys()
// { {
// if (!this->m_sem->tryAcquire(1, 500)) { qInfo() << "[Pass] Get all GPG Keys";
// return false; if (!this->m_sem->tryAcquire(1, 500)) {
// } qInfo() << "[Pass] A job is already running";
// qInfo() << "Get GPG keys"; return false;
// return this->m_gpg->getAllKeys(); }
// } auto job = new GetKeysJob(this->m_gpg_home);
QObject::connect(job, &GetKeysJob::resultError, this, &Pass::slotGetAllGPGKeysError);
QObject::connect(job, &GetKeysJob::resultSuccess, this, &Pass::slotGetAllGPGKeysSucceed);
connect(job, &ImportKeyJob::finished, job, &QObject::deleteLater);
job->start();
return true;
}
void Pass::slotGetAllGPGKeysError(rnp_result_t err)
{
qInfo() << "[Pass] Get all GPG Keys Failed";
emit getAllGPGKeysFailed(rnp_result_to_string(err));
this->m_sem->release(1);
}
void Pass::slotGetAllGPGKeysSucceed(QSet<QString> result)
{
qInfo() << "[Pass] Get all GPG Keys Succeed";
emit getAllGPGKeysSucceed(result.values());
this->m_sem->release(1);
}
// void Pass::getAllGPGKeysResult(Error err, std::vector<GpgME::Key> keys_info) // void Pass::getAllGPGKeysResult(Error err, std::vector<GpgME::Key> keys_info)
// { // {

View File

@ -49,15 +49,19 @@ private slots:
/** /**
* @brief Slot to handle the succeed result of a GPG key import operation. * @brief Slot to handle the succeed result of a GPG key import operation.
* @param err The error that occurred during the operation.
*/ */
void slotImportGPGKeySucceed(); void slotImportGPGKeySucceed();
/** /**
* @brief Slot to handle the result of retrieving all GPG keys. * @brief Slot to handle the result of retrieving all GPG keys.
* @param err The error that occurred during the operation. * @param err The error that occurred during the operation.
* @param keys_info The list of GPG keys retrieved.
*/ */
void getAllGPGKeysResult(Error err, std::vector<GpgME::Key> keys_info); void slotGetAllGPGKeysError(rnp_result_t err);
/**
* @brief Slot to handle the succeed result of a GPG key get all keys operation.
*/
void slotGetAllGPGKeysSucceed(QSet<QString> result);
/** /**
* @brief Slot to handle the result of a delete Password Store operation. * @brief Slot to handle the result of a delete Password Store operation.
@ -93,7 +97,7 @@ signals:
* @brief Emitted when all GPG keys are successfully retrieved. * @brief Emitted when all GPG keys are successfully retrieved.
* @param keys_info The list of retrieved keys. * @param keys_info The list of retrieved keys.
*/ */
void getAllGPGKeysSucceed(QVariant keys_info); void getAllGPGKeysSucceed(QList<QString> keys_info);
/** /**
* @brief Emitted when retrieving GPG keys fails. * @brief Emitted when retrieving GPG keys fails.
@ -146,6 +150,17 @@ private:
std::unique_ptr<QSemaphore> m_sem; /**< Semaphore for managing concurrent operations. */ std::unique_ptr<QSemaphore> m_sem; /**< Semaphore for managing concurrent operations. */
QString m_show_filename; /**< The filename associated with the password to show. */ QString m_show_filename; /**< The filename associated with the password to show. */
/**
* @brief Initialize gpg home.
*/
void initGpgHome();
/**
* @brief Initialize password store.
*/
void initPasswordStore();
public: public:
/** /**
* @brief Constructs the Pass object. * @brief Constructs the Pass object.
@ -167,7 +182,7 @@ public:
*/ */
void set_password_store(QString password_store) void set_password_store(QString password_store)
{ {
qInfo() << "Password Store changed to :" << password_store; qInfo() << "[Pass] Password Store changed to :" << password_store;
this->m_password_store = password_store; this->m_password_store = password_store;
}; };
@ -186,7 +201,7 @@ public:
*/ */
void set_gpg_home(QString gpg_home) void set_gpg_home(QString gpg_home)
{ {
qInfo() << "GNUPG Home changed to :" << gpg_home; qInfo() << "[Pass] GPG Home changed to :" << gpg_home;
this->m_gpg_home = gpg_home; this->m_gpg_home = gpg_home;
}; };

View File

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: utpass.qrouland\n" "Project-Id-Version: utpass.qrouland\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-01-29 16:33+0100\n" "POT-Creation-Date: 2025-01-30 16:16+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"

View File

@ -21,15 +21,13 @@ MainView {
pop.activateFocus(); pop.activateFocus();
} }
objectName: "mainView" objectName: "mainView"
applicationName: "utpass.qrouland" applicationName: "utpass.qrouland"
automaticOrientation: true automaticOrientation: true
width: units.gu(45) width: units.gu(45)
height: units.gu(75) height: units.gu(75)
Component.onCompleted: { Component.onCompleted: {
myWorker.sendMessage("Hello World !") myWorker.sendMessage("Hello World !");
} }
PageStack { PageStack {

View File

@ -11,7 +11,6 @@ Dialog {
signal validated() signal validated()
signal canceled() signal canceled()
Button { Button {
id: continueButton id: continueButton

View File

@ -29,7 +29,6 @@ Page {
anchors.rightMargin: units.gu(2) anchors.rightMargin: units.gu(2)
spacing: units.gu(1) spacing: units.gu(1)
Rectangle { Rectangle {
width: parent.width width: parent.width
height: units.gu(1) height: units.gu(1)

View File

@ -8,6 +8,7 @@ import QtQuick 2.4
Page { Page {
id: infoKeysPage id: infoKeysPage
property list<QtObject> __keys property list<QtObject> __keys
property QtObject __currentKey property QtObject __currentKey
@ -15,7 +16,7 @@ Page {
Pass.getAllGPGKeysSucceed.connect(function(keys_info) { Pass.getAllGPGKeysSucceed.connect(function(keys_info) {
infoKeysPage.__keys = keys_info; infoKeysPage.__keys = keys_info;
for (var i = 0; i < keys_info.length; ++i) { for (var i = 0; i < keys_info.length; ++i) {
console.debug("is secret " + keys_info[i].isSecret) console.debug("is secret " + keys_info[i].isSecret);
} }
}); });
Pass.getAllGPGKeysFailed.connect(function(message) { Pass.getAllGPGKeysFailed.connect(function(message) {
@ -108,7 +109,6 @@ Page {
userIdsModel.append({ userIdsModel.append({
"model": model.modelData.userIds[i] "model": model.modelData.userIds[i]
}); });
} }
} }
} }

Binary file not shown.

Binary file not shown.

View File

@ -13,7 +13,8 @@ public:
char *getPassphrase(const char *useridHint, char *getPassphrase(const char *useridHint,
const char *description, const char *description,
bool previousWasBad, bool previousWasBad,
bool &canceled) override { bool &canceled) override
{
char *ret; char *ret;
gpgrt_asprintf(&ret, "%s", "utpasspassphrase"); gpgrt_asprintf(&ret, "%s", "utpasspassphrase");

View File

@ -28,10 +28,45 @@ QString TestsUtils::getTempPath()
QDir dir; QDir dir;
dir.mkpath(newTempDir); dir.mkpath(newTempDir);
qDebug() << "TempDir : " << newTempDir; qDebug() << "[TestUtils] TempDir : " << newTempDir;
return newTempDir; return newTempDir;
} }
bool TestsUtils::fileExists(QUrl path)
{
QString p = path.toLocalFile();
auto ret = QFileInfo::exists(p) && QFileInfo(p).isFile();
qDebug() << "[TestUtils]" << p << "is existing file :" << ret;
return ret;
}
void TestsUtils::copyFolder(QUrl sourceFolderUrl, QUrl destFolderUrl)
{
auto sourceFolder = sourceFolderUrl.toLocalFile();
auto destFolder = destFolderUrl.toLocalFile();
QDir sourceDir(sourceFolder);
if (!sourceDir.exists())
return;
QDir destDir(destFolder);
if (!destDir.exists()) {
destDir.mkdir(destFolder);
}
qDebug() << "[TestUtils]" << "Copy files from" << sourceFolder << "to" << destFolder;
QStringList files = sourceDir.entryList(QDir::Files);
for (int i = 0; i < files.count(); i++) {
QString srcName = sourceFolder + "/" + files[i];
QString destName = destFolder + "/" + files[i];
QFile::copy(srcName, destName);
qDebug() << "[TestUtils]" << "Copy file from" << srcName << "to" << destName;
}
files.clear();
files = sourceDir.entryList(QDir::AllDirs | QDir::NoDotAndDotDot);
for (int i = 0; i < files.count(); i++) {
QString srcName = sourceFolder + "/" + files[i];
QString destName = destFolder + "/" + files[i];
this->copyFolder(srcName, destName);
}
}
QObject *TestsUtils::getTestPassphraseProvider() QObject *TestsUtils::getTestPassphraseProvider()
{ {

View File

@ -19,7 +19,10 @@ public:
~TestsUtils() override = default; ~TestsUtils() override = default;
Q_INVOKABLE QString getTempPath(); Q_INVOKABLE QString getTempPath();
Q_INVOKABLE bool fileExists(QUrl path);
Q_INVOKABLE void copyFolder(QUrl sourceFolder, QUrl destFolder);
Q_INVOKABLE QObject *getTestPassphraseProvider(); Q_INVOKABLE QObject *getTestPassphraseProvider();
}; };
#endif #endif

View File

@ -1,13 +1,19 @@
import Pass 1.0
import QtQuick 2.9 import QtQuick 2.9
import QtTest 1.2 import QtTest 1.2
import TestsUtils 1.0 import TestsUtils 1.0
import Pass 1.0
TestCase { TestCase {
property string password_store
property string gpg_home
function init() { function init() {
Pass.initialize(null); Pass.initialize(null);
Pass.gpg_home = TestsUtils.getTempPath(); gpg_home = TestsUtils.getTempPath();
Pass.password_store = TestsUtils.getTempPath(); Pass.gpg_home = gpg_home;
password_store = TestsUtils.getTempPath();
Pass.password_store = password_store;
Pass.passphrase_provider = TestsUtils.getTestPassphraseProvider(); Pass.passphrase_provider = TestsUtils.getTestPassphraseProvider();
} }
} }

View File

@ -0,0 +1,52 @@
import Pass 1.0
import QtQuick 2.9
import QtTest 1.2
import TestsUtils 1.0
PassTestCase {
function init_data() {
//TODO some additionanl error test
return [{
"spy": getAllGPGKeysSucceed,
"signal": Pass.getAllGPGKeysSucceed,
"err_msg": null,
"add_home_gpg_data": false,
"nb_keys": 0
}, {
"spy": getAllGPGKeysSucceed,
"signal": Pass.getAllGPGKeysSucceed,
"err_msg": null,
"add_home_gpg_data": true,
"nb_keys": 2
}];
}
function test_get_keys(data) {
if (data.add_home_gpg_data === true)
TestsUtils.copyFolder(Qt.resolvedUrl("../../assets/gpghome"), Qt.resolvedUrl(gpg_home));
var keys;
data.signal.connect(function(keys_info) {
keys = keys_info;
});
Pass.getAllGPGKeys();
data.spy.wait();
verify(keys.length === data.nb_keys, "Nb keys %1 but was excepted %2".arg(keys.length).arg(data.nb_keys));
}
SignalSpy {
id: getAllGPGKeysSucceed
target: Pass
signalName: "getAllGPGKeysSucceed"
}
SignalSpy {
id: getAllGPGKeysFailed
target: Pass
signalName: "getAllGPGKeysFailed"
}
}

View File

@ -1,47 +1,56 @@
import Pass 1.0
import QtQuick 2.9 import QtQuick 2.9
import QtTest 1.2 import QtTest 1.2
import TestsUtils 1.0 import TestsUtils 1.0
import Pass 1.0
PassTestCase { PassTestCase {
function init_data() { function init_data() {
return [ return [{
{ file: Qt.resolvedUrl("../../assets/gpg/test_key.gpg"), spy: importGPGKeySucceed, signal: Pass.importGPGKeySucceed, err_msg : null } "file": Qt.resolvedUrl("../../assets/gpg/test_key.gpg"),
, { file: Qt.resolvedUrl("../../assets/gpg/test_key_do_not_exist.gpg"), spy: importGPGKeyFailed, signal: Pass.importGPGKeyFailed, err_msg : "Error reading file" } "spy": importGPGKeySucceed,
, { file: Qt.resolvedUrl("../../assets/gpg/test_key_invalid.gpg"), spy: importGPGKeyFailed, signal: Pass.importGPGKeyFailed, err_msg : "Bad format" } "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 state"
}];
}
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));
} else {
console.info(Qt.resolvedUrl("%1/pubkeyring.pgp".arg(gpg_home)));
verify(TestsUtils.fileExists(Qt.resolvedUrl("%1/pubring.pgp".arg(gpg_home))), "%1/pubring.pgp should be created".arg(gpg_home));
verify(TestsUtils.fileExists(Qt.resolvedUrl("%1/secring.pgp".arg(gpg_home))), "%1/secring.pgp should be created".arg(gpg_home));
}
} }
SignalSpy { SignalSpy {
id: importGPGKeySucceed id: importGPGKeySucceed
target: Pass target: Pass
signalName: "importGPGKeySucceed" signalName: "importGPGKeySucceed"
} }
SignalSpy { SignalSpy {
id: importGPGKeyFailed id: importGPGKeyFailed
target: Pass target: Pass
signalName: "importGPGKeyFailed" 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));
}
}
} }

View File

@ -5,7 +5,7 @@ import QtTest 1.2
TestCase { TestCase {
function test_import_key() { function test_import_key() {
var homedir = TestUtils.getTempPath(); var homedir = TestUtils.getTempPath();
Pass Pass;
verify(false); verify(false);
} }