aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorsaturneric <[email protected]>2024-07-31 06:13:26 +0000
committersaturneric <[email protected]>2024-07-31 06:13:26 +0000
commit081147d65fcb0a20818bbfb43f6ec4f5ddf59581 (patch)
treef6ec05666acb98da46b4cb0dfc0871225f4ad388 /src
parentfix: dealing with unknown compiler (diff)
downloadGpgFrontend-081147d65fcb0a20818bbfb43f6ec4f5ddf59581.tar.gz
GpgFrontend-081147d65fcb0a20818bbfb43f6ec4f5ddf59581.zip
fix: addressing some of the significant deficiencies identified
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt11
-rw-r--r--src/app.cpp10
-rw-r--r--src/core/GpgCoreInit.cpp106
-rw-r--r--src/core/GpgCoreInit.h5
-rw-r--r--src/core/GpgFrontendCore.h11
-rw-r--r--src/core/function/CoreSignalStation.h6
-rw-r--r--src/core/function/SecureMemoryAllocator.cpp4
-rw-r--r--src/core/function/gpg/GpgContext.cpp11
-rw-r--r--src/core/function/gpg/GpgKeyOpera.cpp4
-rw-r--r--src/core/model/GpgGenKeyInfo.cpp152
-rw-r--r--src/core/module/Event.cpp9
-rw-r--r--src/core/module/GlobalModuleContext.cpp48
-rw-r--r--src/core/module/GlobalModuleContext.h2
-rw-r--r--src/core/module/Module.cpp11
-rw-r--r--src/core/module/ModuleInit.cpp60
-rw-r--r--src/core/module/ModuleManager.cpp166
-rw-r--r--src/core/module/ModuleManager.h14
-rw-r--r--src/core/utils/CommonUtils.cpp29
-rw-r--r--src/core/utils/CommonUtils.h4
-rw-r--r--src/init.cpp3
-rw-r--r--src/sdk/GFSDKBasic.cpp15
-rw-r--r--src/sdk/GFSDKBasic.h6
-rw-r--r--src/test/GpgFrontendTest.h12
-rw-r--r--src/ui/GpgFrontendUI.h13
-rw-r--r--src/ui/GpgFrontendUIInit.cpp41
-rw-r--r--src/ui/GpgFrontendUIInit.h9
-rw-r--r--src/ui/UIModuleManager.cpp81
-rw-r--r--src/ui/UIModuleManager.h29
-rw-r--r--src/ui/dialog/keypair_details/KeyPairDetailTab.cpp2
-rw-r--r--src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp17
30 files changed, 659 insertions, 232 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index ddbc0fae..08b6e3a1 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -569,6 +569,12 @@ endif()
# if only build sdk
if(STABLE_BUILD_ONLY_SDK)
include(GNUInstallDirs)
+
+ if(INSTALL_TO_MODULES_REPO)
+ set(CMAKE_INSTALL_PREFIX "${CMAKE_SOURCE_DIR}/modules/sdk/${CMAKE_PROJECT_VERSION}")
+ message(STATUS "Set CMake Install Prefix for Cooperation: ${CMAKE_INSTALL_PREFIX}")
+ endif()
+
set(GPGFRONTEND_SDK_INSTALL_LIBRARIES
gpgfrontend_module_sdk)
@@ -584,6 +590,11 @@ endif()
if(STABLE_BUILD_FULL_SDK)
include(GNUInstallDirs)
+ if(INSTALL_TO_MODULES_REPO)
+ set(CMAKE_INSTALL_PREFIX "${CMAKE_SOURCE_DIR}/modules/sdk/${CMAKE_PROJECT_VERSION}")
+ message(STATUS "Set CMake Install Prefix for Cooperation: ${CMAKE_INSTALL_PREFIX}")
+ endif()
+
set(GPGFRONTEND_SDK_INSTALL_LIBRARIES
gpgfrontend_core
gpgfrontend_ui
diff --git a/src/app.cpp b/src/app.cpp
index aac9e2cc..0ba65117 100644
--- a/src/app.cpp
+++ b/src/app.cpp
@@ -73,13 +73,17 @@ auto StartApplication(const GFCxtWPtr& p_ctx) -> int {
// after that load ui totally
GpgFrontend::UI::InitGpgFrontendUI(app);
+ // check and waiting for condition
+ GpgFrontend::UI::WaitingAllInitializationFinished();
+
+ // load module's translations
+ GpgFrontend::UI::InitModulesTranslations();
+
// finally create main window
return_from_event_loop_code = GpgFrontend::UI::RunGpgFrontendUI(app);
- restart_count++;
-
} while (return_from_event_loop_code == GpgFrontend::kRestartCode &&
- restart_count < 99);
+ restart_count++ < 99);
// first should shutdown the module system
GpgFrontend::Module::ShutdownGpgFrontendModules();
diff --git a/src/core/GpgCoreInit.cpp b/src/core/GpgCoreInit.cpp
index 1a00049c..3f738835 100644
--- a/src/core/GpgCoreInit.cpp
+++ b/src/core/GpgCoreInit.cpp
@@ -289,36 +289,36 @@ void InitGpgFrontendCore(CoreInitArgs args) {
return;
}
- auto* task = new Thread::Task(
- [args, gnupg_install_fs_path](const DataObjectPtr&) -> int {
- auto settings = GlobalSettingStation::GetInstance().GetSettings();
- // read settings from config file
- auto forbid_all_gnupg_connection =
- settings.value("network/forbid_all_gnupg_connection", false)
- .toBool();
-
- auto auto_import_missing_key =
- settings.value("network/auto_import_missing_key", false).toBool();
-
- auto use_custom_key_database_path =
- settings.value("gnupg/use_custom_key_database_path", false)
- .toBool();
-
- auto custom_key_database_path =
- settings.value("gnupg/custom_key_database_path", QString{})
- .toString();
-
- auto custom_gnupg_install_path =
- settings.value("gnupg/custom_gnupg_install_path", QString{})
- .toString();
-
- auto use_pinentry_as_password_input_dialog =
- settings
- .value(
- "gnupg/use_pinentry_as_password_input_dialog",
- QString::fromLocal8Bit(qgetenv("container")) != "flatpak")
- .toBool();
+ auto settings = GlobalSettingStation::GetInstance().GetSettings();
+
+ // read settings from config file
+ auto forbid_all_gnupg_connection =
+ settings.value("network/forbid_all_gnupg_connection", false).toBool();
+
+ auto auto_import_missing_key =
+ settings.value("network/auto_import_missing_key", false).toBool();
+
+ auto use_custom_key_database_path =
+ settings.value("gnupg/use_custom_key_database_path", false).toBool();
+
+ auto custom_key_database_path =
+ settings.value("gnupg/custom_key_database_path", QString{}).toString();
+
+ auto custom_gnupg_install_path =
+ settings.value("gnupg/custom_gnupg_install_path", QString{}).toString();
+ auto use_pinentry_as_password_input_dialog =
+ settings
+ .value("gnupg/use_pinentry_as_password_input_dialog",
+ QString::fromLocal8Bit(qgetenv("container")) != "flatpak")
+ .toBool();
+
+ // try to restart all components
+ auto restart_all_gnupg_components_on_start =
+ settings.value("gnupg/restart_gpg_agent_on_start", false).toBool();
+
+ auto* task = new Thread::Task(
+ [=](const DataObjectPtr&) -> int {
// key database path
QString key_database_fs_path;
@@ -390,15 +390,10 @@ void InitGpgFrontendCore(CoreInitArgs args) {
Module::UpsertRTValue("core", "env.state.basic", 1);
CoreSignalStation::GetInstance()->SignalGoodGnupgEnv();
- // try to restart all components
- auto restart_all_gnupg_components_on_start =
- settings.value("gnupg/restart_gpg_agent_on_start", false).toBool();
-
if (restart_all_gnupg_components_on_start) {
GpgAdvancedOperator::RestartGpgComponents();
}
- Module::UpsertRTValue("core", "env.state.all", 1);
return 0;
},
"core_init_task");
@@ -414,4 +409,47 @@ void InitGpgFrontendCore(CoreInitArgs args) {
->PostTask(task);
}
+void StartMonitorCoreInitializationStatus() {
+ auto* task = new Thread::Task(
+ [=](const DataObjectPtr&) -> int {
+ for (;;) {
+ if (Module::RetrieveRTValueTypedOrDefault<>("core", "env.state.basic",
+ 0)) {
+ break;
+ }
+
+ LOG_D() << "monitor: core env is still initializing, waiting...";
+ QThread::msleep(15);
+ }
+
+ // waiting for module first
+ for (;;) {
+ if (Module::ModuleManager::GetInstance().IsAllModulesRegistered())
+ break;
+
+ LOG_D() << "monitor: some modules are still going to be registered, "
+ "waiting...";
+ QThread::msleep(15);
+ }
+ LOG_D() << "monitor: good, all module are registered.";
+
+ LOG_D()
+ << "monitor: core is fully initialized, sending signal to ui...";
+ Module::UpsertRTValue("core", "env.state.all", 1);
+ CoreSignalStation::GetInstance()->SignalCoreFullyLoaded();
+ return 0;
+ },
+ "waiting_core_init_task");
+
+ QObject::connect(task, &Thread::Task::SignalTaskEnd, [=]() {
+ LOG_D() << "monitor task ended, call back to main thead.";
+ });
+
+ // start the thread to check ctx and gnupg state
+ // it may take a few seconds or minutes
+ GpgFrontend::Thread::TaskRunnerGetter::GetInstance()
+ .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_External_Process)
+ ->PostTask(task);
+}
+
} // namespace GpgFrontend \ No newline at end of file
diff --git a/src/core/GpgCoreInit.h b/src/core/GpgCoreInit.h
index 203fd4dc..dd60578a 100644
--- a/src/core/GpgCoreInit.h
+++ b/src/core/GpgCoreInit.h
@@ -49,4 +49,9 @@ void GPGFRONTEND_CORE_EXPORT DestroyGpgFrontendCore();
*/
void GPGFRONTEND_CORE_EXPORT InitGpgFrontendCore(CoreInitArgs);
+/**
+ * @brief
+ *
+ */
+void GPGFRONTEND_CORE_EXPORT StartMonitorCoreInitializationStatus();
} // namespace GpgFrontend
diff --git a/src/core/GpgFrontendCore.h b/src/core/GpgFrontendCore.h
index 1d5ae29f..a632966e 100644
--- a/src/core/GpgFrontendCore.h
+++ b/src/core/GpgFrontendCore.h
@@ -46,10 +46,21 @@ Q_DECLARE_LOGGING_CATEGORY(core)
#define LOG_E() qCCritical(core)
#define LOG_F() qCFatal(core)
+#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)
+#define LOG_F(...) qCFatal(core)
+#else
+#define LOG_F(...) qFatal()
+#endif
+
#define FLOG_D(...) qCDebug(core, __VA_ARGS__)
#define FLOG_I(...) qCInfo(core, __VA_ARGS__)
#define FLOG_W(...) qCWarning(core, __VA_ARGS__)
#define FLOG_E(...) qCCritical(core, __VA_ARGS__)
+
+#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)
#define FLOG_F(...) qCFatal(core, __VA_ARGS__)
+#else
+#define FLOG_F(...) qFatal(__VA_ARGS__)
+#endif
#endif \ No newline at end of file
diff --git a/src/core/function/CoreSignalStation.h b/src/core/function/CoreSignalStation.h
index 1b7c3fa2..a5bea44a 100644
--- a/src/core/function/CoreSignalStation.h
+++ b/src/core/function/CoreSignalStation.h
@@ -69,6 +69,12 @@ class GPGFRONTEND_CORE_EXPORT CoreSignalStation : public QObject {
*
*/
void SignalGoodGnupgEnv();
+
+ /**
+ * @brief
+ *
+ */
+ void SignalCoreFullyLoaded();
};
} // namespace GpgFrontend
diff --git a/src/core/function/SecureMemoryAllocator.cpp b/src/core/function/SecureMemoryAllocator.cpp
index cb2249c9..c24e13f2 100644
--- a/src/core/function/SecureMemoryAllocator.cpp
+++ b/src/core/function/SecureMemoryAllocator.cpp
@@ -34,11 +34,13 @@ namespace GpgFrontend {
auto SecureMemoryAllocator::Allocate(std::size_t size) -> void* {
auto* addr = malloc(size);
+ if (addr == nullptr) FLOG_F("malloc failed!");
return addr;
}
auto SecureMemoryAllocator::Reallocate(void* ptr, std::size_t size) -> void* {
auto* addr = realloc(ptr, size);
+ if (addr == nullptr) FLOG_F("realloc failed!");
return addr;
}
@@ -50,11 +52,13 @@ void SecureMemoryAllocator::Deallocate(void* p) { free(p); }
auto SecureMemoryAllocator::Allocate(std::size_t size) -> void* {
auto* addr = mi_malloc(size);
+ if (addr == nullptr) FLOG_F("malloc failed!");
return addr;
}
auto SecureMemoryAllocator::Reallocate(void* ptr, std::size_t size) -> void* {
auto* addr = mi_realloc(ptr, size);
+ if (addr == nullptr) FLOG_F("realloc memory failed!");
return addr;
}
diff --git a/src/core/function/gpg/GpgContext.cpp b/src/core/function/gpg/GpgContext.cpp
index a4757d7f..2d9c5992 100644
--- a/src/core/function/gpg/GpgContext.cpp
+++ b/src/core/function/gpg/GpgContext.cpp
@@ -110,7 +110,7 @@ class GpgContext::Impl {
}
res += gpgme_io_write(fd, "\n", 1);
- return res == pass_size + 1 ? 0 : gpgme_error_from_errno(GPG_ERR_CANCELED);
+ return res == pass_size + 1 ? 0 : GPG_ERR_CANCELED;
}
static auto CustomPassphraseCb(void *hook, const char *uid_hint,
@@ -143,13 +143,18 @@ class GpgContext::Impl {
[&passphrase, &looper](Module::EventIdentifier i,
Module::Event::ListenerIdentifier ei,
Module::Event::Params p) {
- passphrase = p["passphrase"];
+ if (p["ret"] == "0") passphrase = p["passphrase"];
looper.quit();
});
looper.exec();
ResetCacheValue("PinentryContext");
+ LOG_D() << "passphrase size:" << passphrase.size();
+
+ // empty passphrase is not allowed
+ if (passphrase.isEmpty()) return GPG_ERR_CANCELED;
+
auto pass_bytes = passphrase.toLatin1();
auto pass_size = pass_bytes.size();
const auto *p_pass_bytes = pass_bytes.constData();
@@ -166,7 +171,7 @@ class GpgContext::Impl {
}
res += gpgme_io_write(fd, "\n", 1);
- return res == pass_size + 1 ? 0 : gpgme_error_from_errno(GPG_ERR_CANCELED);
+ return res == pass_size + 1 ? 0 : GPG_ERR_CANCELED;
}
static auto TestStatusCb(void *hook, const char *keyword,
diff --git a/src/core/function/gpg/GpgKeyOpera.cpp b/src/core/function/gpg/GpgKeyOpera.cpp
index d501acbc..332ed1b3 100644
--- a/src/core/function/gpg/GpgKeyOpera.cpp
+++ b/src/core/function/gpg/GpgKeyOpera.cpp
@@ -258,7 +258,7 @@ void GpgKeyOpera::GenerateSubkey(const GpgKey& key,
auto err = gpgme_op_createsubkey(ctx.DefaultContext(),
static_cast<gpgme_key_t>(key),
- algo.toUtf8(), 0, expires, flags);
+ algo.toLatin1(), 0, expires, flags);
if (CheckGpgError(err) != GPG_ERR_NO_ERROR) {
data_object->Swap({GpgGenerateKeyResult{}});
return err;
@@ -297,7 +297,7 @@ auto GpgKeyOpera::GenerateSubkeySync(const GpgKey& key,
auto err = gpgme_op_createsubkey(ctx.DefaultContext(),
static_cast<gpgme_key_t>(key),
- algo.toUtf8(), 0, expires, flags);
+ algo.toLatin1(), 0, expires, flags);
if (CheckGpgError(err) != GPG_ERR_NO_ERROR) {
data_object->Swap({GpgGenerateKeyResult{}});
diff --git a/src/core/model/GpgGenKeyInfo.cpp b/src/core/model/GpgGenKeyInfo.cpp
index 0d0ab239..3955a7cd 100644
--- a/src/core/model/GpgGenKeyInfo.cpp
+++ b/src/core/model/GpgGenKeyInfo.cpp
@@ -30,6 +30,9 @@
#include <cassert>
+#include "module/ModuleManager.h"
+#include "utils/CommonUtils.h"
+
namespace GpgFrontend {
void GenKeyInfo::SetAlgo(const QString &t_algo_args) {
@@ -40,6 +43,7 @@ void GenKeyInfo::SetAlgo(const QString &t_algo_args) {
if (!this->subkey_) {
this->SetAllowCertification(true);
+
} else {
this->SetAllowCertification(false);
}
@@ -64,6 +68,7 @@ void GenKeyInfo::SetAlgo(const QString &t_algo_args) {
* Recently, NIST has declared 512-bit keys obsolete:
* now, DSA is available in 1024, 2048 and 3072-bit lengths.
*/
+
SetAllowEncryption(false);
allow_change_encryption_ = false;
@@ -73,11 +78,10 @@ void GenKeyInfo::SetAlgo(const QString &t_algo_args) {
SetKeyLength(2048);
} else if (algo_args == "elg") {
/**
- * Algorithm (DSA) as a government standard for digital signatures.
- * Originally, it supported key lengths between 512 and 1024 bits.
- * Recently, NIST has declared 512-bit keys obsolete:
- * now, DSA is available in 1024, 2048 and 3072-bit lengths.
+ * GnuPG supports the Elgamal asymmetric encryption algorithm in key lengths
+ * ranging from 1024 to 4096 bits.
*/
+
SetAllowEncryption(true);
SetAllowAuthentication(false);
@@ -86,19 +90,12 @@ void GenKeyInfo::SetAlgo(const QString &t_algo_args) {
SetAllowSigning(false);
allow_change_signing_ = false;
- SetAllowCertification(false);
- allow_change_certification_ = false;
-
suggest_min_key_size_ = 1024;
suggest_max_key_size_ = 4096;
suggest_size_addition_step_ = 1024;
SetKeyLength(3072);
} else if (algo_args == "ed25519") {
- /**
- * GnuPG supports the Elgamal asymmetric encryption algorithm in key lengths
- * ranging from 1024 to 4096 bits.
- */
SetAllowEncryption(false);
allow_change_encryption_ = false;
@@ -106,18 +103,45 @@ void GenKeyInfo::SetAlgo(const QString &t_algo_args) {
suggest_max_key_size_ = -1;
suggest_size_addition_step_ = -1;
SetKeyLength(-1);
- } else if (algo_args == "cv25519" || algo_args == "nistp256" ||
- algo_args == "nistp384" || algo_args == "nistp521" ||
- algo_args == "brainpoolp256r1" || algo_args == "brainpoolp384r1" ||
- algo_args == "brainpoolp512r1") {
+ } else if (algo_args == "cv25519" || algo_args == "x448") {
SetAllowAuthentication(false);
allow_change_authentication_ = false;
SetAllowSigning(false);
allow_change_signing_ = false;
- SetAllowCertification(false);
- allow_change_certification_ = false;
+ suggest_min_key_size_ = -1;
+ suggest_max_key_size_ = -1;
+ suggest_size_addition_step_ = -1;
+ SetKeyLength(-1);
+ } else if (algo_args == "ed448") {
+ SetAllowEncryption(false);
+ allow_change_encryption_ = false;
+
+ // why not support signing? test later...
+ SetAllowSigning(false);
+ allow_change_signing_ = false;
+
+ suggest_min_key_size_ = -1;
+ suggest_max_key_size_ = -1;
+ suggest_size_addition_step_ = -1;
+ SetKeyLength(-1);
+ } else if (algo_args == "nistp256" || algo_args == "nistp384" ||
+ algo_args == "nistp521" || algo_args == "brainpoolp256r1" ||
+ algo_args == "brainpoolp384r1" || algo_args == "brainpoolp512r1") {
+ if (!subkey_) { // for primary key is always ecdsa
+
+ SetAllowEncryption(false);
+ allow_change_encryption_ = false;
+
+ } else { // for subkey key is always ecdh
+
+ SetAllowAuthentication(false);
+ allow_change_authentication_ = false;
+
+ SetAllowSigning(false);
+ allow_change_signing_ = false;
+ }
suggest_min_key_size_ = -1;
suggest_max_key_size_ = -1;
@@ -192,33 +216,93 @@ GenKeyInfo::GenKeyInfo(bool m_is_sub_key) : subkey_(m_is_sub_key) {
auto GenKeyInfo::GetSupportedKeyAlgo()
-> const std::vector<GenKeyInfo::KeyGenAlgo> & {
- static const std::vector<GenKeyInfo::KeyGenAlgo> kSupportKeyAlgo = {
+ static std::vector<GenKeyInfo::KeyGenAlgo> k_support_key_algo = {
{"RSA", "RSA", ""},
{"DSA", "DSA", ""},
- {"ECDSA", "ED25519", ""},
- {"ECDSA + ECDH", "ED25519", "CV25519"},
- {"ECDSA + ECDH NIST P-256", "ED25519", "NISTP256"},
- {"ECDSA + ECDH BrainPooL P-256", "ED25519", "BRAINPOOLP256R1"},
};
- return kSupportKeyAlgo;
+ static bool initialized = false;
+
+ if (!initialized) {
+ const auto gnupg_version = Module::RetrieveRTValueTypedOrDefault<>(
+ "core", "gpgme.ctx.gnupg_version", QString{"2.0.0"});
+ if (GFCompareSoftwareVersion(gnupg_version, "2.0.0") < 0) {
+ // do nothing
+ } else if (GFCompareSoftwareVersion(gnupg_version, "2.3.0") < 0) {
+ k_support_key_algo = {
+ {"RSA", "RSA", ""},
+ {"DSA", "DSA", ""},
+ {"ECDSA (ED25519)", "ED25519", ""},
+ {"ECDSA (NIST P-256)", "NISTP256", ""},
+ {"ECDSA (NIST P-384)", "NISTP384", ""},
+ {"ECDSA (NIST P-521)", "NISTP521", ""},
+ };
+ } else {
+ k_support_key_algo = {
+ {"RSA", "RSA", ""},
+ {"DSA", "DSA", ""},
+ {"ECDSA (ED25519)", "ED25519", ""},
+ {"ECDSA (NIST P-256)", "NISTP256", ""},
+ {"ECDSA (NIST P-384)", "NISTP384", ""},
+ {"ECDSA (NIST P-521)", "NISTP521", ""},
+ {"ECDSA (BrainPooL P-256)", "BRAINPOOLP256R1", ""},
+ {"ECDSA (BrainPooL P-384)", "BRAINPOOLP384R1", ""},
+ {"ECDSA (BrainPooL P-512)", "BRAINPOOLP512R1", ""},
+ };
+ }
+
+ initialized = true;
+ }
+
+ return k_support_key_algo;
}
auto GenKeyInfo::GetSupportedSubkeyAlgo()
-> const std::vector<GenKeyInfo::KeyGenAlgo> & {
- static const std::vector<GenKeyInfo::KeyGenAlgo> kSupportSubkeyAlgo = {
+ static std::vector<GenKeyInfo::KeyGenAlgo> k_support_subkey_algo = {
{"RSA", "", "RSA"},
{"DSA", "", "DSA"},
{"ELG-E", "", "ELG"},
- {"ECDSA", "", "ED25519"},
- {"ECDH", "", "CV25519"},
- {"ECDH NIST P-256", "", "NISTP256"},
- {"ECDH NIST P-384", "", "NISTP384"},
- {"ECDH NIST P-521", "", "NISTP521"},
- {"ECDH BrainPooL P-256", "", "BRAINPOOLP256R1"},
- {"ECDH BrainPooL P-384", "", "BRAINPOOLP384R1"},
- {"ECDH BrainPooL P-512", "", "BRAINPOOLP512R1"}};
-
- return kSupportSubkeyAlgo;
+ };
+ static bool initialized = false;
+
+ if (!initialized) {
+ const auto gnupg_version = Module::RetrieveRTValueTypedOrDefault<>(
+ "core", "gpgme.ctx.gnupg_version", QString{"2.0.0"});
+ if (GFCompareSoftwareVersion(gnupg_version, "2.0.0") < 0) {
+ // do nothing
+ } else if (GFCompareSoftwareVersion(gnupg_version, "2.3.0") < 0) {
+ k_support_subkey_algo = {
+ {"RSA", "", "RSA"},
+ {"DSA", "", "DSA"},
+ {"ELG-E", "", "ELG"},
+ {"ECDSA (ED25519)", "", "ED25519"},
+ {"ECDH (CV25519)", "", "CV25519"},
+ {"ECDH (NIST P-256)", "", "NISTP256"},
+ {"ECDH (NIST P-384)", "", "NISTP384"},
+ {"ECDH (NIST P-521)", "", "NISTP521"},
+ };
+ } else {
+ k_support_subkey_algo = {
+ {"RSA", "", "RSA"},
+ {"DSA", "", "DSA"},
+ {"ELG-E", "", "ELG"},
+ {"ECDSA (ED25519)", "", "ED25519"},
+ {"ECDSA (ED448)", "", "ED448"},
+ {"ECDH (CV25519)", "", "CV25519"},
+ {"ECDH (X448)", "", "X448"},
+ {"ECDH (NIST P-256)", "", "NISTP256"},
+ {"ECDH (NIST P-384)", "", "NISTP384"},
+ {"ECDH (NIST P-521)", "", "NISTP521"},
+ {"ECDH (BrainPooL P-256)", "", "BRAINPOOLP256R1"},
+ {"ECDH (BrainPooL P-384)", "", "BRAINPOOLP384R1"},
+ {"ECDH (BrainPooL P-512)", "", "BRAINPOOLP512R1"},
+ };
+ }
+
+ initialized = true;
+ }
+
+ return k_support_subkey_algo;
}
/**
diff --git a/src/core/module/Event.cpp b/src/core/module/Event.cpp
index 873e728d..56f45261 100644
--- a/src/core/module/Event.cpp
+++ b/src/core/module/Event.cpp
@@ -38,7 +38,7 @@ class Event::Impl {
: event_identifier_(std::move(event_id)),
callback_(std::move(callback)),
callback_thread_(QThread::currentThread()) {
- data_.insert(params);
+ if (!params.empty()) data_.insert(params);
}
auto operator[](const QString& key) const -> std::optional<ParameterValue> {
@@ -98,17 +98,16 @@ class Event::Impl {
event->id = GFStrDup(event_identifier_);
event->trigger_id = GFStrDup(trigger_uuid_);
+ event->params = nullptr;
GFModuleEventParam* l_param = nullptr;
GFModuleEventParam* p_param;
- int index = 0;
-
#if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0)
for (const auto& data : data_.asKeyValueRange()) {
p_param = static_cast<GFModuleEventParam*>(
SecureMalloc(sizeof(GFModuleEventParam)));
- if (index++ == 0) event->params = p_param;
+ if (event->params == nullptr) event->params = p_param;
p_param->name = GFStrDup(data.first);
p_param->value = GFStrDup(data.second);
@@ -121,7 +120,7 @@ class Event::Impl {
for (auto it = data_.keyValueBegin(); it != data_.keyValueEnd(); ++it) {
p_param = static_cast<GFModuleEventParam*>(
SecureMalloc(sizeof(GFModuleEventParam)));
- if (index++ == 0) event->params = p_param;
+ if (event->params == nullptr) event->params = p_param;
p_param->name = GFStrDup(it->first);
p_param->value = GFStrDup(it->second);
diff --git a/src/core/module/GlobalModuleContext.cpp b/src/core/module/GlobalModuleContext.cpp
index 08090d33..25ddce65 100644
--- a/src/core/module/GlobalModuleContext.cpp
+++ b/src/core/module/GlobalModuleContext.cpp
@@ -102,14 +102,12 @@ class GlobalModuleContext::Impl {
module_register_table_.find(module->GetModuleIdentifier()) !=
module_register_table_.end()) {
FLOG_W("module is null or have already registered this module");
+ registered_modules_++;
return false;
}
- if (module->Register() != 0) {
- LOG_W() << "register module " << module->GetModuleIdentifier()
- << " failed";
- return false;
- }
+ LOG_D() << "(+) module: " << module->GetModuleIdentifier()
+ << "registering...";
auto register_info =
GpgFrontend::SecureCreateSharedObject<ModuleRegisterInfo>();
@@ -124,13 +122,28 @@ class GlobalModuleContext::Impl {
.GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_Module)
->GetThread());
- // Register the module with its identifier.
+ // register the module with its identifier.
module_register_table_[module->GetModuleIdentifier()] = register_info;
+ if (module->Register() != 0) {
+ LOG_W() << "module: " << module->GetModuleIdentifier()
+ << " register failed.";
+ register_info->registered = false;
+ registered_modules_++;
+ return false;
+ }
+
+ register_info->registered = true;
+ registered_modules_++;
+
+ LOG_D() << "(+) module: " << module->GetModuleIdentifier() << "registered.";
+
return true;
}
auto ActiveModule(ModuleIdentifier module_id) -> bool {
+ LOG_D() << "(*) module: " << module_id << "activating...";
+
// Search for the module in the register table.
auto module_info_opt = search_module_register_table(module_id);
if (!module_info_opt.has_value()) {
@@ -140,6 +153,12 @@ class GlobalModuleContext::Impl {
auto module_info = module_info_opt.value();
+ if (!module_info->registered) {
+ LOG_W() << "module id:" << module_id
+ << " is not properly register, activation abort...";
+ return false;
+ }
+
// try to get module from module info
auto module = module_info->module;
if (module == nullptr) {
@@ -152,6 +171,8 @@ class GlobalModuleContext::Impl {
if (!module_info->activate) {
module->Active();
module_info->activate = true;
+
+ LOG_D() << "(*) module: " << module_id << "activated.";
}
return module_info->activate;
@@ -293,6 +314,12 @@ class GlobalModuleContext::Impl {
return m.has_value() && m->get()->activate;
}
+ [[nodiscard]] auto IsModuleRegistered(const ModuleIdentifier& m_id) const
+ -> bool {
+ auto m = search_module_register_table(m_id);
+ return m.has_value() && m->get()->activate;
+ }
+
auto IsIntegratedModule(ModuleIdentifier m_id) -> bool {
auto m = search_module_register_table(m_id);
return m.has_value() && m->get()->integrated;
@@ -314,10 +341,13 @@ class GlobalModuleContext::Impl {
return module_info->get()->listening_event_ids;
}
+ auto GetRegisteredModuleNum() const -> int { return registered_modules_; }
+
private:
struct ModuleRegisterInfo {
int channel;
ModulePtr module;
+ bool registered;
bool activate;
bool integrated;
QList<QString> listening_event_ids;
@@ -334,6 +364,7 @@ class GlobalModuleContext::Impl {
std::set<int> acquired_channel_;
TaskRunnerPtr default_task_runner_;
+ int registered_modules_ = 0;
auto acquire_new_unique_channel() -> int {
int random_channel = QRandomGenerator::global()->bounded(65535);
@@ -440,4 +471,9 @@ auto GlobalModuleContext::GetModuleListening(ModuleIdentifier module_id)
-> QList<EventIdentifier> {
return p_->GetModuleListening(module_id);
}
+
+auto GlobalModuleContext::GetRegisteredModuleNum() const -> int {
+ return p_->GetRegisteredModuleNum();
+}
+
} // namespace GpgFrontend::Module
diff --git a/src/core/module/GlobalModuleContext.h b/src/core/module/GlobalModuleContext.h
index e3dabe0e..f122f36f 100644
--- a/src/core/module/GlobalModuleContext.h
+++ b/src/core/module/GlobalModuleContext.h
@@ -90,6 +90,8 @@ class GPGFRONTEND_CORE_EXPORT GlobalModuleContext : public QObject {
auto ListAllRegisteredModuleID() -> QList<ModuleIdentifier>;
+ [[nodiscard]] auto GetRegisteredModuleNum() const -> int;
+
private:
class Impl;
SecureUniquePtr<Impl> p_;
diff --git a/src/core/module/Module.cpp b/src/core/module/Module.cpp
index becda4b6..1be4a4bd 100644
--- a/src/core/module/Module.cpp
+++ b/src/core/module/Module.cpp
@@ -110,10 +110,10 @@ class Module::Impl {
if (qt_env_ver_major != QString::number(QT_VERSION_MAJOR) + "." ||
qt_env_ver_minor != QString::number(QT_VERSION_MINOR) + ".") {
- LOG_W() << "uncompatible module: " << identifier_
- << ", reason sdk version: " << qt_env_ver_
- << "current sdk version: " << QString::fromUtf8(QT_VERSION_STR)
- << ", abort...";
+ LOG_W() << "module: " << identifier_
+ << "is not compatible, reason module qt version: " << qt_env_ver_
+ << ", but application qt version: "
+ << QString::fromUtf8(QT_VERSION_STR) << ", abort...";
return;
}
@@ -274,7 +274,8 @@ auto Module::Register() -> int { return p_->Register(); }
auto Module::Active() -> int { return p_->Active(); }
auto Module::Exec(EventReference event) -> int {
- return p_->Exec(std::move(event));
+ LOG_D() << "module" << GetModuleIdentifier() << "executing...";
+ return p_->Exec(event);
}
auto Module::Deactivate() -> int { return p_->Deactivate(); }
diff --git a/src/core/module/ModuleInit.cpp b/src/core/module/ModuleInit.cpp
index 3c71a45b..972e7025 100644
--- a/src/core/module/ModuleInit.cpp
+++ b/src/core/module/ModuleInit.cpp
@@ -38,15 +38,17 @@
namespace GpgFrontend::Module {
-void LoadModuleFromPath(const QString& mods_path, bool integrated) {
+auto SearchModuleFromPath(const QString& mods_path,
+ bool integrated) -> QMap<QString, bool> {
+ QMap<QString, bool> m;
for (const auto& module_library_name : QDir(mods_path).entryList(
QStringList() << "*.so" << "*.dll" << "*.dylib", QDir::Files)) {
- ModuleManager::GetInstance().LoadModule(
- mods_path + "/" + module_library_name, integrated);
+ m[mods_path + "/" + module_library_name] = integrated;
}
+ return m;
}
-auto LoadIntegratedMods() -> bool {
+auto LoadIntegratedMods() -> QMap<QString, bool> {
const auto exec_binary_path = QCoreApplication::applicationDirPath();
QString mods_path = exec_binary_path + "/modules";
@@ -71,37 +73,63 @@ auto LoadIntegratedMods() -> bool {
if (!QDir(mods_path).exists()) {
LOG_W() << "integrated module directory at path: " << mods_path
<< " not found, abort...";
- return false;
+ return {};
}
- LoadModuleFromPath(mods_path, true);
-
- return true;
+ return SearchModuleFromPath(mods_path, true);
}
-auto LoadExternalMods() -> bool {
+auto LoadExternalMods() -> QMap<QString, bool> {
auto mods_path =
GpgFrontend::GlobalSettingStation::GetInstance().GetModulesDir();
if (!QDir(mods_path).exists()) {
LOG_W() << "external module directory at path " << mods_path
<< " not found, abort...";
- return false;
+ return {};
}
- LoadModuleFromPath(mods_path, false);
-
- return true;
+ return SearchModuleFromPath(mods_path, false);
}
void LoadGpgFrontendModules(ModuleInitArgs) {
+ // give user ability to give up all modules
+ auto disable_loading_all_modules =
+ GlobalSettingStation::GetInstance()
+ .GetSettings()
+ .value("basic/disable_loading_all_modules", false)
+ .toBool();
+ if (disable_loading_all_modules) return;
+
// must init at default thread before core
- Thread::TaskRunnerGetter::GetInstance().GetTaskRunner()->PostTask(
- new Thread::Task(
+ Thread::TaskRunnerGetter::GetInstance()
+ .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_Module)
+ ->PostTask(new Thread::Task(
[](const DataObjectPtr&) -> int {
- return LoadIntegratedMods() && LoadExternalMods() ? 0 : -1;
+ QMap<QString, bool> modules = LoadIntegratedMods();
+ modules.insert(LoadExternalMods());
+
+ auto& manager = ModuleManager::GetInstance();
+ manager.SetNeedRegisterModulesNum(static_cast<int>(modules.size()));
+
+#if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0)
+ for (const auto& m : modules.asKeyValueRange()) {
+ manager.LoadModule(m.first, m.second);
+ }
+#else
+ for (auto it = modules.keyValueBegin(); it != modules.keyValueEnd();
+ ++it) {
+ manager.LoadModule(it->first, it->second);
+ }
+#endif
+
+ LOG_D() << "all modules are loaded into memory.";
+ return 0;
},
"modules_system_init_task"));
+
+ LOG_D() << "dear module manager, is all module registered? answer: "
+ << ModuleManager::GetInstance().IsAllModulesRegistered();
}
void ShutdownGpgFrontendModules() {}
diff --git a/src/core/module/ModuleManager.cpp b/src/core/module/ModuleManager.cpp
index 5f8895be..8f97adc3 100644
--- a/src/core/module/ModuleManager.cpp
+++ b/src/core/module/ModuleManager.cpp
@@ -54,66 +54,79 @@ class ModuleManager::Impl {
~Impl() = default;
auto LoadAndRegisterModule(const QString& module_library_path,
- bool integrated_module) -> void {
- // give user ability to give up all modules
- auto disable_loading_all_modules =
- GlobalSettingStation::GetInstance()
- .GetSettings()
- .value("basic/disable_loading_all_modules", false)
- .toBool();
- if (disable_loading_all_modules) return;
-
- Thread::TaskRunnerGetter::GetInstance()
- .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_Default)
- ->PostTask(new Thread::Task(
- [=](GpgFrontend::DataObjectPtr) -> int {
- QLibrary module_library(module_library_path);
- if (!module_library.load()) {
- LOG_W() << "module manager failed to load module: "
- << module_library.fileName()
- << ", reason: " << module_library.errorString();
- return -1;
- }
-
- auto module = SecureCreateSharedObject<Module>(module_library);
- if (!module->IsGood()) {
- LOG_W() << "module manager failed to load module, "
- "reason: illegal module: "
- << module_library.fileName();
- return -1;
- }
-
- module->SetGPC(gmc_.get());
- if (!gmc_->RegisterModule(module, integrated_module)) return -1;
-
- const auto module_id = module->GetModuleIdentifier();
- const auto module_hash = module->GetModuleHash();
-
- SettingsObject so(QString("module.%1.so").arg(module_id));
- ModuleSO module_so(so);
-
- // reset module settings if necessary
- if (module_so.module_id != module_id ||
- module_so.module_hash != module_hash) {
- module_so.module_id = module_id;
- module_so.module_hash = module_hash;
- // auto active integrated module by default
- module_so.auto_activate = integrated_module;
- module_so.set_by_user = false;
-
- so.Store(module_so.ToJson());
- }
-
- // if this module need auto active
- if (module_so.auto_activate) {
- if (!gmc_->ActiveModule(module_id)) {
- return -1;
- }
- }
+ bool integrated_module) -> bool {
+ QLibrary module_library(module_library_path);
+ if (!module_library.load()) {
+ LOG_W() << "module manager failed to load module: "
+ << module_library.fileName()
+ << ", reason: " << module_library.errorString();
+ need_register_modules_--;
+ return false;
+ }
+
+ auto module = SecureCreateSharedObject<Module>(module_library);
+ if (!module->IsGood()) {
+ LOG_W() << "module manager failed to load module, "
+ "reason: illegal module: "
+ << module_library.fileName();
+ need_register_modules_--;
+ return false;
+ }
+
+ module->SetGPC(gmc_.get());
+
+ LOG_D() << "a new need register module: "
+ << QFileInfo(module_library_path).fileName();
+
+ auto runner = Thread::TaskRunnerGetter::GetInstance().GetTaskRunner(
+ Thread::TaskRunnerGetter::kTaskRunnerType_Module);
+
+ runner->PostTask(new Thread::Task(
+ [=](GpgFrontend::DataObjectPtr) -> int {
+ // register module
+ if (!gmc_->RegisterModule(module, integrated_module)) return -1;
+
+ return 0;
+ },
+ __func__, nullptr));
+
+ runner->PostTask(new Thread::Task(
+ [=](GpgFrontend::DataObjectPtr) -> int {
+ const auto module_id = module->GetModuleIdentifier();
+ const auto module_hash = module->GetModuleHash();
+
+ SettingsObject so(QString("module.%1.so").arg(module_id));
+ ModuleSO module_so(so);
+
+ // reset module settings if necessary
+ if (module_so.module_id != module_id ||
+ module_so.module_hash != module_hash) {
+ module_so.module_id = module_id;
+ module_so.module_hash = module_hash;
+ // auto active integrated module by default
+ module_so.auto_activate = integrated_module;
+ module_so.set_by_user = false;
+
+ so.Store(module_so.ToJson());
+ }
+
+ // if this module need auto active
+ if (module_so.auto_activate) {
+ if (!gmc_->ActiveModule(module_id)) {
+ return -1;
+ }
+ }
+
+ return 0;
+ },
+ __func__, nullptr));
+
+ return true;
+ }
- return 0;
- },
- __func__, nullptr));
+ void SetNeedRegisterModulesNum(int n) {
+ if (need_register_modules_ != -1 || n < 0) return;
+ need_register_modules_ = n;
}
auto SearchModule(ModuleIdentifier module_id) -> ModulePtr {
@@ -126,7 +139,7 @@ class ModuleManager::Impl {
void RegisterModule(const ModulePtr& module) {
Thread::TaskRunnerGetter::GetInstance()
- .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_Default)
+ .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_Module)
->PostTask(new Thread::Task(
[=](GpgFrontend::DataObjectPtr) -> int {
module->SetGPC(gmc_.get());
@@ -138,7 +151,7 @@ class ModuleManager::Impl {
void ListenEvent(const ModuleIdentifier& module_id,
const EventIdentifier& event_id) {
Thread::TaskRunnerGetter::GetInstance()
- .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_Default)
+ .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_Module)
->PostTask(new Thread::Task(
[=](const GpgFrontend::DataObjectPtr&) -> int {
gmc_->ListenEvent(module_id, event_id);
@@ -149,7 +162,7 @@ class ModuleManager::Impl {
void TriggerEvent(const EventReference& event) {
Thread::TaskRunnerGetter::GetInstance()
- .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_Default)
+ .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_Module)
->PostTask(new Thread::Task(
[=](const GpgFrontend::DataObjectPtr&) -> int {
gmc_->TriggerEvent(event);
@@ -170,7 +183,7 @@ class ModuleManager::Impl {
void ActiveModule(const ModuleIdentifier& identifier) {
Thread::TaskRunnerGetter::GetInstance()
- .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_Default)
+ .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_Module)
->PostTask(new Thread::Task(
[=](const GpgFrontend::DataObjectPtr&) -> int {
gmc_->ActiveModule(identifier);
@@ -181,7 +194,7 @@ class ModuleManager::Impl {
void DeactivateModule(const ModuleIdentifier& identifier) {
Thread::TaskRunnerGetter::GetInstance()
- .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_Default)
+ .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_Module)
->PostTask(new Thread::Task(
[=](const GpgFrontend::DataObjectPtr&) -> int {
gmc_->DeactivateModule(identifier);
@@ -219,6 +232,14 @@ class ModuleManager::Impl {
return gmc_->IsIntegratedModule(id);
}
+ auto IsAllModulesRegistered() {
+ if (need_register_modules_ == -1) return false;
+ LOG_D() << "module manager report, need register: "
+ << need_register_modules_ << "registered"
+ << gmc_->GetRegisteredModuleNum();
+ return need_register_modules_ == gmc_->GetRegisteredModuleNum();
+ }
+
auto GRT() -> GlobalRegisterTable* { return grt_.get(); }
private:
@@ -226,12 +247,18 @@ class ModuleManager::Impl {
SecureUniquePtr<GlobalModuleContext> gmc_;
SecureUniquePtr<GlobalRegisterTable> grt_;
QList<QLibrary> module_libraries_;
+ int need_register_modules_ = -1;
};
auto IsModuleActivate(ModuleIdentifier id) -> bool {
return ModuleManager::GetInstance().IsModuleActivated(id);
}
+auto GPGFRONTEND_CORE_EXPORT IsModuleExists(ModuleIdentifier id) -> bool {
+ auto module = ModuleManager::GetInstance().SearchModule(id);
+ return module != nullptr && module->IsGood();
+}
+
auto UpsertRTValue(const QString& namespace_, const QString& key,
const std::any& value) -> bool {
return ModuleManager::GetInstance().UpsertRTValue(namespace_, key,
@@ -254,8 +281,8 @@ ModuleManager::ModuleManager(int channel)
ModuleManager::~ModuleManager() = default;
-void ModuleManager::LoadModule(QString module_library_path,
- bool integrated_module) {
+auto ModuleManager::LoadModule(QString module_library_path,
+ bool integrated_module) -> bool {
return p_->LoadAndRegisterModule(module_library_path, integrated_module);
}
@@ -332,4 +359,11 @@ auto ModuleManager::ListAllRegisteredModuleID() -> QList<ModuleIdentifier> {
auto ModuleManager::GRT() -> GlobalRegisterTable* { return p_->GRT(); }
+auto ModuleManager::IsAllModulesRegistered() -> bool {
+ return p_->IsAllModulesRegistered();
+}
+
+void ModuleManager::SetNeedRegisterModulesNum(int n) {
+ p_->SetNeedRegisterModulesNum(n);
+}
} // namespace GpgFrontend::Module \ No newline at end of file
diff --git a/src/core/module/ModuleManager.h b/src/core/module/ModuleManager.h
index 365dd8fd..5c703bf3 100644
--- a/src/core/module/ModuleManager.h
+++ b/src/core/module/ModuleManager.h
@@ -65,14 +65,18 @@ class GPGFRONTEND_CORE_EXPORT ModuleManager
virtual ~ModuleManager() override;
- auto LoadModule(QString, bool) -> void;
+ auto LoadModule(QString, bool) -> bool;
auto SearchModule(ModuleIdentifier) -> ModulePtr;
+ void SetNeedRegisterModulesNum(int);
+
auto ListAllRegisteredModuleID() -> QList<ModuleIdentifier>;
void RegisterModule(ModulePtr);
+ auto IsAllModulesRegistered() -> bool;
+
auto IsModuleActivated(ModuleIdentifier) -> bool;
auto IsIntegratedModule(ModuleIdentifier) -> bool;
@@ -139,6 +143,14 @@ auto GPGFRONTEND_CORE_EXPORT IsModuleActivate(ModuleIdentifier) -> bool;
/**
* @brief
*
+ * @return true
+ * @return false
+ */
+auto GPGFRONTEND_CORE_EXPORT IsModuleExists(ModuleIdentifier) -> bool;
+
+/**
+ * @brief
+ *
* @param namespace_
* @param key
* @param value
diff --git a/src/core/utils/CommonUtils.cpp b/src/core/utils/CommonUtils.cpp
index f8468c46..60ce4642 100644
--- a/src/core/utils/CommonUtils.cpp
+++ b/src/core/utils/CommonUtils.cpp
@@ -72,24 +72,25 @@ auto GFCompareSoftwareVersion(const QString& a, const QString& b) -> int {
return 0;
}
-auto GFStrDup(const QString& str) -> char* {
- auto utf8_str = str.toUtf8();
- auto* c_str =
- static_cast<char*>(SecureMalloc((utf8_str.size() + 1) * sizeof(char)));
-
- memcpy(c_str, utf8_str.constData(), utf8_str.size());
- c_str[utf8_str.size()] = '\0';
- return c_str;
+auto GFStrDup(const QString& s) -> char* {
+ if (s.isEmpty()) return nullptr;
+
+ auto u_s = s.toUtf8();
+ auto* c_s = static_cast<char*>(SecureMalloc((u_s.size() + 1) * sizeof(char)));
+
+ memcpy(c_s, u_s.constData(), u_s.size());
+ c_s[u_s.size()] = '\0';
+ return c_s;
}
-auto GFUnStrDup(char* str) -> QString {
- auto qt_str = QString::fromUtf8(str);
- SecureFree(static_cast<void*>(const_cast<char*>(str)));
- return qt_str;
+auto GFUnStrDup(char* s) -> QString {
+ auto q_s = QString::fromUtf8(s == nullptr ? "" : s);
+ if (s != nullptr) SecureFree(static_cast<void*>(const_cast<char*>(s)));
+ return q_s;
}
-auto GFUnStrDup(const char* str) -> QString {
- return GFUnStrDup(const_cast<char*>(str));
+auto GFUnStrDup(const char* s) -> QString {
+ return GFUnStrDup(const_cast<char*>(s));
}
} // namespace GpgFrontend \ No newline at end of file
diff --git a/src/core/utils/CommonUtils.h b/src/core/utils/CommonUtils.h
index c2f4157a..83490cc4 100644
--- a/src/core/utils/CommonUtils.h
+++ b/src/core/utils/CommonUtils.h
@@ -56,13 +56,13 @@ auto GPGFRONTEND_CORE_EXPORT GFCompareSoftwareVersion(const QString &a,
*
* @return char*
*/
-auto GFStrDup(const QString &) -> char *;
+auto GPGFRONTEND_CORE_EXPORT GFStrDup(const QString &) -> char *;
/**
* @brief
*
* @return QString
*/
-auto GFUnStrDup(const char *) -> QString;
+auto GPGFRONTEND_CORE_EXPORT GFUnStrDup(const char *) -> QString;
} // namespace GpgFrontend \ No newline at end of file
diff --git a/src/init.cpp b/src/init.cpp
index 6d8fe8e4..f5476783 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -108,6 +108,9 @@ void InitGlobalBasicEnv(const GFCxtWPtr &p_ctx, bool gui_mode) {
// then load core
InitGpgFrontendCore(core_init_args);
+
+ // monitor
+ StartMonitorCoreInitializationStatus();
}
/**
diff --git a/src/sdk/GFSDKBasic.cpp b/src/sdk/GFSDKBasic.cpp
index 906f9baf..32076cd0 100644
--- a/src/sdk/GFSDKBasic.cpp
+++ b/src/sdk/GFSDKBasic.cpp
@@ -32,7 +32,7 @@
#include "core/function/gpg/GpgCommandExecutor.h"
#include "core/utils/BuildInfoUtils.h"
#include "sdk/private/CommonUtils.h"
-#include "ui/GpgFrontendUIInit.h"
+#include "ui/UIModuleManager.h"
auto GFAllocateMemory(uint32_t size) -> void* {
return GpgFrontend::SecureMemoryAllocator::Allocate(size);
@@ -110,11 +110,10 @@ auto GFModuleStrDup(const char* src) -> char* {
auto GFAppActiveLocale() -> char* { return GFStrDup(QLocale().name()); }
-auto GFAppRegisterTranslator(char* data, int size) -> int {
- auto b = QByteArray(data, size);
- QMetaObject::invokeMethod(QApplication::instance()->thread(), [b]() {
- GpgFrontend::UI::InstallTranslatorFromQMData(b);
- });
- GFFreeMemory(data);
- return 0;
+auto GFAppRegisterTranslatorReader(const char* id,
+ GFTranslatorDataReader reader) -> int {
+ return GpgFrontend::UI::UIModuleManager::GetInstance()
+ .RegisterTranslatorDataReader(GFUnStrDup(id), reader)
+ ? 0
+ : -1;
}
diff --git a/src/sdk/GFSDKBasic.h b/src/sdk/GFSDKBasic.h
index aba4d2e0..f6c80287 100644
--- a/src/sdk/GFSDKBasic.h
+++ b/src/sdk/GFSDKBasic.h
@@ -48,6 +48,8 @@ using GFCommandExecuteContext = struct {
void* data;
};
+using GFTranslatorDataReader = int (*)(const char* locale, char** data);
+
/**
* @brief
*
@@ -129,6 +131,6 @@ auto GPGFRONTEND_MODULE_SDK_EXPORT GFAppActiveLocale() -> char*;
* @param size
* @return auto
*/
-auto GPGFRONTEND_MODULE_SDK_EXPORT GFAppRegisterTranslator(char* data,
- int size) -> int;
+auto GPGFRONTEND_MODULE_SDK_EXPORT
+GFAppRegisterTranslatorReader(const char* id, GFTranslatorDataReader reader) -> int;
} \ No newline at end of file
diff --git a/src/test/GpgFrontendTest.h b/src/test/GpgFrontendTest.h
index d78f6636..c5b7a375 100644
--- a/src/test/GpgFrontendTest.h
+++ b/src/test/GpgFrontendTest.h
@@ -44,13 +44,23 @@ Q_DECLARE_LOGGING_CATEGORY(test)
#define LOG_I() qCInfo(test)
#define LOG_W() qCWarning(test)
#define LOG_E() qCCritical(test)
-#define LOG_F() qCFatal(test)
+
+#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)
+#define LOG_F(...) qCFatal(test)
+#else
+#define LOG_F(...) qFatal()
+#endif
#define FLOG_D(...) qCDebug(test, __VA_ARGS__)
#define FLOG_I(...) qCInfo(test, __VA_ARGS__)
#define FLOG_W(...) qCWarning(test, __VA_ARGS__)
#define FLOG_E(...) qCCritical(test, __VA_ARGS__)
+
+#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)
#define FLOG_F(...) qCFatal(test, __VA_ARGS__)
+#else
+#define FLOG_F(...) qFatal(__VA_ARGS__)
+#endif
#endif
diff --git a/src/ui/GpgFrontendUI.h b/src/ui/GpgFrontendUI.h
index c3816469..39c39686 100644
--- a/src/ui/GpgFrontendUI.h
+++ b/src/ui/GpgFrontendUI.h
@@ -47,12 +47,23 @@ Q_DECLARE_LOGGING_CATEGORY(ui)
#define LOG_I() qCInfo(ui)
#define LOG_W() qCWarning(ui)
#define LOG_E() qCCritical(ui)
-#define LOG_F() qCFatal(core)
+#define LOG_F() qCFatal(ui)
+
+#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)
+#define LOG_F(...) qCFatal(ui)
+#else
+#define LOG_F(...) qFatal()
+#endif
#define FLOG_D(...) qCDebug(ui, __VA_ARGS__)
#define FLOG_I(...) qCInfo(ui, __VA_ARGS__)
#define FLOG_W(...) qCWarning(ui, __VA_ARGS__)
#define FLOG_E(...) qCCritical(ui, __VA_ARGS__)
+
+#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)
#define FLOG_F(...) qCFatal(ui, __VA_ARGS__)
+#else
+#define FLOG_F(...) qFatal(__VA_ARGS__)
+#endif
#endif
diff --git a/src/ui/GpgFrontendUIInit.cpp b/src/ui/GpgFrontendUIInit.cpp
index 0309ca1f..965ce471 100644
--- a/src/ui/GpgFrontendUIInit.cpp
+++ b/src/ui/GpgFrontendUIInit.cpp
@@ -30,12 +30,12 @@
#include <QtNetwork>
-#include "UIModuleManager.h"
#include "core/GpgConstants.h"
#include "core/function/CoreSignalStation.h"
#include "core/function/GlobalSettingStation.h"
#include "core/model/GpgPassphraseContext.h"
#include "core/module/ModuleManager.h"
+#include "ui/UIModuleManager.h"
#include "ui/UISignalStation.h"
#include "ui/UserInterfaceUtils.h"
#include "ui/main_window/MainWindow.h"
@@ -65,8 +65,9 @@ void WaitEnvCheckingProcess() {
waiting_dialog->setLabel(waiting_dialog_label);
waiting_dialog->resize(420, 120);
QApplication::connect(CoreSignalStation::GetInstance(),
- &CoreSignalStation::SignalGoodGnupgEnv, waiting_dialog,
- [=]() {
+ &CoreSignalStation::SignalCoreFullyLoaded,
+ waiting_dialog, [=]() {
+ LOG_D() << "ui caught signal: core fully loaded";
waiting_dialog->finished(0);
waiting_dialog->deleteLater();
});
@@ -74,7 +75,7 @@ void WaitEnvCheckingProcess() {
// new local event looper
QEventLoop looper;
QApplication::connect(CoreSignalStation::GetInstance(),
- &CoreSignalStation::SignalGoodGnupgEnv, &looper,
+ &CoreSignalStation::SignalCoreFullyLoaded, &looper,
&QEventLoop::quit);
QApplication::connect(waiting_dialog, &QProgressDialog::canceled, [=]() {
@@ -84,9 +85,9 @@ void WaitEnvCheckingProcess() {
});
auto env_state =
- Module::RetrieveRTValueTypedOrDefault<>("core", "env.state.basic", 0);
+ Module::RetrieveRTValueTypedOrDefault<>("core", "env.state.all", 0);
FLOG_D("ui is ready to waiting for env initialized, env_state: %d",
- env_state);
+ env_state);
// check twice to avoid some unlucky sitations
if (env_state == 1) {
@@ -194,16 +195,20 @@ void InitGpgFrontendUI(QApplication* /*app*/) {
// no proxy by default
QNetworkProxy::setApplicationProxy(QNetworkProxy::NoProxy);
}
+}
- if (Module::RetrieveRTValueTypedOrDefault<>("core", "env.state.basic", 0) ==
+void WaitingAllInitializationFinished() {
+ if (Module::RetrieveRTValueTypedOrDefault<>("core", "env.state.all", 0) ==
0) {
+ LOG_D() << "ui init is done, but cor doesn't, going to waiting for core...";
WaitEnvCheckingProcess();
}
+ LOG_D() << "application fully initialized...";
}
auto RunGpgFrontendUI(QApplication* app) -> int {
// create main window and show it
- auto main_window = std::make_unique<GpgFrontend::UI::MainWindow>();
+ auto main_window = SecureCreateUniqueObject<GpgFrontend::UI::MainWindow>();
// pre-check, if application need to restart
if (CommonUtils::GetInstance()->isApplicationNeedRestart()) {
@@ -211,6 +216,8 @@ auto RunGpgFrontendUI(QApplication* app) -> int {
return kDeepRestartCode;
}
+ LOG_D() << "main window start to initialize...";
+
// init main window
main_window->Init();
@@ -257,19 +264,11 @@ void InitUITranslations() {
}
}
-auto InstallTranslatorFromQMData(const QByteArray& data) -> bool {
- auto* translator = new QTranslator(QCoreApplication::instance());
-
- if (translator->load(reinterpret_cast<uchar*>(const_cast<char*>(data.data())),
- data.size())) {
- QCoreApplication::installTranslator(translator);
- registered_translators.append(translator);
- loaded_qm_datum.append(data);
-
- return true;
- }
-
- return false;
+void InitModulesTranslations() {
+ // register module's translations
+ UIModuleManager::GetInstance().RegisterAllModuleTranslators();
+ // translate all params
+ UIModuleManager::GetInstance().TranslateAllModulesParams();
}
} // namespace GpgFrontend::UI
diff --git a/src/ui/GpgFrontendUIInit.h b/src/ui/GpgFrontendUIInit.h
index 5e44c5bf..afdbc2ab 100644
--- a/src/ui/GpgFrontendUIInit.h
+++ b/src/ui/GpgFrontendUIInit.h
@@ -45,6 +45,12 @@ void GPGFRONTEND_UI_EXPORT PreInitGpgFrontendUI();
void GPGFRONTEND_UI_EXPORT InitGpgFrontendUI(QApplication *);
/**
+ * @brief
+ *
+ */
+void GPGFRONTEND_UI_EXPORT WaitingAllInitializationFinished();
+
+/**
* @brief init the UI library
*
*/
@@ -59,7 +65,6 @@ auto GPGFRONTEND_UI_EXPORT RunGpgFrontendUI(QApplication *) -> int;
* @brief
*
*/
-auto GPGFRONTEND_UI_EXPORT InstallTranslatorFromQMData(const QByteArray &data)
- -> bool;
+void GPGFRONTEND_UI_EXPORT InitModulesTranslations();
}; // namespace GpgFrontend::UI
diff --git a/src/ui/UIModuleManager.cpp b/src/ui/UIModuleManager.cpp
index 4b2ce648..353e9053 100644
--- a/src/ui/UIModuleManager.cpp
+++ b/src/ui/UIModuleManager.cpp
@@ -31,6 +31,7 @@
#include <utility>
#include "core/module/ModuleManager.h"
+#include "core/utils/CommonUtils.h"
namespace GpgFrontend::UI {
@@ -101,4 +102,84 @@ auto MountedUIEntry::GetMetaDataByDefault(
if (!meta_data_.contains(key)) return default_value;
return meta_data_[key];
}
+
+auto UIModuleManager::RegisterTranslatorDataReader(
+ Module::ModuleIdentifier id, GFTranslatorDataReader reader) -> bool {
+ if (reader != nullptr && !id.isEmpty() && Module::IsModuleExists(id)) {
+ LOG_D() << "module " << id << "registering translator reader...";
+ translator_data_readers_[id] = ModuleTranslatorInfo{reader};
+ return true;
+ }
+ return false;
+}
+
+void UIModuleManager::RegisterAllModuleTranslators() {
+ registered_translators_.clear();
+ read_translator_data_list_.clear();
+
+ const auto locale_name = QLocale().name();
+
+#if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0)
+ for (const auto& reader : translator_data_readers_.asKeyValueRange()) {
+ char* data = nullptr;
+
+ auto data_size = reader.second.reader_(GFStrDup(locale_name), &data);
+ LOG_D() << "module " << reader.first << "reader, read locale "
+ << locale_name << ", data size: " << data_size;
+#else
+ for (auto it = translator_data_readers_.keyValueBegin();
+ it != translator_data_readers_.keyValueEnd(); ++it) {
+ char* data = nullptr;
+
+ auto data_size = it->second.reader_(GFStrDup(locale_name), &data);
+ LOG_D() << "module " << it->first << "reader, read locale " << locale_name
+ << ", data size: " << data_size;
+#endif
+
+ if (data == nullptr) continue;
+
+ if (data_size <= 0) {
+ SecureFree(data);
+ continue;
+ }
+
+ QByteArray b(data, data_size);
+ SecureFree(data);
+
+ auto* translator = new QTranslator(QCoreApplication::instance());
+ auto load = translator->load(
+ reinterpret_cast<uchar*>(const_cast<char*>(b.data())), b.size());
+ if (load && QCoreApplication::installTranslator(translator)) {
+ registered_translators_.append(translator);
+ read_translator_data_list_.append(b);
+ } else {
+ translator->deleteLater();
+ }
+ }
+}
+
+void UIModuleManager::TranslateAllModulesParams() {
+#if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0)
+ for (auto entry : mounted_entries_.asKeyValueRange()) {
+ for (auto& m_entry : entry.second) {
+ for (auto param : m_entry.meta_data_.asKeyValueRange()) {
+ m_entry.meta_data_[param.first] =
+ QApplication::translate("GTrC", param.second.toUtf8());
+ }
+ }
+ }
+#else
+ for (auto it = mounted_entries_.keyValueBegin();
+ it != mounted_entries_.keyValueEnd(); ++it) {
+ for (auto& m_entry : it->second) {
+ for (auto it_p = m_entry.meta_data_.keyValueBegin();
+ it_p != m_entry.meta_data_.keyValueEnd(); ++it_p) {
+ m_entry.meta_data_[it_p->first] =
+ QApplication::translate("GTrC", it_p->second.toUtf8());
+ }
+ }
+ }
+#endif
+}
+
} // namespace GpgFrontend::UI \ No newline at end of file
diff --git a/src/ui/UIModuleManager.h b/src/ui/UIModuleManager.h
index bef3768d..392222d6 100644
--- a/src/ui/UIModuleManager.h
+++ b/src/ui/UIModuleManager.h
@@ -30,6 +30,8 @@
#include "GpgFrontendUIExport.h"
#include "core/function/basic/GpgFunctionObject.h"
+#include "core/module/Module.h"
+#include "sdk/GFSDKBasic.h"
#include "sdk/GFSDKUI.h"
#include "ui/struct/UIMountPoint.h"
@@ -48,6 +50,10 @@ struct MountedUIEntry {
const QString& key, QString default_value) const -> QString;
};
+struct ModuleTranslatorInfo {
+ GFTranslatorDataReader reader_;
+};
+
class GPGFRONTEND_UI_EXPORT UIModuleManager
: public SingletonFunctionObject<UIModuleManager> {
public:
@@ -95,9 +101,32 @@ class GPGFRONTEND_UI_EXPORT UIModuleManager
*/
auto QueryMountedEntries(QString id) -> QList<MountedUIEntry>;
+ /**
+ * @brief
+ *
+ * @return auto
+ */
+ auto RegisterTranslatorDataReader(Module::ModuleIdentifier id,
+ GFTranslatorDataReader reader) -> bool;
+
+ /**
+ * @brief
+ *
+ */
+ void RegisterAllModuleTranslators();
+
+ /**
+ * @brief
+ *
+ */
+ void TranslateAllModulesParams();
+
private:
QMap<QString, UIMountPoint> mount_points_;
QMap<QString, QList<MountedUIEntry>> mounted_entries_;
+ QMap<QString, ModuleTranslatorInfo> translator_data_readers_;
+ QList<QTranslator*> registered_translators_;
+ QList<QByteArray> read_translator_data_list_;
};
} // namespace GpgFrontend::UI \ No newline at end of file
diff --git a/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp b/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp
index 2e9e4150..711e6784 100644
--- a/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp
+++ b/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp
@@ -120,6 +120,7 @@ KeyPairDetailTab::KeyPairDetailTab(const QString& key_id, QWidget* parent)
fingerprint_var_label_->setTextInteractionFlags(Qt::TextSelectableByMouse);
fingerprint_var_label_->setStyleSheet("margin-left: 0; margin-right: 5;");
fingerprint_var_label_->setAlignment(Qt::AlignCenter);
+ fingerprint_var_label_->setMinimumWidth(400);
auto* hbox_fp = new QHBoxLayout();
hbox_fp->addStretch();
@@ -264,6 +265,7 @@ void KeyPairDetailTab::slot_refresh_key_info() {
algorithm_var_label_->setText(key_algo_val);
algorithm_detail_var_label_->setText(key_algo_detail_val);
fingerprint_var_label_->setText(BeautifyFingerprint(key_.GetFingerprint()));
+ fingerprint_var_label_->setWordWrap(true); // for x448 and ed448
icon_label_->hide();
exp_label_->hide();
diff --git a/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp b/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp
index bb7972ae..c008206f 100644
--- a/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp
+++ b/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp
@@ -156,8 +156,8 @@ void KeyPairSubkeyTab::create_subkey_list() {
subkey_list_->setAlternatingRowColors(true);
QStringList labels;
- labels << tr("Subkey ID") << tr("Key Size") << tr("Algo") << tr("Create Date")
- << tr("Expire Date");
+ labels << tr("Subkey ID") << tr("Key Size") << tr("Algorithm")
+ << tr("Algorithm Detail") << tr("Create Date") << tr("Expire Date");
subkey_list_->setHorizontalHeaderLabels(labels);
subkey_list_->horizontalHeader()->setStretchLastSection(false);
@@ -190,17 +190,21 @@ void KeyPairSubkeyTab::slot_refresh_subkey_list() {
tmp2->setTextAlignment(Qt::AlignCenter);
subkey_list_->setItem(row, 2, tmp2);
- auto* tmp3 =
- new QTableWidgetItem(QLocale().toString(subkeys.GetCreateTime()));
+ auto* tmp3 = new QTableWidgetItem(subkeys.GetKeyAlgo());
tmp3->setTextAlignment(Qt::AlignCenter);
subkey_list_->setItem(row, 3, tmp3);
auto* tmp4 =
+ new QTableWidgetItem(QLocale().toString(subkeys.GetCreateTime()));
+ tmp4->setTextAlignment(Qt::AlignCenter);
+ subkey_list_->setItem(row, 4, tmp4);
+
+ auto* tmp5 =
new QTableWidgetItem(subkeys.GetExpireTime().toSecsSinceEpoch() == 0
? tr("Never Expire")
: QLocale().toString(subkeys.GetExpireTime()));
- tmp4->setTextAlignment(Qt::AlignCenter);
- subkey_list_->setItem(row, 4, tmp4);
+ tmp5->setTextAlignment(Qt::AlignCenter);
+ subkey_list_->setItem(row, 5, tmp5);
if (!row) {
for (auto i = 0; i < subkey_list_->columnCount(); i++) {
@@ -292,6 +296,7 @@ void KeyPairSubkeyTab::slot_refresh_subkey_detail() {
}
fingerprint_var_label_->setText(BeautifyFingerprint(subkey.GetFingerprint()));
+ fingerprint_var_label_->setWordWrap(true); // for x448 and ed448
}
void KeyPairSubkeyTab::create_subkey_opera_menu() {