diff options
author | saturneric <[email protected]> | 2023-10-25 14:28:25 +0000 |
---|---|---|
committer | saturneric <[email protected]> | 2023-10-25 14:28:25 +0000 |
commit | b7ceed0b87752077fe19fefe9b0df8ec27ce0531 (patch) | |
tree | 51cb5f2a9210dabaa585b65d085f336cc5f0f844 /src | |
parent | fix: solve some code tidy issues (diff) | |
download | GpgFrontend-b7ceed0b87752077fe19fefe9b0df8ec27ce0531.tar.gz GpgFrontend-b7ceed0b87752077fe19fefe9b0df8ec27ce0531.zip |
feat: moving gnupg info gathering logic to a new module
Diffstat (limited to 'src')
32 files changed, 923 insertions, 617 deletions
diff --git a/src/core/GpgConstants.cpp b/src/core/GpgConstants.cpp index 932b5f88..76e5fa6f 100644 --- a/src/core/GpgConstants.cpp +++ b/src/core/GpgConstants.cpp @@ -28,7 +28,9 @@ #include "core/GpgConstants.h" +#include <boost/algorithm/string.hpp> #include <boost/algorithm/string/predicate.hpp> +#include <boost/lexical_cast.hpp> #include <sstream> #include "core/function/FileOperator.h" @@ -203,3 +205,41 @@ void GpgFrontend::_result_ref_deletor::operator()(void* _result) { SPDLOG_TRACE("gpgme unref {}", _result); if (_result != nullptr) gpgme_result_unref(_result); } + +int GpgFrontend::software_version_compare(const std::string& a, + const std::string& b) { + auto remove_prefix = [](const std::string& version) { + return version.front() == 'v' ? version.substr(1) : version; + }; + + std::string real_version_a = remove_prefix(a); + std::string real_version_b = remove_prefix(b); + + std::vector<std::string> split_a, split_b; + boost::split(split_a, real_version_a, boost::is_any_of(".")); + boost::split(split_b, real_version_b, boost::is_any_of(".")); + + const int min_depth = std::min(split_a.size(), split_b.size()); + + for (int i = 0; i < min_depth; ++i) { + int num_a = 0, num_b = 0; + + try { + num_a = boost::lexical_cast<int>(split_a[i]); + num_b = boost::lexical_cast<int>(split_b[i]); + } catch (boost::bad_lexical_cast&) { + // Handle exception if needed + return 0; + } + + if (num_a != num_b) { + return (num_a > num_b) ? 1 : -1; + } + } + + if (split_a.size() != split_b.size()) { + return (split_a.size() > split_b.size()) ? 1 : -1; + } + + return 0; +} diff --git a/src/core/GpgConstants.h b/src/core/GpgConstants.h index 477c48cc..f7b623f1 100644 --- a/src/core/GpgConstants.h +++ b/src/core/GpgConstants.h @@ -168,6 +168,9 @@ std::string read_all_data_in_file(const std::string& path); GPGFRONTEND_CORE_EXPORT bool write_buffer_to_file( const std::string& path, const std::string& out_buffer); +int GPGFRONTEND_CORE_EXPORT software_version_compare(const std::string& a, + const std::string& b); + /** * @brief Get the file extension object * diff --git a/src/core/GpgContext.cpp b/src/core/GpgContext.cpp index 6e6cf4dd..8b4677ff 100644 --- a/src/core/GpgContext.cpp +++ b/src/core/GpgContext.cpp @@ -30,21 +30,16 @@ #include <gpg-error.h> #include <gpgme.h> -#include <spdlog/spdlog.h> #include <unistd.h> -#include <mutex> -#include <shared_mutex> -#include <string> -#include <vector> - #include "core/GpgConstants.h" #include "core/common/CoreCommonUtil.h" #include "core/function/CoreSignalStation.h" #include "core/function/gpg/GpgCommandExecutor.h" +#include "core/function/gpg/GpgKeyGetter.h" +#include "core/module/ModuleManager.h" #include "core/thread/Task.h" #include "core/thread/TaskRunnerGetter.h" -#include "function/gpg/GpgKeyGetter.h" #ifdef _WIN32 #include <windows.h> @@ -63,20 +58,13 @@ GpgContext::GpgContext(const GpgContextInitArgs &args) : args_(args) { gpgme_ctx_t _p_ctx; // get gpgme library version - info_.GpgMEVersion = gpgme_check_version(nullptr); + Module::UpsertRTValue("core", "gpgme.version", + std::string(gpgme_check_version(nullptr))); // create a new context check_gpg_error(gpgme_new(&_p_ctx)); _ctx_ref = CtxRefHandler(_p_ctx); - if (args.gpg_alone) { - info_.AppPath = args.gpg_path; - auto err = gpgme_ctx_set_engine_info(_ctx_ref.get(), GPGME_PROTOCOL_OpenPGP, - info_.AppPath.c_str(), - info_.DatabasePath.c_str()); - assert(check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR); - } - if (args.custom_gpgconf && !args.custom_gpgconf_path.empty()) { SPDLOG_DEBUG("set custom gpgconf path: {}", args.custom_gpgconf_path); auto err = @@ -119,22 +107,30 @@ GpgContext::GpgContext(const GpgContextInitArgs &args) : args_(args) { switch (engine_info->protocol) { case GPGME_PROTOCOL_OpenPGP: find_openpgp = true; - info_.AppPath = engine_info->file_name; - info_.GnupgVersion = engine_info->version; - info_.DatabasePath = std::string(engine_info->home_dir == nullptr - ? "default" - : engine_info->home_dir); + + Module::UpsertRTValue("core", "gpgme.ctx.app_path", + std::string(engine_info->file_name)); + Module::UpsertRTValue("core", "gpgme.ctx.gnupg_version", + std::string(engine_info->version)); + Module::UpsertRTValue("core", "gpgme.ctx.database_path", + std::string(engine_info->home_dir == nullptr + ? "default" + : engine_info->home_dir)); break; case GPGME_PROTOCOL_CMS: find_cms = true; - info_.CMSPath = engine_info->file_name; + Module::UpsertRTValue("core", "gpgme.ctx.cms_path", + std::string(engine_info->file_name)); + break; case GPGME_PROTOCOL_GPGCONF: find_gpgconf = true; - info_.GpgConfPath = engine_info->file_name; + Module::UpsertRTValue("core", "gpgme.ctx.gpgconf_path", + std::string(engine_info->file_name)); break; case GPGME_PROTOCOL_ASSUAN: - info_.AssuanPath = engine_info->file_name; + Module::UpsertRTValue("core", "gpgme.ctx.assuan_path", + std::string(engine_info->file_name)); break; case GPGME_PROTOCOL_G13: break; @@ -152,18 +148,28 @@ GpgContext::GpgContext(const GpgContextInitArgs &args) : args_(args) { // set custom key db path if (!args.db_path.empty()) { - info_.DatabasePath = args.db_path; - auto err = gpgme_ctx_set_engine_info(_ctx_ref.get(), GPGME_PROTOCOL_OpenPGP, - info_.AppPath.c_str(), - info_.DatabasePath.c_str()); - SPDLOG_DEBUG("ctx set custom key db path: {}", info_.DatabasePath); + Module::UpsertRTValue("core", "gpgme.ctx.database_path", + std::string(args.db_path)); + + const auto app_path = Module::RetrieveRTValueTypedOrDefault<>( + "core", "gpgme.ctx.app_path", std::string{}); + const auto database_path = Module::RetrieveRTValueTypedOrDefault<>( + "core", "gpgme.ctx.database_path", std::string{}); + + auto err = + gpgme_ctx_set_engine_info(_ctx_ref.get(), GPGME_PROTOCOL_OpenPGP, + app_path.c_str(), database_path.c_str()); + SPDLOG_DEBUG("ctx set custom key db path: {}", database_path); assert(check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR); } - // conditional check - if ((info_.GnupgVersion >= "2.0.0" && find_gpgconf && find_openpgp && - find_cms) || - (info_.GnupgVersion > "1.0.0" && find_gpgconf)) + const auto gnupg_version = Module::RetrieveRTValueTypedOrDefault<>( + "core", "gpgme.ctx.gnupg_version", std::string{"0.0.0"}); + SPDLOG_DEBUG("got gnupg version from rt: {}", gnupg_version); + + // conditional check: only support gpg 2.x now + if ((software_version_compare(gnupg_version, "2.0.0") >= 0 && find_gpgconf && + find_openpgp && find_cms)) check_passed = true; if (!check_passed) { @@ -175,7 +181,7 @@ GpgContext::GpgContext(const GpgContextInitArgs &args) : args_(args) { gpgme_set_offline(*this, 1); // set keylist mode - if (info_.GnupgVersion >= "2.0.0") { + if (gnupg_version >= "2.0.0") { check_gpg_error(gpgme_set_keylist_mode( *this, GPGME_KEYLIST_MODE_LOCAL | GPGME_KEYLIST_MODE_WITH_SECRET | GPGME_KEYLIST_MODE_SIGS | @@ -203,16 +209,26 @@ GpgContext::GpgContext(const GpgContextInitArgs &args) : args_(args) { } void GpgContext::post_init_ctx() { + const auto gnupg_version = Module::RetrieveRTValueTypedOrDefault<>( + "core", "gpgme.ctx.gnupg_version", std::string{"2.0.0"}); + // Set Independent Database - if (info_.GnupgVersion <= "2.0.0" && args_.independent_database) { - info_.DatabasePath = args_.db_path; - SPDLOG_DEBUG("custom key db path {}", info_.DatabasePath); - auto err = gpgme_ctx_set_engine_info(_ctx_ref.get(), GPGME_PROTOCOL_OpenPGP, - info_.AppPath.c_str(), - info_.DatabasePath.c_str()); + if (software_version_compare(gnupg_version, "2.0.0") >= 0 && + args_.independent_database) { + const auto app_path = Module::RetrieveRTValueTypedOrDefault<>( + "core", "gpgme.ctx.app_path", std::string{}); + + Module::UpsertRTValue("core", "gpgme.ctx.database_path", + std::string(args_.db_path)); + SPDLOG_DEBUG("set custom key db path to: {}", args_.db_path); + + auto err = + gpgme_ctx_set_engine_info(_ctx_ref.get(), GPGME_PROTOCOL_OpenPGP, + app_path.c_str(), args_.db_path.c_str()); assert(check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR); } else { - info_.DatabasePath = "default"; + Module::UpsertRTValue("core", "gpgme.ctx.database_path", + std::string("default")); } if (args_.ascii) { @@ -227,13 +243,11 @@ void GpgContext::post_init_ctx() { // for unit test if (args_.test_mode) { - if (info_.GnupgVersion >= "2.1.0") SetPassphraseCb(test_passphrase_cb); + if (software_version_compare(gnupg_version, "2.1.0") >= 0) + SetPassphraseCb(test_passphrase_cb); gpgme_set_status_cb(*this, test_status_cb, nullptr); } - // preload info - auto &info = GetInfo(); - // // use custom qt dialog to replace pinentry if (!args_.use_pinentry) { SetPassphraseCb(custom_passphrase_cb); @@ -247,13 +261,16 @@ void GpgContext::post_init_ctx() { bool GpgContext::good() const { return good_; } void GpgContext::SetPassphraseCb(gpgme_passphrase_cb_t cb) const { - if (info_.GnupgVersion >= "2.1.0") { + const auto gnupg_version = Module::RetrieveRTValueTypedOrDefault<>( + "core", "gpgme.ctx.gnupg_version", std::string{"2.0.0"}); + + if (software_version_compare(gnupg_version, "2.1.0") >= 0) { if (gpgme_get_pinentry_mode(*this) != GPGME_PINENTRY_MODE_LOOPBACK) { gpgme_set_pinentry_mode(*this, GPGME_PINENTRY_MODE_LOOPBACK); } gpgme_set_passphrase_cb(*this, cb, nullptr); } else { - SPDLOG_ERROR("not supported for gnupg version: {}", info_.GnupgVersion); + SPDLOG_ERROR("not supported for gnupg version: {}", gnupg_version); } } @@ -341,330 +358,6 @@ std::string GpgContext::need_user_input_passphrase() { return final_passphrase; } -const GpgInfo &GpgContext::GetInfo(bool refresh) { - if (!extend_info_loaded_ || refresh) { - // try lock - std::unique_lock lock(preload_lock_); - - // check twice - if (extend_info_loaded_ && !refresh) return info_; - - SPDLOG_DEBUG("start to load extra info"); - - // get all components - GpgCommandExecutor::GetInstance().ExecuteSync( - {info_.GpgConfPath, - {"--list-components"}, - [this](int exit_code, const std::string &p_out, - const std::string &p_err) { - SPDLOG_DEBUG( - "gpgconf components exit_code: {} process stdout size: {}", - exit_code, p_out.size()); - - if (exit_code != 0) { - SPDLOG_ERROR( - "gpgconf execute error, process stderr: {} ,process stdout: " - "{}", - p_err, p_out); - return; - } - - auto &components_info = info_.ComponentsInfo; - components_info["gpgme"] = {"GPG Made Easy", info_.GpgMEVersion, - _("Embedded In"), "/"}; - - auto gpgconf_binary_checksum = - check_binary_chacksum(info_.GpgConfPath); - components_info["gpgconf"] = {"GPG Configure", "/", - info_.GpgConfPath, - gpgconf_binary_checksum.has_value() - ? gpgconf_binary_checksum.value() - : "/"}; - - std::vector<std::string> line_split_list; - boost::split(line_split_list, p_out, boost::is_any_of("\n")); - - for (const auto &line : line_split_list) { - std::vector<std::string> info_split_list; - boost::split(info_split_list, line, boost::is_any_of(":")); - - if (info_split_list.size() != 3) continue; - - auto component_name = info_split_list[0]; - auto component_desc = info_split_list[1]; - auto component_path = info_split_list[2]; - - boost::algorithm::trim(component_name); - boost::algorithm::trim(component_desc); - boost::algorithm::trim(component_path); - -#ifdef WINDOWS - // replace some special substrings on windows platform - boost::replace_all(component_path, "%3a", ":"); -#endif - - auto binary_checksum = check_binary_chacksum(component_path); - - SPDLOG_DEBUG( - "gnupg component name: {} desc: {} checksum: {} path: {} ", - component_name, component_desc, - binary_checksum.has_value() ? binary_checksum.value() : "/", - component_path); - - std::string version = "/"; - - if (component_name == "gpg") { - version = info_.GnupgVersion; - } - if (component_name == "gpg-agent") { - info_.GpgAgentPath = component_path; - } - if (component_name == "dirmngr") { - info_.DirmngrPath = component_path; - } - if (component_name == "keyboxd") { - info_.KeyboxdPath = component_path; - } - - { - // try lock - std::unique_lock lock(info_.Lock); - // add component info to list - components_info[component_name] = { - component_desc, version, component_path, - binary_checksum.has_value() ? binary_checksum.value() : "/"}; - } - } - }}); - - SPDLOG_DEBUG("start to get dirs info"); - - GpgCommandExecutor::ExecuteContexts exec_contexts; - - exec_contexts.emplace_back(GpgCommandExecutor::ExecuteContext{ - info_.GpgConfPath, - {"--list-dirs"}, - [this](int exit_code, const std::string &p_out, - const std::string &p_err) { - SPDLOG_DEBUG( - "gpgconf configurations exit_code: {} process stdout size: {}", - exit_code, p_out.size()); - - if (exit_code != 0) { - SPDLOG_ERROR( - "gpgconf execute error, process stderr: {} process stdout: " - "{}", - p_err, p_out); - return; - } - - auto &configurations_info = info_.ConfigurationsInfo; - - std::vector<std::string> line_split_list; - boost::split(line_split_list, p_out, boost::is_any_of("\n")); - - for (const auto &line : line_split_list) { - std::vector<std::string> info_split_list; - boost::split(info_split_list, line, boost::is_any_of(":")); - SPDLOG_DEBUG("gpgconf info line: {} info size: {}", line, - info_split_list.size()); - - if (info_split_list.size() != 2) continue; - - auto configuration_name = info_split_list[0]; - auto configuration_value = info_split_list[1]; - boost::algorithm::trim(configuration_name); - boost::algorithm::trim(configuration_value); - -#ifdef WINDOWS - // replace some special substrings on windows platform - boost::replace_all(configuration_value, "%3a", ":"); -#endif - - // record gnupg home path - if (configuration_name == "homedir") { - info_.GnuPGHomePath = info_split_list[1]; - } - - { - // try lock - std::unique_lock lock(info_.Lock); - configurations_info[configuration_name] = {configuration_value}; - } - } - }}); - - SPDLOG_DEBUG("start to get components info"); - - for (const auto &component : info_.ComponentsInfo) { - SPDLOG_DEBUG("gpgconf check options ready", "component", component.first); - - if (component.first == "gpgme" || component.first == "gpgconf") continue; - - exec_contexts.emplace_back(GpgCommandExecutor::ExecuteContext{ - info_.GpgConfPath, - {"--check-options", component.first}, - [this, component](int exit_code, const std::string &p_out, - const std::string &p_err) { - SPDLOG_DEBUG( - "gpgconf {} options exit_code: {} process stdout " - "size: {} ", - component.first, exit_code, p_out.size()); - - if (exit_code != 0) { - SPDLOG_ERROR( - "gpgconf {} options execute error, process " - "stderr: {} , process stdout:", - component.first, p_err, p_out); - return; - } - - auto &options_info = info_.OptionsInfo; - - std::vector<std::string> line_split_list; - boost::split(line_split_list, p_out, boost::is_any_of("\n")); - - for (const auto &line : line_split_list) { - std::vector<std::string> info_split_list; - boost::split(info_split_list, line, boost::is_any_of(":")); - - SPDLOG_DEBUG("component {} options line: {} info size: {}", - component.first, line, info_split_list.size()); - - if (info_split_list.size() != 6) continue; - - auto configuration_name = info_split_list[0]; - boost::algorithm::trim(configuration_name); - { - // try lock - std::unique_lock lock(info_.Lock); - options_info[configuration_name] = { - info_split_list[1], info_split_list[2], info_split_list[3], - info_split_list[4], info_split_list[5]}; - - boost::algorithm::trim(options_info[configuration_name][0]); - boost::algorithm::trim(options_info[configuration_name][1]); - boost::algorithm::trim(options_info[configuration_name][2]); - boost::algorithm::trim(options_info[configuration_name][3]); - boost::algorithm::trim(options_info[configuration_name][4]); - } - } - }}); - } - - SPDLOG_DEBUG("start to get avaliable component options info"); - - for (const auto &component : info_.ComponentsInfo) { - SPDLOG_DEBUG("gpgconf list options ready", "component", component.first); - - if (component.first == "gpgme" || component.first == "gpgconf") continue; - - exec_contexts.emplace_back(GpgCommandExecutor::ExecuteContext{ - info_.GpgConfPath, - {"--list-options", component.first}, - [this, component](int exit_code, const std::string &p_out, - const std::string &p_err) { - SPDLOG_DEBUG( - "gpgconf {} avaliable options exit_code: {} process stdout " - "size: {} ", - component.first, exit_code, p_out.size()); - - if (exit_code != 0) { - SPDLOG_ERROR( - "gpgconf {} avaliable options execute error, process stderr: " - "{} , process stdout:", - component.first, p_err, p_out); - return; - } - - auto &available_options_info = info_.AvailableOptionsInfo; - - std::vector<std::string> line_split_list; - boost::split(line_split_list, p_out, boost::is_any_of("\n")); - - for (const auto &line : line_split_list) { - std::vector<std::string> info_split_list; - boost::split(info_split_list, line, boost::is_any_of(":")); - - SPDLOG_DEBUG( - "component {} avaliable options line: {} info size: {}", - component.first, line, info_split_list.size()); - - if (info_split_list.size() != 10) continue; - - auto configuration_name = info_split_list[0]; - boost::algorithm::trim(configuration_name); - { - // try lock - std::unique_lock lock(info_.Lock); - available_options_info[configuration_name] = { - info_split_list[1], info_split_list[2], info_split_list[3], - info_split_list[4], info_split_list[5], info_split_list[6], - info_split_list[7], info_split_list[8], info_split_list[9]}; - - boost::algorithm::trim( - available_options_info[configuration_name][0]); - boost::algorithm::trim( - available_options_info[configuration_name][1]); - boost::algorithm::trim( - available_options_info[configuration_name][2]); - boost::algorithm::trim( - available_options_info[configuration_name][3]); - boost::algorithm::trim( - available_options_info[configuration_name][4]); - boost::algorithm::trim( - available_options_info[configuration_name][5]); - boost::algorithm::trim( - available_options_info[configuration_name][6]); - boost::algorithm::trim( - available_options_info[configuration_name][7]); - boost::algorithm::trim( - available_options_info[configuration_name][8]); - } - } - }}); - } - - GpgCommandExecutor::GetInstance().ExecuteConcurrentlySync(exec_contexts); - extend_info_loaded_ = true; - } - - // ensure nothing is changing now - std::shared_lock lock(preload_lock_); - return info_; -} - -std::optional<std::string> GpgContext::check_binary_chacksum( - std::filesystem::path path) { - // check file info and access rights - QFileInfo info(QString::fromStdString(path.u8string())); - if (!info.exists() || !info.isFile() || !info.isReadable()) { - SPDLOG_ERROR("get info for file {} error, exists: {}", - info.filePath().toStdString(), info.exists()); - return {}; - } - - // open and read file - QFile f(info.filePath()); - if (!f.open(QIODevice::ReadOnly)) { - SPDLOG_ERROR("open {} to calculate check sum error: {}", path.u8string(), - f.errorString().toStdString()); - return {}; - } - - // read all data from file - auto buffer = f.readAll(); - f.close(); - - auto hash_sha = QCryptographicHash(QCryptographicHash::Sha256); - // md5 - hash_sha.addData(buffer); - auto sha = hash_sha.result().toHex().toStdString(); - SPDLOG_DEBUG("checksum for file {} is {}", path.u8string(), sha); - - return sha.substr(0, 6); -} - void GpgContext::_ctx_ref_deleter::operator()(gpgme_ctx_t _ctx) { if (_ctx != nullptr) gpgme_release(_ctx); } diff --git a/src/core/GpgContext.h b/src/core/GpgContext.h index 4c09d02c..2545f304 100644 --- a/src/core/GpgContext.h +++ b/src/core/GpgContext.h @@ -28,12 +28,7 @@ #pragma once -#include <mutex> -#include <optional> -#include <shared_mutex> - #include "GpgFunctionObject.h" -#include "GpgInfo.h" namespace GpgFrontend { @@ -100,13 +95,6 @@ class GPGFRONTEND_CORE_EXPORT GpgContext [[nodiscard]] bool good() const; /** - * @brief Get the Info object - * - * @return const GpgInfo& - */ - [[nodiscard]] const GpgInfo& GetInfo(bool refresh = false); - - /** * @brief * * @return gpgme_ctx_t @@ -114,10 +102,7 @@ class GPGFRONTEND_CORE_EXPORT GpgContext operator gpgme_ctx_t() const { return _ctx_ref.get(); } private: - GpgInfo info_{}; ///< GpgContextInitArgs args_{}; ///< - bool extend_info_loaded_ = false; - std::shared_mutex preload_lock_{}; /** * @brief @@ -133,12 +118,6 @@ class GPGFRONTEND_CORE_EXPORT GpgContext std::string need_user_input_passphrase(); /** - * @brief Construct a new std::check component existence object - * - */ - std::optional<std::string> check_binary_chacksum(std::filesystem::path); - - /** * @brief * */ diff --git a/src/core/GpgCoreInit.cpp b/src/core/GpgCoreInit.cpp index 78f3ed7a..728bc93d 100644 --- a/src/core/GpgCoreInit.cpp +++ b/src/core/GpgCoreInit.cpp @@ -38,6 +38,7 @@ #include "core/GpgContext.h" #include "core/function/GlobalSettingStation.h" #include "core/function/gpg/GpgAdvancedOperator.h" +#include "core/module/ModuleManager.h" #include "core/thread/Task.h" #include "core/thread/TaskRunner.h" #include "core/thread/TaskRunnerGetter.h" @@ -101,7 +102,7 @@ void ShutdownCoreLoggingSystem() { void ResetGpgFrontendCore() { reset_gpgfrontend_core(); } -void init_gpgfrontend_core() { +void InitGpgFrontendCore() { /* Initialize the locale environment. */ SPDLOG_DEBUG("locale: {}", setlocale(LC_CTYPE, nullptr)); // init gpgme subsystem @@ -241,8 +242,19 @@ void init_gpgfrontend_core() { }, "default_channel_ctx_init")); - // try to restart all components - GpgFrontend::GpgAdvancedOperator::GetInstance().RestartGpgComponents(); + Module::ListenRTPublishEvent( + &default_ctx, + Module::GetRealModuleIdentifier( + "com.bktus.gpgfrontend.module.integrated.gnupginfogathering"), + "gnupg.gathering_done", + [=](Module::Namespace, Module::Key, int, std::any) { + SPDLOG_DEBUG( + "gnupginfogathering gnupg.gathering_done changed, restarting gpg " + "components"); + // try to restart all components + GpgFrontend::GpgAdvancedOperator::GetInstance().RestartGpgComponents(); + }); + Module::TriggerEvent("GPGFRONTEND_CORE_INITLIZED"); } void reset_gpgfrontend_core() { SingletonStorageCollection::GetInstance(true); } diff --git a/src/core/GpgCoreInit.h b/src/core/GpgCoreInit.h index ea33180c..487db62b 100644 --- a/src/core/GpgCoreInit.h +++ b/src/core/GpgCoreInit.h @@ -54,7 +54,7 @@ void GPGFRONTEND_CORE_EXPORT ResetGpgFrontendCore(); * @brief * */ -void init_gpgfrontend_core(); +void GPGFRONTEND_CORE_EXPORT InitGpgFrontendCore(); /** * @brief diff --git a/src/core/function/CharsetOperator.cpp b/src/core/function/CharsetOperator.cpp index e850a52f..4233440c 100644 --- a/src/core/function/CharsetOperator.cpp +++ b/src/core/function/CharsetOperator.cpp @@ -28,7 +28,6 @@ #include "core/function/CharsetOperator.h" -#include <spdlog/spdlog.h> #include <unicode/ucnv.h> #include <unicode/ucsdet.h> #include <unicode/ustring.h> diff --git a/src/core/function/gpg/GpgAdvancedOperator.cpp b/src/core/function/gpg/GpgAdvancedOperator.cpp index 7faab674..9f8de193 100644 --- a/src/core/function/gpg/GpgAdvancedOperator.cpp +++ b/src/core/function/gpg/GpgAdvancedOperator.cpp @@ -33,14 +33,21 @@ #include "GpgAdvancedOperator.h" #include "core/function/gpg/GpgCommandExecutor.h" +#include "core/module/ModuleManager.h" +#include "spdlog/spdlog.h" GpgFrontend::GpgAdvancedOperator::GpgAdvancedOperator(int channel) : SingletonFunctionObject(channel) {} bool GpgFrontend::GpgAdvancedOperator::ClearGpgPasswordCache() { bool success = false; + + const auto gpgconf_path = Module::RetrieveRTValueTypedOrDefault<>( + "core", "gpgme.ctx.gpgconf_path", std::string{}); + SPDLOG_DEBUG("got gpgconf path from rt: {}", gpgconf_path); + GpgFrontend::GpgCommandExecutor::GetInstance().ExecuteSync( - {ctx_.GetInfo().GpgConfPath, + {gpgconf_path, {"--reload", "gpg-agent"}, [&](int exit_code, const std::string &p_out, const std::string &p_err) { if (exit_code == 0) { @@ -53,8 +60,13 @@ bool GpgFrontend::GpgAdvancedOperator::ClearGpgPasswordCache() { bool GpgFrontend::GpgAdvancedOperator::ReloadGpgComponents() { bool success = false; + + const auto gpgconf_path = Module::RetrieveRTValueTypedOrDefault<>( + "core", "gpgme.ctx.gpgconf_path", std::string{}); + SPDLOG_DEBUG("got gpgconf path from rt: {}", gpgconf_path); + GpgFrontend::GpgCommandExecutor::GetInstance().ExecuteSync( - {ctx_.GetInfo().GpgConfPath, + {gpgconf_path, {"--reload"}, [&](int exit_code, const std::string &p_out, const std::string &p_err) { if (exit_code == 0) { @@ -69,39 +81,65 @@ bool GpgFrontend::GpgAdvancedOperator::ReloadGpgComponents() { return success; } -bool GpgFrontend::GpgAdvancedOperator::RestartGpgComponents() { - bool success = false; +void GpgFrontend::GpgAdvancedOperator::RestartGpgComponents() { + const auto gpgconf_path = Module::RetrieveRTValueTypedOrDefault<>( + "core", "gpgme.ctx.gpgconf_path", std::string{}); + SPDLOG_DEBUG("got gpgconf path from rt: {}", gpgconf_path); GpgFrontend::GpgCommandExecutor::GetInstance().ExecuteSync( - {ctx_.GetInfo().GpgConfPath, + {gpgconf_path, {"--verbose", "--kill", "all"}, [&](int exit_code, const std::string &p_out, const std::string &p_err) { - if (exit_code == 0) { - success = true; - return; - } else { + SPDLOG_DEBUG("gpgconf --kill all command got exit code: {}", + exit_code); + bool success = true; + if (exit_code != 0) { + success = false; SPDLOG_ERROR( "gpgconf execute error, process stderr: {}, process stdout: {}", p_err, p_out); + } + + SPDLOG_DEBUG("gpgconf --kill --all execute result: {}", success); + if (!success) { + SPDLOG_ERROR("restart all component after core initilized failed"); + Module::UpsertRTValue( + "core", "gpg_advanced_operator.restart_gpg_components", false); return; } - }}); - if (!success) return false; + success &= StartGpgAgent(); - success &= StartGpgAgent(); + if (!success) { + SPDLOG_ERROR("start gpg agent after core initilized failed"); + } - success &= StartDirmngr(); + success &= StartDirmngr(); - success &= StartKeyBoxd(); + if (!success) { + SPDLOG_ERROR("start dirmngr after core initilized failed"); + } - return success; + success &= StartKeyBoxd(); + + if (!success) { + SPDLOG_ERROR("start keyboxd after core initilized failed"); + } + + Module::UpsertRTValue( + "core", "gpg_advanced_operator.restart_gpg_components", true); + }}); } bool GpgFrontend::GpgAdvancedOperator::ResetConfigures() { bool success = false; + + const auto gpgconf_path = Module::RetrieveRTValueTypedOrDefault<>( + "core", "gpgme.ctx.gpgconf_path", std::string{}); + SPDLOG_DEBUG("got gpgconf path from rt: {}", gpgconf_path); + GpgFrontend::GpgCommandExecutor::GetInstance().ExecuteSync( - {ctx_.GetInfo().GpgConfPath, + {gpgconf_path, {"--apply-defaults"}, [&](int exit_code, const std::string &p_out, const std::string &p_err) { if (exit_code == 0) { @@ -119,9 +157,22 @@ bool GpgFrontend::GpgAdvancedOperator::ResetConfigures() { bool GpgFrontend::GpgAdvancedOperator::StartGpgAgent() { bool success = false; + + const auto gpg_agent_path = Module::RetrieveRTValueTypedOrDefault<>( + Module::GetRealModuleIdentifier( + "com.bktus.gpgfrontend.module.integrated.gnupginfogathering"), + "gnupg.gpg_agent_path", std::string{}); + SPDLOG_DEBUG("got gnupg agent path from rt: {}", gpg_agent_path); + + const auto home_path = Module::RetrieveRTValueTypedOrDefault<>( + Module::GetRealModuleIdentifier( + "com.bktus.gpgfrontend.module.integrated.gnupginfogathering"), + "gnupg.home_path", std::string{}); + SPDLOG_DEBUG("got gnupg home path from rt: {}", home_path); + GpgFrontend::GpgCommandExecutor::GetInstance().ExecuteSync( - {ctx_.GetInfo().GpgAgentPath, - {"--homedir", ctx_.GetInfo().GnuPGHomePath, "--daemon"}, + {gpg_agent_path, + {"--homedir", home_path, "--daemon"}, [&](int exit_code, const std::string &p_out, const std::string &p_err) { if (exit_code == 0) { success = true; @@ -143,9 +194,22 @@ bool GpgFrontend::GpgAdvancedOperator::StartGpgAgent() { bool GpgFrontend::GpgAdvancedOperator::StartDirmngr() { bool success = false; + + const auto dirmngr_path = Module::RetrieveRTValueTypedOrDefault<>( + Module::GetRealModuleIdentifier( + "com.bktus.gpgfrontend.module.integrated.gnupginfogathering"), + "gnupg.dirmngr_path", std::string{}); + SPDLOG_DEBUG("got gnupg dirmngr path from rt: {}", dirmngr_path); + + const auto home_path = Module::RetrieveRTValueTypedOrDefault<>( + Module::GetRealModuleIdentifier( + "com.bktus.gpgfrontend.module.integrated.gnupginfogathering"), + "gnupg.home_path", std::string{}); + SPDLOG_DEBUG("got gnupg home path from rt: {}", home_path); + GpgFrontend::GpgCommandExecutor::GetInstance().ExecuteSync( - {ctx_.GetInfo().DirmngrPath, - {"--homedir", ctx_.GetInfo().GnuPGHomePath, "--daemon"}, + {dirmngr_path, + {"--homedir", home_path, "--daemon"}, [&](int exit_code, const std::string &p_out, const std::string &p_err) { if (exit_code == 0) { success = true; @@ -166,9 +230,22 @@ bool GpgFrontend::GpgAdvancedOperator::StartDirmngr() { bool GpgFrontend::GpgAdvancedOperator::StartKeyBoxd() { bool success = false; + + const auto keyboxd_path = Module::RetrieveRTValueTypedOrDefault<>( + Module::GetRealModuleIdentifier( + "com.bktus.gpgfrontend.module.integrated.gnupginfogathering"), + "gnupg.keyboxd_path", std::string{}); + SPDLOG_DEBUG("got gnupg keyboxd path from rt: {}", keyboxd_path); + + const auto home_path = Module::RetrieveRTValueTypedOrDefault<>( + Module::GetRealModuleIdentifier( + "com.bktus.gpgfrontend.module.integrated.gnupginfogathering"), + "gnupg.home_path", std::string{}); + SPDLOG_DEBUG("got gnupg home path from rt: {}", home_path); + GpgFrontend::GpgCommandExecutor::GetInstance().ExecuteSync( - {ctx_.GetInfo().KeyboxdPath, - {"--homedir", ctx_.GetInfo().GnuPGHomePath, "--daemon"}, + {keyboxd_path, + {"--homedir", home_path, "--daemon"}, [&](int exit_code, const std::string &p_out, const std::string &p_err) { if (exit_code == 0) { success = true; diff --git a/src/core/function/gpg/GpgAdvancedOperator.h b/src/core/function/gpg/GpgAdvancedOperator.h index 959764ed..1e55370b 100644 --- a/src/core/function/gpg/GpgAdvancedOperator.h +++ b/src/core/function/gpg/GpgAdvancedOperator.h @@ -71,7 +71,7 @@ class GPGFRONTEND_CORE_EXPORT GpgAdvancedOperator * @return true * @return false */ - bool RestartGpgComponents(); + void RestartGpgComponents(); /** * @brief diff --git a/src/core/function/gpg/GpgCommandExecutor.cpp b/src/core/function/gpg/GpgCommandExecutor.cpp index ba2b7e02..582f8afa 100644 --- a/src/core/function/gpg/GpgCommandExecutor.cpp +++ b/src/core/function/gpg/GpgCommandExecutor.cpp @@ -99,12 +99,19 @@ Thread::Task *GpgCommandExecutor::build_task(const ExecuteContext &context) { auto &interact_function = context.interact_func; auto &callback = context.callback; + const std::string joined_argument = std::accumulate( + std::begin(arguments), std::end(arguments), std::string(), + [](const std::string &a, const std::string &b) -> std::string { + return a + (a.length() > 0 ? " " : "") + b; + }); + SPDLOG_DEBUG("building task: called cmd {} arguments size: {}", cmd, arguments.size()); Thread::Task::TaskCallback result_callback = [](int rtn, Thread::DataObjectPtr data_object) { - SPDLOG_DEBUG("data object use count: {}", data_object->GetObjectSize()); + SPDLOG_DEBUG("data object args count: {}", + data_object->GetObjectSize()); if (!data_object->Check<int, std::string, std::string, GpgCommandExecutorCallback>()) throw std::runtime_error("invalid data object size"); @@ -117,12 +124,13 @@ Thread::Task *GpgCommandExecutor::build_task(const ExecuteContext &context) { auto callback = Thread::ExtractParams<GpgCommandExecutorCallback>(data_object, 3); + SPDLOG_DEBUG("data object args got, exit_code: {}", exit_code); // call callback callback(exit_code, process_stdout, process_stderr); }; Thread::Task::TaskRunnable runner = - [](Thread::DataObjectPtr data_object) -> int { + [joined_argument](Thread::DataObjectPtr data_object) -> int { SPDLOG_DEBUG("process runner called, data object size: {}", data_object->GetObjectSize()); @@ -133,7 +141,6 @@ Thread::Task *GpgCommandExecutor::build_task(const ExecuteContext &context) { // get arguments auto cmd = Thread::ExtractParams<std::string>(data_object, 0); - SPDLOG_DEBUG("get cmd: {}", cmd); auto arguments = Thread::ExtractParams<std::vector<std::string>>(data_object, 1); auto interact_func = @@ -142,6 +149,7 @@ Thread::Task *GpgCommandExecutor::build_task(const ExecuteContext &context) { Thread::ExtractParams<GpgCommandExecutorCallback>(data_object, 3); auto *cmd_process = new QProcess(); + cmd_process->moveToThread(QThread::currentThread()); cmd_process->setProcessChannelMode(QProcess::MergedChannels); QObject::connect(cmd_process, &QProcess::started, @@ -157,16 +165,27 @@ Thread::Task *GpgCommandExecutor::build_task(const ExecuteContext &context) { QObject::connect( cmd_process, qOverload<int, QProcess::ExitStatus>(&QProcess::finished), [=](int, QProcess::ExitStatus status) { + int exit_code = cmd_process->exitCode(); if (status == QProcess::NormalExit) SPDLOG_DEBUG( - "proceess finished, succeed in executing command: {}, exit " - "status: {}", - cmd, status); + "proceess finished, succeed in executing command: {} {}, exit " + "code: {}", + cmd, joined_argument, exit_code); else SPDLOG_ERROR( - "proceess finished, error in executing command: {}, exit " - "status: {}", - cmd, status); + "proceess finished, error in executing command: {} {}, exit " + "code: {}", + cmd, joined_argument, exit_code); + std::string process_stdout = + cmd_process->readAllStandardOutput().toStdString(), + process_stderr = + cmd_process->readAllStandardError().toStdString(); + + cmd_process->close(); + cmd_process->deleteLater(); + + data_object->Swap( + {exit_code, process_stdout, process_stderr, callback}); }); cmd_process->setProgram(QString::fromStdString(cmd)); @@ -195,12 +214,6 @@ Thread::Task *GpgCommandExecutor::build_task(const ExecuteContext &context) { return 0; }; - const std::string joined_argument = std::accumulate( - std::begin(arguments), std::end(arguments), std::string(), - [](const std::string &a, const std::string &b) -> std::string { - return a + (a.length() > 0 ? " " : "") + b; - }); - return new Thread::Task( std::move(runner), (boost::format("Execute(%1%){%2%}") % cmd % joined_argument).str(), diff --git a/src/core/function/gpg/GpgKeyOpera.cpp b/src/core/function/gpg/GpgKeyOpera.cpp index bdce3831..1d31bb1d 100644 --- a/src/core/function/gpg/GpgKeyOpera.cpp +++ b/src/core/function/gpg/GpgKeyOpera.cpp @@ -28,28 +28,28 @@ #include "GpgKeyOpera.h" +#include <boost/algorithm/string.hpp> #include <boost/asio.hpp> #include <boost/date_time/posix_time/conversion.hpp> #include <boost/format.hpp> #include <boost/process/async_pipe.hpp> -#include <memory> -#include <string> -#include <vector> #include "GpgCommandExecutor.h" #include "GpgKeyGetter.h" #include "core/GpgConstants.h" #include "core/GpgGenKeyInfo.h" +#include "core/module/ModuleManager.h" -GpgFrontend::GpgKeyOpera::GpgKeyOpera(int channel) +namespace GpgFrontend { + +GpgKeyOpera::GpgKeyOpera(int channel) : SingletonFunctionObject<GpgKeyOpera>(channel) {} /** * Delete keys * @param uidList key ids */ -void GpgFrontend::GpgKeyOpera::DeleteKeys( - GpgFrontend::KeyIdArgsListPtr key_ids) { +void GpgKeyOpera::DeleteKeys(GpgFrontend::KeyIdArgsListPtr key_ids) { GpgError err; for (const auto& tmp : *key_ids) { auto key = GpgKeyGetter::GetInstance().GetKey(tmp); @@ -72,7 +72,7 @@ void GpgFrontend::GpgKeyOpera::DeleteKeys( * @param expires date and time * @return if successful */ -GpgFrontend::GpgError GpgFrontend::GpgKeyOpera::SetExpire( +GpgError GpgKeyOpera::SetExpire( const GpgKey& key, const SubkeyId& subkey_fpr, std::unique_ptr<boost::posix_time::ptime>& expires) { unsigned long expires_time = 0; @@ -102,11 +102,13 @@ GpgFrontend::GpgError GpgFrontend::GpgKeyOpera::SetExpire( * @param outputFileName out file name(path) * @return the process doing this job */ -void GpgFrontend::GpgKeyOpera::GenerateRevokeCert( - const GpgKey& key, const std::string& output_file_path) { +void GpgKeyOpera::GenerateRevokeCert(const GpgKey& key, + const std::string& output_file_path) { + const auto app_path = Module::RetrieveRTValueTypedOrDefault<>( + "core", "gpgme.ctx.app_path", std::string{}); // get all components GpgCommandExecutor::GetInstance().ExecuteSync( - {ctx_.GetInfo().AppPath, + {app_path, {"--command-fd", "0", "--status-fd", "1", "--no-tty", "-o", output_file_path, "--gen-revoke", key.GetFingerprint().c_str()}, [=](int exit_code, const std::string& p_out, const std::string& p_err) { @@ -152,8 +154,8 @@ void GpgFrontend::GpgKeyOpera::GenerateRevokeCert( * @param params key generation args * @return error information */ -GpgFrontend::GpgError GpgFrontend::GpgKeyOpera::GenerateKey( - const std::unique_ptr<GenKeyInfo>& params, GpgGenKeyResult& result) { +GpgError GpgKeyOpera::GenerateKey(const std::unique_ptr<GenKeyInfo>& params, + GpgGenKeyResult& result) { auto userid_utf8 = params->GetUserid(); const char* userid = userid_utf8.c_str(); auto algo_utf8 = params->GetAlgo() + params->GetKeySizeStr(); @@ -171,9 +173,11 @@ GpgFrontend::GpgError GpgFrontend::GpgKeyOpera::GenerateKey( GpgError err; - SPDLOG_DEBUG("ctx version, {}", ctx_.GetInfo(false).GnupgVersion); + const auto gnupg_version = Module::RetrieveRTValueTypedOrDefault<>( + "core", "gpgme.ctx.gnupg_version", std::string{"2.0.0"}); + SPDLOG_DEBUG("got gnupg version from rt: {}", gnupg_version); - if (ctx_.GetInfo(false).GnupgVersion >= "2.1.0") { + if (software_version_compare(gnupg_version, "2.1.0") >= 0) { unsigned int flags = 0; if (!params->IsSubKey()) flags |= GPGME_CREATE_CERT; @@ -231,7 +235,7 @@ GpgFrontend::GpgError GpgFrontend::GpgKeyOpera::GenerateKey( * @param params opera args * @return error info */ -GpgFrontend::GpgError GpgFrontend::GpgKeyOpera::GenerateSubkey( +GpgError GpgKeyOpera::GenerateSubkey( const GpgKey& key, const std::unique_ptr<GenKeyInfo>& params) { if (!params->IsSubKey()) return GPG_ERR_CANCELED; @@ -263,27 +267,37 @@ GpgFrontend::GpgError GpgFrontend::GpgKeyOpera::GenerateSubkey( return check_gpg_error(err); } -GpgFrontend::GpgError GpgFrontend::GpgKeyOpera::ModifyPassword( - const GpgFrontend::GpgKey& key) { - if (ctx_.GetInfo(false).GnupgVersion < "2.0.15") { +GpgError GpgKeyOpera::ModifyPassword(const GpgKey& key) { + const auto gnupg_version = Module::RetrieveRTValueTypedOrDefault<>( + "core", "gpgme.ctx.gnupg_version", std::string{"2.0.0"}); + SPDLOG_DEBUG("got gnupg version from rt: {}", gnupg_version); + + if (software_version_compare(gnupg_version, "2.0.15") < 0) { SPDLOG_ERROR("operator not support"); return GPG_ERR_NOT_SUPPORTED; } auto err = gpgme_op_passwd(ctx_, gpgme_key_t(key), 0); return check_gpg_error(err); } -GpgFrontend::GpgError GpgFrontend::GpgKeyOpera::ModifyTOFUPolicy( - const GpgFrontend::GpgKey& key, gpgme_tofu_policy_t tofu_policy) { - if (ctx_.GetInfo(false).GnupgVersion < "2.1.10") { + +GpgError GpgKeyOpera::ModifyTOFUPolicy(const GpgKey& key, + gpgme_tofu_policy_t tofu_policy) { + const auto gnupg_version = Module::RetrieveRTValueTypedOrDefault<>( + "core", "gpgme.ctx.gnupg_version", std::string{"2.0.0"}); + SPDLOG_DEBUG("got gnupg version from rt: {}", gnupg_version); + + if (software_version_compare(gnupg_version, "2.1.10") < 0) { SPDLOG_ERROR("operator not support"); return GPG_ERR_NOT_SUPPORTED; } + auto err = gpgme_op_tofu_policy(ctx_, gpgme_key_t(key), tofu_policy); return check_gpg_error(err); } -void GpgFrontend::GpgKeyOpera::DeleteKey(const GpgFrontend::KeyId& key_id) { +void GpgKeyOpera::DeleteKey(const GpgFrontend::KeyId& key_id) { auto keys = std::make_unique<KeyIdArgsList>(); keys->push_back(key_id); DeleteKeys(std::move(keys)); } +} // namespace GpgFrontend diff --git a/src/core/module/GlobalRegisterTable.cpp b/src/core/module/GlobalRegisterTable.cpp index 42a8f1f7..47552eb8 100644 --- a/src/core/module/GlobalRegisterTable.cpp +++ b/src/core/module/GlobalRegisterTable.cpp @@ -65,8 +65,6 @@ class GlobalRegisterTable::Impl { auto sub_it = sub_table.find(k); if (sub_it == sub_table.end()) { sub_it = sub_table.emplace(k, std::make_unique<Value>(Value{v})).first; - SPDLOG_DEBUG("new kv in rt, created n: {}, k: {}, v type: {}", n, k, - v.type().name()); } else { if (sub_it->second->type != v.type()) { return false; @@ -76,8 +74,7 @@ class GlobalRegisterTable::Impl { version = ++sub_it->second->version; } - emit parent_->SignalPublish(n, k, version); - SPDLOG_DEBUG("published kv to rt, n: {}, k: {}", n, k); + emit parent_->SignalPublish(n, k, version, v); return true; } @@ -95,18 +92,18 @@ class GlobalRegisterTable::Impl { ? std::optional<std::any>{sub_it->second->value} : std::nullopt; } - SPDLOG_DEBUG("looking up kv in rt done, n: {}, k: {}", n, k); return rtn; } - bool ListenPublish(QObject* o, Namespace n, Key k, LPCallback c) { + bool ListenPublish(QObject* o, Namespace n, Key k, LPCallback c, bool c_o) { if (o == nullptr) return false; - return QObject::connect(parent_, &GlobalRegisterTable::SignalPublish, o, - [n, k, c](Namespace pn, Key pk, int v) { - if (pn == n && pk == k) { - c(pn, pk, v); - } - }) == nullptr; + return QObject::connect( + parent_, &GlobalRegisterTable::SignalPublish, o, + [n, k, c](Namespace pn, Key pk, int ver, std::any value) { + if (pn == n && pk == k) { + c(pn, pk, ver, value); + } + }) == nullptr; } private: @@ -131,8 +128,8 @@ std::optional<std::any> GlobalRegisterTable::LookupKV(Namespace n, Key v) { } bool GlobalRegisterTable::ListenPublish(QObject* o, Namespace n, Key k, - LPCallback c) { - return p_->ListenPublish(o, n, k, c); + LPCallback c, bool c_o) { + return p_->ListenPublish(o, n, k, c, c_o); } } // namespace GpgFrontend::Module
\ No newline at end of file diff --git a/src/core/module/GlobalRegisterTable.h b/src/core/module/GlobalRegisterTable.h index 5991efb5..164f74b4 100644 --- a/src/core/module/GlobalRegisterTable.h +++ b/src/core/module/GlobalRegisterTable.h @@ -36,7 +36,7 @@ namespace GpgFrontend::Module { using Namespace = std::string; using Key = std::string; -using LPCallback = std::function<void(Namespace, Key, int)>; +using LPCallback = std::function<void(Namespace, Key, int, std::any)>; class GlobalRegisterTable : public QObject { Q_OBJECT @@ -49,10 +49,10 @@ class GlobalRegisterTable : public QObject { std::optional<std::any> LookupKV(Namespace, Key); - bool ListenPublish(QObject *, Namespace, Key, LPCallback); + bool ListenPublish(QObject *, Namespace, Key, LPCallback, bool); signals: - void SignalPublish(Namespace, Key, int); + void SignalPublish(Namespace, Key, int, std::any); private: class Impl; diff --git a/src/core/module/ModuleManager.cpp b/src/core/module/ModuleManager.cpp index 4a78a85b..ba24ec7a 100644 --- a/src/core/module/ModuleManager.cpp +++ b/src/core/module/ModuleManager.cpp @@ -89,8 +89,8 @@ class ModuleManager::Impl { return grt_->LookupKV(n, k); } - bool ListenPublish(QObject* o, Namespace n, Key k, LPCallback c) { - return grt_->ListenPublish(o, n, k, c); + bool ListenPublish(QObject* o, Namespace n, Key k, LPCallback c, bool c_o) { + return grt_->ListenPublish(o, n, k, c, c_o); } private: @@ -107,8 +107,9 @@ bool UpsertRTValue(const std::string& namespace_, const std::string& key, } bool GPGFRONTEND_CORE_EXPORT ListenRTPublishEvent(QObject* o, Namespace n, - Key k, LPCallback c) { - return ModuleManager::GetInstance()->ListenRTPublish(o, n, k, c); + Key k, LPCallback c, + bool c_o) { + return ModuleManager::GetInstance()->ListenRTPublish(o, n, k, c, c_o); } ModuleManager::ModuleManager() : p_(std::make_unique<Impl>()) {} @@ -146,8 +147,8 @@ std::optional<std::any> ModuleManager::RetrieveRTValue(Namespace n, Key k) { } bool ModuleManager::ListenRTPublish(QObject* o, Namespace n, Key k, - LPCallback c) { - return p_->ListenPublish(o, n, k, c); + LPCallback c, bool c_o) { + return p_->ListenPublish(o, n, k, c, c_o); } ModuleIdentifier GetRealModuleIdentifier(const ModuleIdentifier& id) { diff --git a/src/core/module/ModuleManager.h b/src/core/module/ModuleManager.h index 865f196b..1ce2d8b5 100644 --- a/src/core/module/ModuleManager.h +++ b/src/core/module/ModuleManager.h @@ -50,7 +50,7 @@ using ModuleMangerPtr = std::shared_ptr<ModuleManager>; using GMCPtr = std::shared_ptr<GlobalModuleContext>; using Namespace = std::string; using Key = std::string; -using LPCallback = std::function<void(Namespace, Key, int)>; +using LPCallback = std::function<void(Namespace, Key, int, std::any)>; ModuleIdentifier GPGFRONTEND_CORE_EXPORT GetRealModuleIdentifier(const ModuleIdentifier& id); @@ -76,7 +76,7 @@ class GPGFRONTEND_CORE_EXPORT ModuleManager : public QObject { std::optional<std::any> RetrieveRTValue(Namespace, Key); - bool ListenRTPublish(QObject*, Namespace, Key, LPCallback); + bool ListenRTPublish(QObject*, Namespace, Key, LPCallback, bool); private: class Impl; @@ -111,7 +111,8 @@ bool GPGFRONTEND_CORE_EXPORT UpsertRTValue(const std::string& namespace_, const std::any& value); bool GPGFRONTEND_CORE_EXPORT ListenRTPublishEvent(QObject*, Namespace, Key, - LPCallback); + LPCallback, + bool callback_once = true); template <typename T> std::optional<T> RetrieveRTValueTyped(const std::string& namespace_, diff --git a/src/core/thread/CtxCheckTask.cpp b/src/core/thread/CtxCheckTask.cpp index 3a248303..cfaea461 100644 --- a/src/core/thread/CtxCheckTask.cpp +++ b/src/core/thread/CtxCheckTask.cpp @@ -34,15 +34,15 @@ #include "core/function/gpg/GpgKeyGetter.h" #include "thread/Task.h" -GpgFrontend::Thread::CtxCheckTask::CtxCheckTask() : Task("ctx_check_task") { - connect(this, &CtxCheckTask::SignalGnupgNotInstall, +GpgFrontend::Thread::CoreInitTask::CoreInitTask() : Task("ctx_check_task") { + connect(this, &CoreInitTask::SignalGnupgNotInstall, CoreCommonUtil::GetInstance(), &CoreCommonUtil::SignalGnupgNotInstall); } -void GpgFrontend::Thread::CtxCheckTask::Run() { +void GpgFrontend::Thread::CoreInitTask::Run() { // Init GpgFrontend Core - init_gpgfrontend_core(); + InitGpgFrontendCore(); // Create & Check Gnupg Context Status if (!GpgContext::GetInstance().good()) { diff --git a/src/core/thread/CtxCheckTask.h b/src/core/thread/CtxCheckTask.h index f1a443ec..08eb3fc3 100644 --- a/src/core/thread/CtxCheckTask.h +++ b/src/core/thread/CtxCheckTask.h @@ -36,14 +36,14 @@ namespace GpgFrontend::Thread { * @brief * */ -class GPGFRONTEND_CORE_EXPORT CtxCheckTask : public Task { +class GPGFRONTEND_CORE_EXPORT CoreInitTask : public Task { Q_OBJECT public: /** * @brief Construct a new Ctx Check Thread object * */ - CtxCheckTask(); + CoreInitTask(); signals: /** diff --git a/src/module/GpgFrontendModuleInit.cpp b/src/module/GpgFrontendModuleInit.cpp index cd874817..46a57f47 100644 --- a/src/module/GpgFrontendModuleInit.cpp +++ b/src/module/GpgFrontendModuleInit.cpp @@ -32,6 +32,7 @@ #include <module/sdk/Log.h> // integrated modules +#include "integrated/gnupg_info_gathering_module/GnuPGInfoGatheringModule.h" #include "integrated/version_checking_module/VersionCheckingModule.h" namespace GpgFrontend::Module { @@ -45,6 +46,10 @@ void LoadGpgFrontendModules() { RegisterAndActivateModule< Integrated::VersionCheckingModule::VersionCheckingModule>(); + // VersionCheckingModule + RegisterAndActivateModule< + Integrated::GnuPGInfoGatheringModule::GnuPGInfoGatheringModule>(); + MODULE_LOG_INFO("load integrated module done."); } diff --git a/src/module/integrated/gnupg_info_gathering_module/CMakeLists.txt b/src/module/integrated/gnupg_info_gathering_module/CMakeLists.txt new file mode 100644 index 00000000..bdc7ff15 --- /dev/null +++ b/src/module/integrated/gnupg_info_gathering_module/CMakeLists.txt @@ -0,0 +1,38 @@ +# Copyright (C) 2021 Saturneric <[email protected]> +# +# This file is part of GpgFrontend. +# +# GpgFrontend is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# GpgFrontend is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GpgFrontend. If not, see <https://www.gnu.org/licenses/>. +# +# The initial version of the source code is inherited from +# the gpg4usb project, which is under GPL-3.0-or-later. +# +# All the source code of GpgFrontend was modified and released by +# Saturneric <[email protected]> starting on May 12, 2021. +# +# SPDX-License-Identifier: GPL-3.0-or-later + +# com.bktus.gpgfrontend.module.integrated.gnupginfogathering + +aux_source_directory(. INTEGRATED_MODULE_SOURCE) + +# define libgpgfrontend_module +add_library(gpgfrontend_integrated_module_gnupg_info_gathering SHARED ${INTEGRATED_MODULE_SOURCE}) + +# link sdk +target_link_libraries(gpgfrontend_integrated_module_gnupg_info_gathering PRIVATE + gpgfrontend_module_sdk) + +# using std c++ 17 +target_compile_features(gpgfrontend_integrated_module_gnupg_info_gathering PRIVATE cxx_std_17)
\ No newline at end of file diff --git a/src/module/integrated/gnupg_info_gathering_module/GnuPGInfoGatheringModule.cpp b/src/module/integrated/gnupg_info_gathering_module/GnuPGInfoGatheringModule.cpp new file mode 100644 index 00000000..e8c4cf34 --- /dev/null +++ b/src/module/integrated/gnupg_info_gathering_module/GnuPGInfoGatheringModule.cpp @@ -0,0 +1,385 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "GnuPGInfoGatheringModule.h" + +#include <boost/algorithm/string.hpp> + +#include "core/function/gpg/GpgCommandExecutor.h" + +namespace GpgFrontend::Module::Integrated::GnuPGInfoGatheringModule { + +std::optional<std::string> check_binary_chacksum(std::filesystem::path path) { + // check file info and access rights + QFileInfo info(QString::fromStdString(path.u8string())); + if (!info.exists() || !info.isFile() || !info.isReadable()) { + SPDLOG_ERROR("get info for file {} error, exists: {}", + info.filePath().toStdString(), info.exists()); + return {}; + } + + // open and read file + QFile f(info.filePath()); + if (!f.open(QIODevice::ReadOnly)) { + SPDLOG_ERROR("open {} to calculate check sum error: {}", path.u8string(), + f.errorString().toStdString()); + return {}; + } + + // read all data from file + auto buffer = f.readAll(); + f.close(); + + auto hash_sha = QCryptographicHash(QCryptographicHash::Sha256); + // md5 + hash_sha.addData(buffer); + auto sha = hash_sha.result().toHex().toStdString(); + SPDLOG_DEBUG("checksum for file {} is {}", path.u8string(), sha); + + return sha.substr(0, 6); +} + +GnuPGInfoGatheringModule::GnuPGInfoGatheringModule() + : Module( + "com.bktus.gpgfrontend.module.integrated.gnupginfogathering", "1.0.0", + ModuleMetaData{{"description", "try to gathering gnupg informations"}, + {"author", "saturneric"}}) {} + +GnuPGInfoGatheringModule::~GnuPGInfoGatheringModule() = default; + +bool GnuPGInfoGatheringModule::Register() { + MODULE_LOG_INFO("gnupg info gathering module registering"); + listenEvent("GPGFRONTEND_CORE_INITLIZED"); + return true; +} + +bool GnuPGInfoGatheringModule::Active() { + MODULE_LOG_INFO("gnupg info gathering module activating"); + return true; +} + +int GnuPGInfoGatheringModule::Exec(EventRefrernce event) { + MODULE_LOG_INFO("gnupg info gathering module executing, event id: {}", + event->GetIdentifier()); + + const auto gpgme_version = RetrieveRTValueTypedOrDefault<>( + "core", "gpgme.version", std::string{"2.0.0"}); + SPDLOG_DEBUG("got gpgme version from rt: {}", gpgme_version); + + const auto gpgconf_path = RetrieveRTValueTypedOrDefault<>( + "core", "gpgme.ctx.gpgconf_path", std::string{}); + SPDLOG_DEBUG("got gpgconf path from rt: {}", gpgconf_path); + + SPDLOG_DEBUG("start to load extra info..."); + + // get all components + GpgCommandExecutor::GetInstance().ExecuteSync( + {gpgconf_path, + {"--list-components"}, + [this, gpgme_version, gpgconf_path]( + int exit_code, const std::string &p_out, const std::string &p_err) { + SPDLOG_DEBUG( + "gpgconf components exit_code: {} process stdout size: {}", + exit_code, p_out.size()); + + if (exit_code != 0) { + SPDLOG_ERROR( + "gpgconf execute error, process stderr: {} ,process stdout: " + "{}", + p_err, p_out); + return; + } + + auto &components_info = info_.ComponentsInfo; + components_info["gpgme"] = {"GPG Made Easy", gpgme_version, + _("Embedded In"), "/"}; + + auto gpgconf_binary_checksum = check_binary_chacksum(gpgconf_path); + components_info["gpgconf"] = {"GPG Configure", "/", gpgconf_path, + gpgconf_binary_checksum.has_value() + ? gpgconf_binary_checksum.value() + : "/"}; + + std::vector<std::string> line_split_list; + boost::split(line_split_list, p_out, boost::is_any_of("\n")); + + for (const auto &line : line_split_list) { + std::vector<std::string> info_split_list; + boost::split(info_split_list, line, boost::is_any_of(":")); + + if (info_split_list.size() != 3) continue; + + auto component_name = info_split_list[0]; + auto component_desc = info_split_list[1]; + auto component_path = info_split_list[2]; + + boost::algorithm::trim(component_name); + boost::algorithm::trim(component_desc); + boost::algorithm::trim(component_path); + +#ifdef WINDOWS + // replace some special substrings on windows platform + boost::replace_all(component_path, "%3a", ":"); +#endif + + auto binary_checksum = check_binary_chacksum(component_path); + + SPDLOG_DEBUG( + "gnupg component name: {} desc: {} checksum: {} path: {} ", + component_name, component_desc, + binary_checksum.has_value() ? binary_checksum.value() : "/", + component_path); + + std::string version = "/"; + + if (component_name == "gpg") { + const auto version = RetrieveRTValueTypedOrDefault<>( + "core", "gpgme.ctx.gnupg_version", std::string{"2.0.0"}); + } + if (component_name == "gpg-agent") { + UpsertRTValue(GetModuleIdentifier(), "gnupg.gpg_agent_path", + std::string(component_path)); + } + if (component_name == "dirmngr") { + UpsertRTValue(GetModuleIdentifier(), "gnupg.dirmngr_path", + std::string(component_path)); + } + if (component_name == "keyboxd") { + UpsertRTValue(GetModuleIdentifier(), "gnupg.keyboxd_path", + std::string(component_path)); + } + + { + // try lock + std::unique_lock lock(info_.Lock); + // add component info to list + components_info[component_name] = { + component_desc, version, component_path, + binary_checksum.has_value() ? binary_checksum.value() : "/"}; + } + } + }}); + + SPDLOG_DEBUG("start to get dirs info"); + + GpgCommandExecutor::ExecuteContexts exec_contexts; + + exec_contexts.emplace_back(GpgCommandExecutor::ExecuteContext{ + gpgconf_path, + {"--list-dirs"}, + [this](int exit_code, const std::string &p_out, + const std::string &p_err) { + SPDLOG_DEBUG( + "gpgconf configurations exit_code: {} process stdout size: {}", + exit_code, p_out.size()); + + if (exit_code != 0) { + SPDLOG_ERROR( + "gpgconf execute error, process stderr: {} process stdout: " + "{}", + p_err, p_out); + return; + } + + auto &configurations_info = info_.ConfigurationsInfo; + + std::vector<std::string> line_split_list; + boost::split(line_split_list, p_out, boost::is_any_of("\n")); + + for (const auto &line : line_split_list) { + std::vector<std::string> info_split_list; + boost::split(info_split_list, line, boost::is_any_of(":")); + SPDLOG_DEBUG("gpgconf info line: {} info size: {}", line, + info_split_list.size()); + + if (info_split_list.size() != 2) continue; + + auto configuration_name = info_split_list[0]; + auto configuration_value = info_split_list[1]; + boost::algorithm::trim(configuration_name); + boost::algorithm::trim(configuration_value); + +#ifdef WINDOWS + // replace some special substrings on windows platform + boost::replace_all(configuration_value, "%3a", ":"); +#endif + + // record gnupg home path + if (configuration_name == "homedir") { + info_.GnuPGHomePath = info_split_list[1]; + } + + { + // try lock + std::unique_lock lock(info_.Lock); + configurations_info[configuration_name] = {configuration_value}; + } + } + }}); + + SPDLOG_DEBUG("start to get components info"); + + for (const auto &component : info_.ComponentsInfo) { + SPDLOG_DEBUG("gpgconf check options ready", "component", component.first); + + if (component.first == "gpgme" || component.first == "gpgconf") continue; + + exec_contexts.emplace_back(GpgCommandExecutor::ExecuteContext{ + gpgconf_path, + {"--check-options", component.first}, + [this, component](int exit_code, const std::string &p_out, + const std::string &p_err) { + SPDLOG_DEBUG( + "gpgconf {} options exit_code: {} process stdout " + "size: {} ", + component.first, exit_code, p_out.size()); + + if (exit_code != 0) { + SPDLOG_ERROR( + "gpgconf {} options execute error, process " + "stderr: {} , process stdout:", + component.first, p_err, p_out); + return; + } + + auto &options_info = info_.OptionsInfo; + + std::vector<std::string> line_split_list; + boost::split(line_split_list, p_out, boost::is_any_of("\n")); + + for (const auto &line : line_split_list) { + std::vector<std::string> info_split_list; + boost::split(info_split_list, line, boost::is_any_of(":")); + + SPDLOG_DEBUG("component {} options line: {} info size: {}", + component.first, line, info_split_list.size()); + + if (info_split_list.size() != 6) continue; + + auto configuration_name = info_split_list[0]; + boost::algorithm::trim(configuration_name); + { + // try lock + std::unique_lock lock(info_.Lock); + options_info[configuration_name] = { + info_split_list[1], info_split_list[2], info_split_list[3], + info_split_list[4], info_split_list[5]}; + + boost::algorithm::trim(options_info[configuration_name][0]); + boost::algorithm::trim(options_info[configuration_name][1]); + boost::algorithm::trim(options_info[configuration_name][2]); + boost::algorithm::trim(options_info[configuration_name][3]); + boost::algorithm::trim(options_info[configuration_name][4]); + } + } + }}); + } + + SPDLOG_DEBUG("start to get avaliable component options info"); + + for (const auto &component : info_.ComponentsInfo) { + SPDLOG_DEBUG("gpgconf list options ready", "component", component.first); + + if (component.first == "gpgme" || component.first == "gpgconf") continue; + + exec_contexts.emplace_back(GpgCommandExecutor::ExecuteContext{ + gpgconf_path, + {"--list-options", component.first}, + [this, component](int exit_code, const std::string &p_out, + const std::string &p_err) { + SPDLOG_DEBUG( + "gpgconf {} avaliable options exit_code: {} process stdout " + "size: {} ", + component.first, exit_code, p_out.size()); + + if (exit_code != 0) { + SPDLOG_ERROR( + "gpgconf {} avaliable options execute error, process stderr: " + "{} , process stdout:", + component.first, p_err, p_out); + return; + } + + auto &available_options_info = info_.AvailableOptionsInfo; + + std::vector<std::string> line_split_list; + boost::split(line_split_list, p_out, boost::is_any_of("\n")); + + for (const auto &line : line_split_list) { + std::vector<std::string> info_split_list; + boost::split(info_split_list, line, boost::is_any_of(":")); + + SPDLOG_DEBUG( + "component {} avaliable options line: {} info size: {}", + component.first, line, info_split_list.size()); + + if (info_split_list.size() != 10) continue; + + auto configuration_name = info_split_list[0]; + boost::algorithm::trim(configuration_name); + { + // try lock + std::unique_lock lock(info_.Lock); + available_options_info[configuration_name] = { + info_split_list[1], info_split_list[2], info_split_list[3], + info_split_list[4], info_split_list[5], info_split_list[6], + info_split_list[7], info_split_list[8], info_split_list[9]}; + + boost::algorithm::trim( + available_options_info[configuration_name][0]); + boost::algorithm::trim( + available_options_info[configuration_name][1]); + boost::algorithm::trim( + available_options_info[configuration_name][2]); + boost::algorithm::trim( + available_options_info[configuration_name][3]); + boost::algorithm::trim( + available_options_info[configuration_name][4]); + boost::algorithm::trim( + available_options_info[configuration_name][5]); + boost::algorithm::trim( + available_options_info[configuration_name][6]); + boost::algorithm::trim( + available_options_info[configuration_name][7]); + boost::algorithm::trim( + available_options_info[configuration_name][8]); + } + } + }}); + } + + GpgCommandExecutor::GetInstance().ExecuteConcurrentlySync(exec_contexts); + + UpsertRTValue(GetModuleIdentifier(), "gnupg.gathering_done", true); + + return 0; +} + +bool GnuPGInfoGatheringModule::Deactive() { return true; } + +} // namespace GpgFrontend::Module::Integrated::GnuPGInfoGatheringModule diff --git a/src/module/integrated/gnupg_info_gathering_module/GnuPGInfoGatheringModule.h b/src/module/integrated/gnupg_info_gathering_module/GnuPGInfoGatheringModule.h new file mode 100644 index 00000000..2b83e636 --- /dev/null +++ b/src/module/integrated/gnupg_info_gathering_module/GnuPGInfoGatheringModule.h @@ -0,0 +1,57 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +#include <module/sdk/GpgFrontendModuleSDK.h> + +#include <memory> + +#include "GpgInfo.h" + +namespace GpgFrontend::Module::Integrated::GnuPGInfoGatheringModule { + +class GPGFRONTEND_MODULE_SDK_EXPORT GnuPGInfoGatheringModule : public Module { + Q_OBJECT + public: + GnuPGInfoGatheringModule(); + + ~GnuPGInfoGatheringModule(); + + virtual bool Register() override; + + virtual bool Active() override; + + virtual int Exec(EventRefrernce) override; + + virtual bool Deactive() override; + + private: + GpgInfo info_; +}; +} // namespace GpgFrontend::Module::Integrated::GnuPGInfoGatheringModule diff --git a/src/core/GpgInfo.cpp b/src/module/integrated/gnupg_info_gathering_module/GpgInfo.cpp index 960ed3e0..8d6fef74 100644 --- a/src/core/GpgInfo.cpp +++ b/src/module/integrated/gnupg_info_gathering_module/GpgInfo.cpp @@ -26,4 +26,6 @@ * */ -#include "core/GpgInfo.h" +#include "module/integrated/gnupg_info_gathering_module/GpgInfo.h" + +namespace GpgFrontend::Module::Integrated::GnuPGInfoGatheringModule {} diff --git a/src/core/GpgInfo.h b/src/module/integrated/gnupg_info_gathering_module/GpgInfo.h index 8c1a947c..8fddc0d5 100644 --- a/src/core/GpgInfo.h +++ b/src/module/integrated/gnupg_info_gathering_module/GpgInfo.h @@ -30,25 +30,13 @@ #include <shared_mutex> -namespace GpgFrontend { +namespace GpgFrontend::Module::Integrated::GnuPGInfoGatheringModule { /** * @brief Use to record some info about gnupg * */ class GpgInfo { public: - std::string GnupgVersion; ///< version of gnupg - std::string GpgMEVersion; ///< - - std::string AppPath; ///< executable binary path of gnupg - std::string DatabasePath; ///< key database path - std::string GpgConfPath; ///< executable binary path of gpgconf - std::string AssuanPath; ///< executable binary path of assuan - std::string CMSPath; ///< executable binary path of cms - std::string GpgAgentPath; ///< executable binary path of gpg-agent - std::string DirmngrPath; ///< executable binary path of dirmgr - std::string KeyboxdPath; ///< executable binary path of keyboxd - std::string GnuPGHomePath; ///< value of ---homedir std::map<std::string, std::vector<std::string>> ComponentsInfo; ///< @@ -58,4 +46,4 @@ class GpgInfo { std::shared_mutex Lock; }; -} // namespace GpgFrontend +} // namespace GpgFrontend::Module::Integrated::GnuPGInfoGatheringModule diff --git a/src/module/integrated/version_checking_module/CMakeLists.txt b/src/module/integrated/version_checking_module/CMakeLists.txt index ffe21c32..b6e3fb2c 100644 --- a/src/module/integrated/version_checking_module/CMakeLists.txt +++ b/src/module/integrated/version_checking_module/CMakeLists.txt @@ -23,6 +23,7 @@ # # SPDX-License-Identifier: GPL-3.0-or-later +# com.bktus.gpgfrontend.module.integrated.versionchecking aux_source_directory(. INTEGRATED_MODULE_SOURCE) diff --git a/src/module/integrated/version_checking_module/SoftwareVersion.cpp b/src/module/integrated/version_checking_module/SoftwareVersion.cpp index 23b50dae..56993fb8 100644 --- a/src/module/integrated/version_checking_module/SoftwareVersion.cpp +++ b/src/module/integrated/version_checking_module/SoftwareVersion.cpp @@ -28,63 +28,21 @@ #include "SoftwareVersion.h" -#include <boost/algorithm/string.hpp> -#include <boost/lexical_cast.hpp> +#include "core/GpgConstants.h" namespace GpgFrontend::Module::Integrated::VersionCheckingModule { -int VersionCheckingModule::SoftwareVersion::version_compare( - const std::string& a, const std::string& b) { - auto remove_prefix = [](const std::string& version) { - return version.front() == 'v' ? version.substr(1) : version; - }; - - std::string real_version_a = remove_prefix(a); - std::string real_version_b = remove_prefix(b); - - MODULE_LOG_DEBUG("real version a: {}", real_version_a); - MODULE_LOG_DEBUG("real version b: {}", real_version_b); - - std::vector<std::string> split_a, split_b; - boost::split(split_a, real_version_a, boost::is_any_of(".")); - boost::split(split_b, real_version_b, boost::is_any_of(".")); - - const int min_depth = std::min(split_a.size(), split_b.size()); - - for (int i = 0; i < min_depth; ++i) { - int num_a = 0, num_b = 0; - - try { - num_a = boost::lexical_cast<int>(split_a[i]); - num_b = boost::lexical_cast<int>(split_b[i]); - } catch (boost::bad_lexical_cast&) { - // Handle exception if needed - return 0; - } - - if (num_a != num_b) { - return (num_a > num_b) ? 1 : -1; - } - } - - if (split_a.size() != split_b.size()) { - return (split_a.size() > split_b.size()) ? 1 : -1; - } - - return 0; -} - bool VersionCheckingModule::SoftwareVersion::NeedUpgrade() const { MODULE_LOG_DEBUG("compair version current {} latest {}, result {}", current_version, latest_version, - version_compare(current_version, latest_version)); + software_version_compare(current_version, latest_version)); MODULE_LOG_DEBUG("load done: {}, pre-release: {}, draft: {}", loading_done, latest_prerelease_version_from_remote, latest_draft_from_remote); return loading_done && !latest_prerelease_version_from_remote && !latest_draft_from_remote && - version_compare(current_version, latest_version) < 0; + software_version_compare(current_version, latest_version) < 0; } bool VersionCheckingModule::SoftwareVersion::VersionWithdrawn() const { diff --git a/src/ui/GpgFrontendUIInit.cpp b/src/ui/GpgFrontendUIInit.cpp index c3bbbfd2..573baec1 100644 --- a/src/ui/GpgFrontendUIInit.cpp +++ b/src/ui/GpgFrontendUIInit.cpp @@ -134,7 +134,7 @@ void InitGpgFrontendUI(QApplication* app) { } // create the thread to load the gpg context - auto* init_ctx_task = new Thread::CtxCheckTask(); + auto* init_ctx_task = new Thread::CoreInitTask(); // create and show loading window before starting the main window auto* waiting_dialog = new QProgressDialog(); @@ -149,7 +149,7 @@ void InitGpgFrontendUI(QApplication* app) { waiting_dialog_label->setWordWrap(true); waiting_dialog->setLabel(waiting_dialog_label); waiting_dialog->resize(420, 120); - app->connect(init_ctx_task, &Thread::CtxCheckTask::SignalTaskEnd, + app->connect(init_ctx_task, &Thread::CoreInitTask::SignalTaskEnd, waiting_dialog, [=]() { SPDLOG_DEBUG("gpg context loaded"); waiting_dialog->finished(0); @@ -169,7 +169,7 @@ void InitGpgFrontendUI(QApplication* app) { // new local event looper QEventLoop looper; - app->connect(init_ctx_task, &Thread::CtxCheckTask::SignalTaskEnd, &looper, + app->connect(init_ctx_task, &Thread::CoreInitTask::SignalTaskEnd, &looper, &QEventLoop::quit); // start the thread to load the gpg context diff --git a/src/ui/UserInterfaceUtils.cpp b/src/ui/UserInterfaceUtils.cpp index 63a78873..5b92ffc0 100644 --- a/src/ui/UserInterfaceUtils.cpp +++ b/src/ui/UserInterfaceUtils.cpp @@ -40,12 +40,13 @@ #include "core/function/FileOperator.h" #include "core/function/GlobalSettingStation.h" #include "core/function/gpg/GpgKeyGetter.h" +#include "core/module/ModuleManager.h" #include "core/thread/Task.h" #include "core/thread/TaskRunner.h" #include "core/thread/TaskRunnerGetter.h" -#include "dialog/gnupg/GnuPGControllerDialog.h" #include "ui/SignalStation.h" #include "ui/dialog/WaitingDialog.h" +#include "ui/dialog/gnupg/GnuPGControllerDialog.h" #include "ui/struct/SettingsObject.h" #include "ui/widgets/TextEdit.h" @@ -325,8 +326,11 @@ void CommonUtils::SlotExecuteGpgCommand( _("Finished executing command.")); }); - gpg_process->setProgram( - GpgContext::GetInstance().GetInfo(false).AppPath.c_str()); + const auto app_path = Module::RetrieveRTValueTypedOrDefault<>( + "core", "gpgme.ctx.app_path", std::string{}); + SPDLOG_DEBUG("got gnupg app path from rt: {}", app_path); + + gpg_process->setProgram(app_path.c_str()); gpg_process->setArguments(arguments); gpg_process->start(); looper.exec(); diff --git a/src/ui/dialog/gnupg/GnuPGControllerDialog.cpp b/src/ui/dialog/gnupg/GnuPGControllerDialog.cpp index f80b6c7a..b13049ba 100644 --- a/src/ui/dialog/gnupg/GnuPGControllerDialog.cpp +++ b/src/ui/dialog/gnupg/GnuPGControllerDialog.cpp @@ -30,6 +30,8 @@ #include "SignalStation.h" #include "core/function/GlobalSettingStation.h" +#include "core/module/ModuleManager.h" +#include "spdlog/spdlog.h" #include "ui/dialog/GeneralDialog.h" #include "ui_GnuPGControllerDialog.h" @@ -204,9 +206,13 @@ void GnuPGControllerDialog::slot_update_custom_key_database_path_label( // announce the restart this->slot_set_restart_needed(DEEP_RESTART_CODE); + const auto database_path = Module::RetrieveRTValueTypedOrDefault<>( + "core", "gpgme.ctx.database_path", std::string{}); + SPDLOG_DEBUG("got gpgme.ctx.database_path from rt: {}", database_path); + if (state != Qt::CheckState::Checked) { - ui_->currentKeyDatabasePathLabel->setText(QString::fromStdString( - GpgContext::GetInstance().GetInfo(false).DatabasePath)); + ui_->currentKeyDatabasePathLabel->setText( + QString::fromStdString(database_path)); // hide label (not necessary to show the default path) this->ui_->currentKeyDatabasePathLabel->setHidden(true); @@ -238,9 +244,15 @@ void GnuPGControllerDialog::slot_update_custom_gnupg_install_path_label( // announce the restart this->slot_set_restart_needed(DEEP_RESTART_CODE); + const auto home_path = Module::RetrieveRTValueTypedOrDefault<>( + Module::GetRealModuleIdentifier( + "com.bktus.gpgfrontend.module.integrated.gnupginfogathering"), + "gnupg.home_path", std::string{}); + SPDLOG_DEBUG("got gnupg home path from rt: {}", home_path); + if (state != Qt::CheckState::Checked) { - ui_->currentCustomGnuPGInstallPathLabel->setText(QString::fromStdString( - GpgContext::GetInstance().GetInfo(false).GnuPGHomePath)); + ui_->currentCustomGnuPGInstallPathLabel->setText( + QString::fromStdString(home_path)); // hide label (not necessary to show the default path) this->ui_->currentCustomGnuPGInstallPathLabel->setHidden(true); diff --git a/src/ui/dialog/help/AboutDialog.cpp b/src/ui/dialog/help/AboutDialog.cpp index 9948f1fc..ae708e46 100644 --- a/src/ui/dialog/help/AboutDialog.cpp +++ b/src/ui/dialog/help/AboutDialog.cpp @@ -80,6 +80,10 @@ AboutDialog::AboutDialog(int defaultIndex, QWidget* parent) void AboutDialog::showEvent(QShowEvent* ev) { QDialog::showEvent(ev); } InfoTab::InfoTab(QWidget* parent) : QWidget(parent) { + const auto gpgme_version = Module::RetrieveRTValueTypedOrDefault<>( + "core", "gpgme.version", std::string{"2.0.0"}); + SPDLOG_DEBUG("got gpgme version from rt: {}", gpgme_version); + auto* pixmap = new QPixmap(":gpgfrontend-logo.png"); auto* text = new QString( "<center><h2>" + qApp->applicationName() + "</h2></center>" + @@ -98,11 +102,8 @@ InfoTab::InfoTab(QWidget* parent) : QWidget(parent) { _("or send a mail to my mailing list at") + " <a " + "href=\"mailto:[email protected]\">[email protected]</a>." + "<br><br> " + _("Built with Qt") + " " + qVersion() + ", " + OPENSSL_VERSION_TEXT + - " " + _("and") + " " + "GPGME" + " " + - GpgFrontend::GpgContext::GetInstance() - .GetInfo(false) - .GpgMEVersion.c_str() + - "<br>" + _("Built at") + " " + BUILD_TIMESTAMP + "</center>"); + " " + _("and") + " " + "GPGME" + " " + gpgme_version.c_str() + "<br>" + + _("Built at") + " " + BUILD_TIMESTAMP + "</center>"); auto* layout = new QGridLayout(); auto* pixmapLabel = new QLabel(); @@ -214,6 +215,17 @@ void UpdateTab::showEvent(QShowEvent* event) { "version.loading_done", false); if (!is_loading_done) { + Module::ListenRTPublishEvent( + this, + Module::GetRealModuleIdentifier( + "com.bktus.gpgfrontend.module.integrated.versionchecking"), + "version.loading_done", + [=](Module::Namespace, Module::Key, int, std::any) { + SPDLOG_DEBUG( + "versionchecking version.loading_done changed, calling slot " + "version upgrade"); + this->slot_show_version_status(); + }); Module::TriggerEvent("CHECK_APPLICATION_VERSION"); } else { slot_show_version_status(); @@ -222,6 +234,7 @@ void UpdateTab::showEvent(QShowEvent* event) { void UpdateTab::slot_show_version_status() { SPDLOG_DEBUG("loading version info from rt"); + this->pb_->setHidden(true); auto is_loading_done = Module::RetrieveRTValueTypedOrDefault<>( Module::GetRealModuleIdentifier( @@ -230,10 +243,7 @@ void UpdateTab::slot_show_version_status() { if (!is_loading_done) { SPDLOG_DEBUG("version info loading havn't been done yet."); - this->pb_->setHidden(false); return; - } else { - this->pb_->setHidden(true); } auto is_need_upgrade = Module::RetrieveRTValueTypedOrDefault<>( diff --git a/src/ui/dialog/help/GnupgTab.cpp b/src/ui/dialog/help/GnupgTab.cpp index 639157bd..4780dbf1 100644 --- a/src/ui/dialog/help/GnupgTab.cpp +++ b/src/ui/dialog/help/GnupgTab.cpp @@ -34,6 +34,7 @@ #include <shared_mutex> +#include "core/module/ModuleManager.h" #include "ui/UserInterfaceUtils.h" #include "ui_GnuPGInfo.h" @@ -80,59 +81,66 @@ GpgFrontend::UI::GnupgTab::GnupgTab(QWidget* parent) } void GpgFrontend::UI::GnupgTab::process_software_info() { - auto& ctx_info = GpgContext::GetInstance().GetInfo(); + const auto gnupg_version = Module::RetrieveRTValueTypedOrDefault<>( + "core", "gpgme.ctx.gnupg_version", std::string{"2.0.0"}); + SPDLOG_DEBUG("got gnupg version from rt: {}", gnupg_version); - ui_->gnupgVersionLabel->setText(QString::fromStdString( - fmt::format("Version: {}", ctx_info.GnupgVersion))); + ui_->gnupgVersionLabel->setText( + QString::fromStdString(fmt::format("Version: {}", gnupg_version))); - ui_->componentDetailsTable->setRowCount(ctx_info.ComponentsInfo.size()); + // ui_->componentDetailsTable->setRowCount(ctx_info.ComponentsInfo.size()); - int row = 0; - for (const auto& info : ctx_info.ComponentsInfo) { - if (info.second.size() != 4) continue; + // int row = 0; + // for (const auto& info : ctx_info.ComponentsInfo) { + // if (info.second.size() != 4) continue; - auto* tmp0 = new QTableWidgetItem(QString::fromStdString(info.first)); - tmp0->setTextAlignment(Qt::AlignCenter); - ui_->componentDetailsTable->setItem(row, 0, tmp0); + // auto* tmp0 = new QTableWidgetItem(QString::fromStdString(info.first)); + // tmp0->setTextAlignment(Qt::AlignCenter); + // ui_->componentDetailsTable->setItem(row, 0, tmp0); - auto* tmp1 = new QTableWidgetItem(QString::fromStdString(info.second[0])); - tmp1->setTextAlignment(Qt::AlignCenter); - ui_->componentDetailsTable->setItem(row, 1, tmp1); + // auto* tmp1 = new + // QTableWidgetItem(QString::fromStdString(info.second[0])); + // tmp1->setTextAlignment(Qt::AlignCenter); + // ui_->componentDetailsTable->setItem(row, 1, tmp1); - auto* tmp2 = new QTableWidgetItem(QString::fromStdString(info.second[1])); - tmp2->setTextAlignment(Qt::AlignCenter); - ui_->componentDetailsTable->setItem(row, 2, tmp2); + // auto* tmp2 = new + // QTableWidgetItem(QString::fromStdString(info.second[1])); + // tmp2->setTextAlignment(Qt::AlignCenter); + // ui_->componentDetailsTable->setItem(row, 2, tmp2); - auto* tmp3 = new QTableWidgetItem(QString::fromStdString(info.second[3])); - tmp3->setTextAlignment(Qt::AlignCenter); - ui_->componentDetailsTable->setItem(row, 3, tmp3); + // auto* tmp3 = new + // QTableWidgetItem(QString::fromStdString(info.second[3])); + // tmp3->setTextAlignment(Qt::AlignCenter); + // ui_->componentDetailsTable->setItem(row, 3, tmp3); - auto* tmp4 = new QTableWidgetItem(QString::fromStdString(info.second[2])); - tmp4->setTextAlignment(Qt::AlignLeft); - ui_->componentDetailsTable->setItem(row, 4, tmp4); + // auto* tmp4 = new + // QTableWidgetItem(QString::fromStdString(info.second[2])); + // tmp4->setTextAlignment(Qt::AlignLeft); + // ui_->componentDetailsTable->setItem(row, 4, tmp4); - row++; - } + // row++; + // } - ui_->componentDetailsTable->resizeColumnsToContents(); + // ui_->componentDetailsTable->resizeColumnsToContents(); - ui_->configurationDetailsTable->setRowCount( - ctx_info.ConfigurationsInfo.size()); + // ui_->configurationDetailsTable->setRowCount( + // ctx_info.ConfigurationsInfo.size()); - row = 0; - for (const auto& info : ctx_info.ConfigurationsInfo) { - if (info.second.size() != 1) continue; + // row = 0; + // for (const auto& info : ctx_info.ConfigurationsInfo) { + // if (info.second.size() != 1) continue; - auto* tmp0 = new QTableWidgetItem(QString::fromStdString(info.first)); - tmp0->setTextAlignment(Qt::AlignCenter); - ui_->configurationDetailsTable->setItem(row, 0, tmp0); + // auto* tmp0 = new QTableWidgetItem(QString::fromStdString(info.first)); + // tmp0->setTextAlignment(Qt::AlignCenter); + // ui_->configurationDetailsTable->setItem(row, 0, tmp0); - auto* tmp1 = new QTableWidgetItem(QString::fromStdString(info.second[0])); - tmp1->setTextAlignment(Qt::AlignCenter); - ui_->configurationDetailsTable->setItem(row, 1, tmp1); + // auto* tmp1 = new + // QTableWidgetItem(QString::fromStdString(info.second[0])); + // tmp1->setTextAlignment(Qt::AlignCenter); + // ui_->configurationDetailsTable->setItem(row, 1, tmp1); - row++; - } + // row++; + // } - ui_->configurationDetailsTable->resizeColumnsToContents(); + // ui_->configurationDetailsTable->resizeColumnsToContents(); } diff --git a/src/ui/main_window/MainWindow.cpp b/src/ui/main_window/MainWindow.cpp index fdad9ad1..46d72361 100644 --- a/src/ui/main_window/MainWindow.cpp +++ b/src/ui/main_window/MainWindow.cpp @@ -136,7 +136,8 @@ void MainWindow::Init() noexcept { this, Module::GetRealModuleIdentifier( "com.bktus.gpgfrontend.module.integrated.versionchecking"), - "version.loading_done", [=](Module::Namespace, Module::Key, int) { + "version.loading_done", + [=](Module::Namespace, Module::Key, int, std::any) { SPDLOG_DEBUG( "versionchecking version.loading_done changed, calling slot " "version upgrade"); diff --git a/src/ui/main_window/MainWindowUI.cpp b/src/ui/main_window/MainWindowUI.cpp index f18a7c7b..93bbd088 100644 --- a/src/ui/main_window/MainWindowUI.cpp +++ b/src/ui/main_window/MainWindowUI.cpp @@ -26,9 +26,12 @@ * */ +#include <any> + #include "MainWindow.h" #include "core/function/GlobalSettingStation.h" #include "core/function/gpg/GpgAdvancedOperator.h" +#include "core/module/ModuleManager.h" #include "ui/UserInterfaceUtils.h" #include "ui/dialog/gnupg/GnuPGControllerDialog.h" #include "ui/dialog/help/AboutDialog.h" @@ -313,16 +316,21 @@ void MainWindow::create_actions() { restart_components_act_->setIcon(QIcon(":configure.png")); restart_components_act_->setToolTip(_("Restart All GnuPG's Components")); connect(restart_components_act_, &QAction::triggered, this, [=]() { - if (GpgFrontend::GpgAdvancedOperator::GetInstance() - .RestartGpgComponents()) { - QMessageBox::information( - this, _("Successful Operation"), - _("Restart all the GnuPG's components successfully")); - } else { - QMessageBox::critical( - this, _("Failed Operation"), - _("Failed to restart all or one of the GnuPG's component(s)")); - } + GpgFrontend::GpgAdvancedOperator::GetInstance().RestartGpgComponents(); + Module::ListenRTPublishEvent( + this, "core", "gpg_advanced_operator.restart_gpg_components", + [=](Module::Namespace, Module::Key, int, std::any value) { + bool success_state = std::any_cast<bool>(value); + if (success_state) { + QMessageBox::information( + this, _("Successful Operation"), + _("Restart all the GnuPG's components successfully")); + } else { + QMessageBox::critical( + this, _("Failed Operation"), + _("Failed to restart all or one of the GnuPG's component(s)")); + } + }); }); gnupg_controller_open_act_ = new QAction(_("Open GnuPG Controller"), this); |