diff options
author | saturneric <[email protected]> | 2023-12-03 20:25:21 +0000 |
---|---|---|
committer | saturneric <[email protected]> | 2023-12-03 20:25:21 +0000 |
commit | 054e6e28cca2517dda2319ef683314b3318c39a6 (patch) | |
tree | ae9ff4a9fe280f3640ca249bad45ab250cfd1610 /src/core/GpgCoreInit.cpp | |
parent | fix: slove issues in key/subkey generation (diff) | |
download | GpgFrontend-054e6e28cca2517dda2319ef683314b3318c39a6.tar.gz GpgFrontend-054e6e28cca2517dda2319ef683314b3318c39a6.zip |
feat: standarized and speed up app env loading process
Diffstat (limited to 'src/core/GpgCoreInit.cpp')
-rw-r--r-- | src/core/GpgCoreInit.cpp | 372 |
1 files changed, 249 insertions, 123 deletions
diff --git a/src/core/GpgCoreInit.cpp b/src/core/GpgCoreInit.cpp index 09b3a0ec..dcd0dcfb 100644 --- a/src/core/GpgCoreInit.cpp +++ b/src/core/GpgCoreInit.cpp @@ -27,6 +27,7 @@ */ #include "GpgCoreInit.h" +#include <gpgme.h> #include <spdlog/async.h> #include <spdlog/common.h> #include <spdlog/sinks/rotating_file_sink.h> @@ -35,15 +36,19 @@ #include <boost/date_time.hpp> #include "core/function/GlobalSettingStation.h" +#include "core/function/basic/ChannelObject.h" +#include "core/function/basic/SingletonStorage.h" #include "core/function/gpg/GpgAdvancedOperator.h" #include "core/function/gpg/GpgContext.h" #include "core/module/ModuleManager.h" #include "core/thread/Task.h" #include "core/thread/TaskRunner.h" #include "core/thread/TaskRunnerGetter.h" +#include "core/utils/CommonUtils.h" +#include "core/utils/GpgUtils.h" #include "core/utils/MemoryUtils.h" -#include "function/basic/ChannelObject.h" -#include "function/basic/SingletonStorage.h" +#include "function/CoreSignalStation.h" +#include "function/gpg/GpgKeyGetter.h" namespace GpgFrontend { @@ -99,123 +104,206 @@ void ShutdownCoreLoggingSystem() { #endif } -void ResetGpgFrontendCore() { reset_gpgfrontend_core(); } +void DestroyGpgFrontendCore() { + SingletonStorageCollection::Destroy(); + ShutdownCoreLoggingSystem(); +} + +auto InitGpgME() -> bool { + // init gpgme subsystem and get gpgme library version + Module::UpsertRTValue("core", "gpgme.version", + std::string(gpgme_check_version(nullptr))); -void InitGpgFrontendCore() { - /* Initialize the locale environment. */ - SPDLOG_DEBUG("locale: {}", setlocale(LC_CTYPE, nullptr)); - // init gpgme subsystem - gpgme_check_version(nullptr); gpgme_set_locale(nullptr, LC_CTYPE, setlocale(LC_CTYPE, nullptr)); #ifdef LC_MESSAGES gpgme_set_locale(nullptr, LC_MESSAGES, setlocale(LC_MESSAGES, nullptr)); #endif - // read settings - bool forbid_all_gnupg_connection = - GlobalSettingStation::GetInstance().LookupSettings( - "network.forbid_all_gnupg_connection", false); - - bool auto_import_missing_key = - GlobalSettingStation::GetInstance().LookupSettings( - "network.auto_import_missing_key", false); - - bool use_custom_key_database_path = - GlobalSettingStation::GetInstance().LookupSettings( - "general.use_custom_key_database_path", false); + gpgme_ctx_t p_ctx; + + CheckGpgError(gpgme_new(&p_ctx)); + + // get engine info + auto* engine_info = gpgme_ctx_get_engine_info(p_ctx); + // Check ENV before running + bool find_openpgp = false; + bool find_gpgconf = false; + bool find_cms = false; + + while (engine_info != nullptr) { + if (strcmp(engine_info->version, "1.0.0") == 0) { + engine_info = engine_info->next; + continue; + } + + SPDLOG_DEBUG( + "gpg context engine info: {} {} {} {}", + gpgme_get_protocol_name(engine_info->protocol), + std::string(engine_info->file_name == nullptr ? "null" + : engine_info->file_name), + std::string(engine_info->home_dir == nullptr ? "null" + : engine_info->home_dir), + std::string(engine_info->version ? "null" : engine_info->version)); + + switch (engine_info->protocol) { + case GPGME_PROTOCOL_OpenPGP: + find_openpgp = true; + + Module::UpsertRTValue("core", "gpgme.engine.openpgp", "1"); + 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; + Module::UpsertRTValue("core", "gpgme.engine.cms", "1"); + Module::UpsertRTValue("core", "gpgme.ctx.cms_path", + std::string(engine_info->file_name)); + + break; + case GPGME_PROTOCOL_GPGCONF: + find_gpgconf = true; + + Module::UpsertRTValue("core", "gpgme.engine.gpgconf", "1"); + Module::UpsertRTValue("core", "gpgme.ctx.gpgconf_path", + std::string(engine_info->file_name)); + break; + case GPGME_PROTOCOL_ASSUAN: + + Module::UpsertRTValue("core", "gpgme.engine.assuan", "1"); + Module::UpsertRTValue("core", "gpgme.ctx.assuan_path", + std::string(engine_info->file_name)); + break; + case GPGME_PROTOCOL_G13: + break; + case GPGME_PROTOCOL_UISERVER: + break; + case GPGME_PROTOCOL_SPAWN: + break; + case GPGME_PROTOCOL_DEFAULT: + break; + case GPGME_PROTOCOL_UNKNOWN: + break; + } + engine_info = engine_info->next; + } - std::string custom_key_database_path = - GlobalSettingStation::GetInstance().LookupSettings( - "general.custom_key_database_path", std::string{}); + 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); - bool use_custom_gnupg_install_path = - GlobalSettingStation::GetInstance().LookupSettings( - "general.use_custom_gnupg_install_path", false); + // conditional check: only support gpg 2.1.x now + if (!(CompareSoftwareVersion(gnupg_version, "2.1.0") >= 0 && find_gpgconf && + find_openpgp && find_cms)) { + SPDLOG_ERROR("gpgme env check failed, abort"); + return false; + } - std::string custom_gnupg_install_path = - GlobalSettingStation::GetInstance().LookupSettings( - "general.custom_gnupg_install_path", std::string{}); + Module::UpsertRTValue("core", "env.state.gpgme", std::string{"1"}); + return true; +} - bool use_pinentry_as_password_input_dialog = - GpgFrontend::GlobalSettingStation::GetInstance().LookupSettings( - "general.use_pinentry_as_password_input_dialog", false); +void InitGpgFrontendCore() { + // initialize global register table + Module::UpsertRTValue("core", "env.state.gpgme", std::string{"0"}); + Module::UpsertRTValue("core", "env.state.ctx", std::string{"0"}); + Module::UpsertRTValue("core", "env.state.gnupg", std::string{"0"}); + Module::UpsertRTValue("core", "env.state.basic", std::string{"0"}); + Module::UpsertRTValue("core", "env.state.all", std::string{"0"}); + + // initialize locale environment + SPDLOG_DEBUG("locale: {}", setlocale(LC_CTYPE, nullptr)); - SPDLOG_DEBUG("core loaded if use custom key databse path: {}", - use_custom_key_database_path); - SPDLOG_DEBUG("core loaded custom key databse path: {}", - custom_key_database_path); + // initialize library gpgme + if (!InitGpgME()) { + CoreSignalStation::GetInstance()->SignalBadGnupgEnv(); + return; + } - // check gpgconf path - std::filesystem::path custom_gnupg_install_fs_path = - custom_gnupg_install_path; + // start the thread to check ctx and gnupg state + // it may take a few seconds or minutes + GpgFrontend::Thread::TaskRunnerGetter::GetInstance() + .GetTaskRunner() + ->PostTask(new Thread::Task( + [](const DataObjectPtr&) -> int { + // read settings from config file + auto forbid_all_gnupg_connection = + GlobalSettingStation::GetInstance().LookupSettings( + "network.forbid_all_gnupg_connection", false); + + auto auto_import_missing_key = + GlobalSettingStation::GetInstance().LookupSettings( + "network.auto_import_missing_key", false); + + auto use_custom_key_database_path = + GlobalSettingStation::GetInstance().LookupSettings( + "general.use_custom_key_database_path", false); + + auto custom_key_database_path = + GlobalSettingStation::GetInstance().LookupSettings( + "general.custom_key_database_path", std::string{}); + + auto use_custom_gnupg_install_path = + GlobalSettingStation::GetInstance().LookupSettings( + "general.use_custom_gnupg_install_path", false); + + auto custom_gnupg_install_path = + GlobalSettingStation::GetInstance().LookupSettings( + "general.custom_gnupg_install_path", std::string{}); + + auto use_pinentry_as_password_input_dialog = + GpgFrontend::GlobalSettingStation::GetInstance().LookupSettings( + "general.use_pinentry_as_password_input_dialog", false); + + SPDLOG_DEBUG("core loaded if use custom key databse path: {}", + use_custom_key_database_path); + SPDLOG_DEBUG("core loaded custom key databse path: {}", + custom_key_database_path); + + // check gpgconf path + std::filesystem::path custom_gnupg_install_fs_path = + custom_gnupg_install_path; #ifdef WINDOWS - custom_gnupg_install_fs_path /= "gpgconf.exe"; + custom_gnupg_install_fs_path /= "gpgconf.exe"; #else - custom_gnupg_install_fs_path /= "gpgconf"; + custom_gnupg_install_fs_path /= "gpgconf"; #endif - if (!custom_gnupg_install_fs_path.is_absolute() || - !std::filesystem::exists(custom_gnupg_install_fs_path) || - !std::filesystem::is_regular_file(custom_gnupg_install_fs_path)) { - use_custom_gnupg_install_path = false; - SPDLOG_ERROR("core loaded custom gpgconf path is illegal: {}", - custom_gnupg_install_fs_path.u8string()); - } else { - SPDLOG_DEBUG("core loaded custom gpgconf path: {}", - custom_gnupg_install_fs_path.u8string()); - } - - // check key database path - std::filesystem::path custom_key_database_fs_path = custom_key_database_path; - if (!custom_key_database_fs_path.is_absolute() || - !std::filesystem::exists(custom_key_database_fs_path) || - !std::filesystem::is_directory(custom_key_database_fs_path)) { - use_custom_key_database_path = false; - SPDLOG_ERROR("core loaded custom gpg key database is illegal: {}", - custom_key_database_fs_path.u8string()); - } else { - SPDLOG_DEBUG("core loaded custom gpg key database path: {}", - custom_key_database_fs_path.u8string()); - } - - // init default channel - auto& default_ctx = GpgFrontend::GpgContext::CreateInstance( - kGpgfrontendDefaultChannel, [=]() -> ChannelObjectPtr { - GpgFrontend::GpgContextInitArgs args; - - // set key database path - if (use_custom_key_database_path && !custom_key_database_path.empty()) { - args.db_path = custom_key_database_path; - } - - if (use_custom_gnupg_install_path) { - args.custom_gpgconf = true; - args.custom_gpgconf_path = custom_gnupg_install_fs_path.u8string(); - } - - args.offline_mode = forbid_all_gnupg_connection; - args.auto_import_missing_key = auto_import_missing_key; - args.use_pinentry = use_pinentry_as_password_input_dialog; - - return ConvertToChannelObjectPtr<>(SecureCreateUniqueObject<GpgContext>( - args, kGpgFrontendDefaultChannel)); - }); - - // exit if failed - if (!default_ctx.Good()) { - SPDLOG_ERROR("default gnupg context init error"); - }; - - // async init no-ascii(binary output) channel - Thread::TaskRunnerGetter::GetInstance() - .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_GPG) - ->PostTask(new Thread::Task( - [=](const DataObjectPtr& /*data_obj*/) -> int { - // init non-ascii channel + if (!custom_gnupg_install_fs_path.is_absolute() || + !std::filesystem::exists(custom_gnupg_install_fs_path) || + !std::filesystem::is_regular_file( + custom_gnupg_install_fs_path)) { + use_custom_gnupg_install_path = false; + SPDLOG_ERROR("core loaded custom gpgconf path is illegal: {}", + custom_gnupg_install_fs_path.u8string()); + } else { + SPDLOG_DEBUG("core loaded custom gpgconf path: {}", + custom_gnupg_install_fs_path.u8string()); + } + + // check key database path + std::filesystem::path custom_key_database_fs_path = + custom_key_database_path; + if (!custom_key_database_fs_path.is_absolute() || + !std::filesystem::exists(custom_key_database_fs_path) || + !std::filesystem::is_directory(custom_key_database_fs_path)) { + use_custom_key_database_path = false; + SPDLOG_ERROR("core loaded custom gpg key database is illegal: {}", + custom_key_database_fs_path.u8string()); + } else { + SPDLOG_DEBUG("core loaded custom gpg key database path: {}", + custom_key_database_fs_path.u8string()); + } + + // init ctx, also checking the basical env auto& ctx = GpgFrontend::GpgContext::CreateInstance( - kGpgfrontendNonAsciiChannel, [=]() -> ChannelObjectPtr { + kGpgfrontendDefaultChannel, [=]() -> ChannelObjectPtr { GpgFrontend::GpgContextInitArgs args; - args.ascii = false; // set key database path if (use_custom_key_database_path && @@ -223,6 +311,7 @@ void InitGpgFrontendCore() { args.db_path = custom_key_database_path; } + // set custom gnupg path if (use_custom_gnupg_install_path) { args.custom_gpgconf = true; args.custom_gpgconf_path = @@ -235,31 +324,68 @@ void InitGpgFrontendCore() { return ConvertToChannelObjectPtr<>( SecureCreateUniqueObject<GpgContext>( - args, kGpgfrontendNonAsciiChannel)); + args, kGpgFrontendDefaultChannel)); }); - if (!ctx.Good()) SPDLOG_ERROR("no-ascii channel init error"); - return ctx.Good() ? 0 : -1; + // exit if failed + if (!ctx.Good()) { + SPDLOG_ERROR("default gnupg context init error, abort"); + CoreSignalStation::GetInstance()->SignalBadGnupgEnv(); + return -1; + } + Module::UpsertRTValue("core", "env.state.ctx", std::string{"1"}); + + // if gnupg-info-gathering module activated + if (Module::IsModuleAcivate("com.bktus.gpgfrontend.module." + "integrated.gnupg-info-gathering")) { + SPDLOG_DEBUG("gnupg-info-gathering is activated"); + + // gather external gnupg info + Module::TriggerEvent( + "GPGFRONTEND_CORE_INITLIZED", + [](const Module::EventIdentifier& /*e*/, + const Module::Event::ListenerIdentifier& l_id, + DataObjectPtr o) { + SPDLOG_DEBUG( + "received event GPGFRONTEND_CORE_INITLIZED callback " + "from module: {}", + l_id); + + if (l_id == + "com.bktus.gpgfrontend.module.integrated.gnupg-info-" + "gathering") { + SPDLOG_DEBUG( + "received callback from gnupg-info-gathering "); + + // try to restart all components + GpgFrontend::GpgAdvancedOperator::RestartGpgComponents(); + Module::UpsertRTValue("core", "env.state.gnupg", + std::string{"1"}); + + // announce that all checkings were finished + SPDLOG_INFO( + "all env checking finished, including gpgme, " + "ctx and " + "gnupg"); + Module::UpsertRTValue("core", "env.state.all", + std::string{"1"}); + } + }); + } else { + SPDLOG_DEBUG("gnupg-info-gathering is not activated"); + Module::UpsertRTValue("core", "env.state.all", std::string{"1"}); + } + + GpgKeyGetter::GetInstance().FlushKeyCache(); + SPDLOG_INFO( + "basic env checking finished, including gpgme, ctx, and key " + "infos"); + Module::UpsertRTValue("core", "env.state.basic", std::string{"1"}); + CoreSignalStation::GetInstance()->SignalGoodGnupgEnv(); + + return 0; }, - "default_channel_ctx_init")); - - Module::TriggerEvent( - "GPGFRONTEND_CORE_INITLIZED", - [](const Module::EventIdentifier& /*e*/, - const Module::Event::ListenerIdentifier& l_id, DataObjectPtr o) { - if (l_id == - "com.bktus.gpgfrontend.module.integrated." - "gnupginfogathering") { - SPDLOG_DEBUG( - "gnupg-info-gathering gnupg.gathering_done changed, restarting " - "gpg " - "components"); - // try to restart all components - GpgFrontend::GpgAdvancedOperator::RestartGpgComponents(); - } - }); + "core_init_task")); } -void reset_gpgfrontend_core() { SingletonStorageCollection::GetInstance(true); } - } // namespace GpgFrontend
\ No newline at end of file |