aboutsummaryrefslogtreecommitdiffstats
path: root/src/core/GpgCoreInit.cpp
diff options
context:
space:
mode:
authorsaturneric <[email protected]>2023-12-03 20:25:21 +0000
committersaturneric <[email protected]>2023-12-03 20:25:21 +0000
commit054e6e28cca2517dda2319ef683314b3318c39a6 (patch)
treeae9ff4a9fe280f3640ca249bad45ab250cfd1610 /src/core/GpgCoreInit.cpp
parentfix: slove issues in key/subkey generation (diff)
downloadGpgFrontend-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.cpp372
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