diff options
author | saturneric <[email protected]> | 2025-04-18 17:11:40 +0000 |
---|---|---|
committer | saturneric <[email protected]> | 2025-04-18 17:11:40 +0000 |
commit | 502a43488d51c88be33d95be11ba8f160c2a3fd4 (patch) | |
tree | 87ee50bc5fdb1ca89d71ccfc988b1e6f67550f83 | |
parent | feat: add more info check (diff) | |
download | GpgFrontend-502a43488d51c88be33d95be11ba8f160c2a3fd4.tar.gz GpgFrontend-502a43488d51c88be33d95be11ba8f160c2a3fd4.zip |
feat: add more basic env checks at init
-rw-r--r-- | src/core/GpgCoreInit.cpp | 63 | ||||
-rw-r--r-- | src/core/function/gpg/GpgAutomatonHandler.h | 3 | ||||
-rw-r--r-- | src/core/model/GpgKeyGenerateInfo.cpp | 26 | ||||
-rw-r--r-- | src/core/model/GpgKeyGenerateInfo.h | 6 | ||||
-rw-r--r-- | src/core/utils/GpgUtils.cpp | 19 | ||||
-rw-r--r-- | src/core/utils/GpgUtils.h | 6 | ||||
-rw-r--r-- | src/ui/UserInterfaceUtils.cpp | 8 | ||||
-rw-r--r-- | src/ui/UserInterfaceUtils.h | 7 | ||||
-rw-r--r-- | src/ui/dialog/key_generate/KeyGenerateDialog.cpp | 9 | ||||
-rw-r--r-- | src/ui/dialog/key_generate/SubkeyGenerateDialog.cpp | 7 | ||||
-rw-r--r-- | src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp | 14 | ||||
-rw-r--r-- | src/ui/main_window/KeyMgmt.cpp | 19 | ||||
-rw-r--r-- | src/ui/main_window/MainWindow.cpp | 21 |
13 files changed, 174 insertions, 34 deletions
diff --git a/src/core/GpgCoreInit.cpp b/src/core/GpgCoreInit.cpp index ff9bb231..1735c316 100644 --- a/src/core/GpgCoreInit.cpp +++ b/src/core/GpgCoreInit.cpp @@ -387,6 +387,60 @@ auto DecideGnuPGPath(const QString& default_gnupg_path) -> QString { return default_gnupg_path; } +void EnsureGpgAgentConfHasPinentry(GpgContext& ctx) { + auto pinentry_path = DecidePinentry(); + if (pinentry_path.isEmpty()) { + LOG_W() << "no suitable pinentry found."; + return; + } + + QDir gnupg_dir(ctx.HomeDirectory()); + if (!gnupg_dir.exists()) { + gnupg_dir.mkpath("."); + } + + QString config_path = gnupg_dir.filePath("gpg-agent.conf"); + QFile config_file(config_path); + QStringList lines; + + LOG_D() << "checking pinentry config at:" << gnupg_dir; + + bool has_pinentry_line = false; + if (config_file.exists()) { + if (config_file.open(QIODevice::ReadOnly | QIODevice::Text)) { + QTextStream in(&config_file); + while (!in.atEnd()) { + QString line = in.readLine(); + if (line.trimmed().startsWith("pinentry-program")) { + has_pinentry_line = true; + } + lines.append(line); + } + config_file.close(); + } + } + + if (!has_pinentry_line) { + lines.append(QString("pinentry-program %1").arg(pinentry_path)); + if (config_file.open(QIODevice::WriteOnly | QIODevice::Text)) { + QTextStream out(&config_file); + for (const QString& line : lines) { + out << line << '\n'; + } + config_file.close(); + LOG_D() << "updated gpg-agent.conf with pinentry:" << pinentry_path; + + // reload configure + GpgAdvancedOperator::GetInstance(ctx.GetChannel()) + .ReloadAllGpgComponents(); + } else { + LOG_W() << "failed to write to gpg-agent.conf"; + } + } else { + LOG_D() << "gpg-agent.conf already contains pinentry-program"; + } +} + auto InitBasicPath() -> bool { auto default_gpgconf_path = Module::RetrieveRTValueTypedOrDefault<>( "core", "gpgme.ctx.gpgconf_path", QString{}); @@ -548,6 +602,7 @@ auto InitGpgFrontendCore(CoreInitArgs args) -> int { return ConvertToChannelObjectPtr<>(SecureCreateUniqueObject<GpgContext>( args, kGpgFrontendDefaultChannel)); }); + if (!default_ctx.Good()) { LOG_E() << "Init GpgME Default Context failed!" << "GpgFrontend cannot start under this situation!"; @@ -557,6 +612,10 @@ auto InitGpgFrontendCore(CoreInitArgs args) -> int { return -1; } +#if defined(__linux__) + EnsureGpgAgentConfHasPinentry(default_ctx); +#endif + Module::UpsertRTValue("core", "env.state.ctx", 1); if (!GpgKeyGetter::GetInstance(kGpgFrontendDefaultChannel).FlushKeyCache()) { @@ -606,6 +665,10 @@ auto InitGpgFrontendCore(CoreInitArgs args) -> int { continue; } +#if defined(__linux__) + EnsureGpgAgentConfHasPinentry(ctx); +#endif + if (!GpgKeyGetter::GetInstance(ctx.GetChannel()).FlushKeyCache()) { LOG_E() << "gpgme context init key cache failed, index:" << channel_index; diff --git a/src/core/function/gpg/GpgAutomatonHandler.h b/src/core/function/gpg/GpgAutomatonHandler.h index 7ab2bf44..34c23455 100644 --- a/src/core/function/gpg/GpgAutomatonHandler.h +++ b/src/core/function/gpg/GpgAutomatonHandler.h @@ -28,14 +28,13 @@ #pragma once -#include "core/GpgFrontendCore.h" #include "core/function/basic/GpgFunctionObject.h" #include "core/function/gpg/GpgContext.h" #include "core/typedef/GpgTypedef.h" namespace GpgFrontend { -class GpgAutomatonHandler +class GPGFRONTEND_CORE_EXPORT GpgAutomatonHandler : public SingletonFunctionObject<GpgAutomatonHandler> { public: using Command = QString; diff --git a/src/core/model/GpgKeyGenerateInfo.cpp b/src/core/model/GpgKeyGenerateInfo.cpp index b1dcaa7a..0d8aa23c 100644 --- a/src/core/model/GpgKeyGenerateInfo.cpp +++ b/src/core/model/GpgKeyGenerateInfo.cpp @@ -30,8 +30,9 @@ #include <cassert> -#include "module/ModuleManager.h" -#include "utils/CommonUtils.h" +#include "core/module/ModuleManager.h" +#include "core/utils/CommonUtils.h" +#include "core/utils/GpgUtils.h" namespace GpgFrontend { @@ -98,14 +99,12 @@ const QContainer<KeyAlgo> KeyGenerateInfo::kSubKeyAlgos = { {"elg4096", "ELG-E", "ELG-E", 4096, kENCRYPT, "2.2.0"}, }; -auto KeyGenerateInfo::GetSupportedKeyAlgo() -> QContainer<KeyAlgo> { - const auto gnupg_version = Module::RetrieveRTValueTypedOrDefault<>( - "core", "gpgme.ctx.gnupg_version", QString{"2.0.0"}); - +auto KeyGenerateInfo::GetSupportedKeyAlgo(int channel) -> QContainer<KeyAlgo> { QContainer<KeyAlgo> algos; for (const auto &algo : kPrimaryKeyAlgos) { - if (!algo.IsSupported(gnupg_version)) continue; + if (!CheckGpgVersion(channel, algo.SupportedVersion())) continue; + algos.append(algo); } @@ -116,14 +115,13 @@ auto KeyGenerateInfo::GetSupportedKeyAlgo() -> QContainer<KeyAlgo> { return algos; } -auto KeyGenerateInfo::GetSupportedSubkeyAlgo() -> QContainer<KeyAlgo> { - const auto gnupg_version = Module::RetrieveRTValueTypedOrDefault<>( - "core", "gpgme.ctx.gnupg_version", QString{"2.0.0"}); - +auto KeyGenerateInfo::GetSupportedSubkeyAlgo(int channel) + -> QContainer<KeyAlgo> { QContainer<KeyAlgo> algos; for (const auto &algo : kSubKeyAlgos) { - if (!algo.IsSupported(gnupg_version)) continue; + if (!CheckGpgVersion(channel, algo.SupportedVersion())) continue; + algos.append(algo); } @@ -490,9 +488,7 @@ auto KeyAlgo::CanAuth() const -> bool { return auth_; } auto KeyAlgo::CanCert() const -> bool { return cert_; } -auto KeyAlgo::IsSupported(const QString &version) const -> bool { - return GFCompareSoftwareVersion(version, supported_version_) >= 0; -} +auto KeyAlgo::SupportedVersion() const -> QString { return supported_version_; } auto KeyAlgo::operator==(const KeyAlgo &o) const -> bool { return this->id_ == o.id_; diff --git a/src/core/model/GpgKeyGenerateInfo.h b/src/core/model/GpgKeyGenerateInfo.h index 2956a00d..b3f3b2c7 100644 --- a/src/core/model/GpgKeyGenerateInfo.h +++ b/src/core/model/GpgKeyGenerateInfo.h @@ -62,7 +62,7 @@ class GPGFRONTEND_CORE_EXPORT KeyAlgo { [[nodiscard]] auto CanCert() const -> bool; - [[nodiscard]] auto IsSupported(const QString &version) const -> bool; + [[nodiscard]] auto SupportedVersion() const -> QString; private: QString id_; @@ -96,14 +96,14 @@ class GPGFRONTEND_CORE_EXPORT KeyGenerateInfo : public QObject { * * @return const QContainer<KeyGenAlgo>& */ - static auto GetSupportedKeyAlgo() -> QContainer<KeyAlgo>; + static auto GetSupportedKeyAlgo(int channel) -> QContainer<KeyAlgo>; /** * @brief Get the Supported Subkey Algo object * * @return const QContainer<KeyGenAlgo>& */ - static auto GetSupportedSubkeyAlgo() -> QContainer<KeyAlgo>; + static auto GetSupportedSubkeyAlgo(int channel) -> QContainer<KeyAlgo>; /** * @brief diff --git a/src/core/utils/GpgUtils.cpp b/src/core/utils/GpgUtils.cpp index 13f6ef05..8b2abeb7 100644 --- a/src/core/utils/GpgUtils.cpp +++ b/src/core/utils/GpgUtils.cpp @@ -456,4 +456,23 @@ auto GPGFRONTEND_CORE_EXPORT CheckGpgVersion(int channel, return true; } + +auto GPGFRONTEND_CORE_EXPORT DecidePinentry() -> QString { +#ifdef __linux__ + QStringList preferred_list = {"pinentry-gnome3", + "pinentry-qt" + "pinentry-gtk2"}; +#else + QStringList preferred_list = {"pinentry-qt"}; +#endif + + for (const QString& name : preferred_list) { + QString path = QStandardPaths::findExecutable(name); + if (!path.isEmpty()) { + return path; + } + } + + return {}; +} } // namespace GpgFrontend diff --git a/src/core/utils/GpgUtils.h b/src/core/utils/GpgUtils.h index d0fe1701..f005bbfc 100644 --- a/src/core/utils/GpgUtils.h +++ b/src/core/utils/GpgUtils.h @@ -221,4 +221,10 @@ auto GPGFRONTEND_CORE_EXPORT GpgAgentVersionGreaterThan(int channel, auto GPGFRONTEND_CORE_EXPORT CheckGpgVersion(int channel, const QString&) -> bool; +/** + * @brief + * + * @return QString + */ +auto GPGFRONTEND_CORE_EXPORT DecidePinentry() -> QString; } // namespace GpgFrontend
\ No newline at end of file diff --git a/src/ui/UserInterfaceUtils.cpp b/src/ui/UserInterfaceUtils.cpp index ed76824a..b5747b9f 100644 --- a/src/ui/UserInterfaceUtils.cpp +++ b/src/ui/UserInterfaceUtils.cpp @@ -167,6 +167,14 @@ void CommonUtils::RaiseMessageBox(QWidget *parent, GpgError err) { } } +void CommonUtils::RaiseMessageBoxNotSupported(QWidget *parent) { + QMessageBox::warning( + parent, QObject::tr("Operation Not Supported"), + QObject::tr( + "The current GnuPG version is too low and does not support this " + "operation. Please upgrade your GnuPG version to continue.")); +} + void CommonUtils::RaiseFailureMessageBox(QWidget *parent, GpgError err, const QString &msg) { GpgErrorDesc desc = DescribeGpgErrCode(err); diff --git a/src/ui/UserInterfaceUtils.h b/src/ui/UserInterfaceUtils.h index b544ffc3..86b83e7f 100644 --- a/src/ui/UserInterfaceUtils.h +++ b/src/ui/UserInterfaceUtils.h @@ -113,6 +113,13 @@ class CommonUtils : public QWidget { * * @param err */ + static void RaiseMessageBoxNotSupported(QWidget* parent); + + /** + * @brief + * + * @param err + */ static void RaiseFailureMessageBox(QWidget* parent, GpgError err, const QString& msg = {}); diff --git a/src/ui/dialog/key_generate/KeyGenerateDialog.cpp b/src/ui/dialog/key_generate/KeyGenerateDialog.cpp index d738029d..df8b5232 100644 --- a/src/ui/dialog/key_generate/KeyGenerateDialog.cpp +++ b/src/ui/dialog/key_generate/KeyGenerateDialog.cpp @@ -49,8 +49,9 @@ KeyGenerateDialog::KeyGenerateDialog(int channel, QWidget* parent) ui_(QSharedPointer<Ui_KeyGenDialog>::create()), gen_key_info_(QSharedPointer<KeyGenerateInfo>::create()), gen_subkey_info_(nullptr), - supported_primary_key_algos_(KeyGenerateInfo::GetSupportedKeyAlgo()), - supported_subkey_algos_(KeyGenerateInfo::GetSupportedSubkeyAlgo()), + supported_primary_key_algos_( + KeyGenerateInfo::GetSupportedKeyAlgo(channel)), + supported_subkey_algos_(KeyGenerateInfo::GetSupportedSubkeyAlgo(channel)), channel_(channel) { ui_->setupUi(this); @@ -146,6 +147,10 @@ KeyGenerateDialog::KeyGenerateDialog(int channel, QWidget* parent) this->setWindowTitle(tr("Generate Key")); this->setAttribute(Qt::WA_DeleteOnClose); this->setModal(true); + + this->show(); + this->raise(); + this->activateWindow(); } void KeyGenerateDialog::slot_key_gen_accept() { diff --git a/src/ui/dialog/key_generate/SubkeyGenerateDialog.cpp b/src/ui/dialog/key_generate/SubkeyGenerateDialog.cpp index fd592733..68c68765 100644 --- a/src/ui/dialog/key_generate/SubkeyGenerateDialog.cpp +++ b/src/ui/dialog/key_generate/SubkeyGenerateDialog.cpp @@ -50,7 +50,8 @@ SubkeyGenerateDialog::SubkeyGenerateDialog(int channel, GpgKeyPtr key, current_gpg_context_channel_(channel), key_(std::move(key)), gen_subkey_info_(QSharedPointer<KeyGenerateInfo>::create(true)), - supported_subkey_algos_(KeyGenerateInfo::GetSupportedSubkeyAlgo()) { + supported_subkey_algos_(KeyGenerateInfo::GetSupportedSubkeyAlgo( + current_gpg_context_channel_)) { ui_->setupUi(this); assert(key_ != nullptr); @@ -88,6 +89,10 @@ SubkeyGenerateDialog::SubkeyGenerateDialog(int channel, GpgKeyPtr key, set_signal_slot_config(); refresh_widgets_state(); + + this->show(); + this->raise(); + this->activateWindow(); } void SubkeyGenerateDialog::set_signal_slot_config() { diff --git a/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp b/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp index 73e7f4e5..b8942b94 100644 --- a/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp +++ b/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp @@ -66,6 +66,11 @@ KeyPairSubkeyTab::KeyPairSubkeyTab(int channel, GpgKeyPtr key, QWidget* parent) add_adsk_button->hide(); } + if (!CheckGpgVersion(channel, "2.4.1")) { + add_adsk_button->setDisabled(true); + add_adsk_button->hide(); + } + uid_buttons_layout->addWidget(add_subkey_button, 0, 0); uid_buttons_layout->addWidget(add_adsk_button, 0, 1); @@ -277,9 +282,12 @@ void KeyPairSubkeyTab::slot_refresh_subkey_list() { } void KeyPairSubkeyTab::slot_add_subkey() { - auto* dialog = - new SubkeyGenerateDialog(current_gpg_context_channel_, key_, this); - dialog->show(); + if (!CheckGpgVersion(current_gpg_context_channel_, "2.2.0")) { + CommonUtils::RaiseMessageBoxNotSupported(this); + return; + } + + new SubkeyGenerateDialog(current_gpg_context_channel_, key_, this); } void KeyPairSubkeyTab::slot_add_adsk() { diff --git a/src/ui/main_window/KeyMgmt.cpp b/src/ui/main_window/KeyMgmt.cpp index e3128231..f9364ecf 100644 --- a/src/ui/main_window/KeyMgmt.cpp +++ b/src/ui/main_window/KeyMgmt.cpp @@ -428,12 +428,20 @@ void KeyMgmt::SlotExportKeyToClipboard() { } void KeyMgmt::SlotGenerateKeyDialog() { - (new KeyGenerateDialog(key_list_->GetCurrentGpgContextChannel(), this)) - ->exec(); - this->raise(); + if (!CheckGpgVersion(key_list_->GetCurrentGpgContextChannel(), "2.2.0")) { + CommonUtils::RaiseMessageBoxNotSupported(this); + return; + } + + new KeyGenerateDialog(key_list_->GetCurrentGpgContextChannel(), this); } void KeyMgmt::SlotGenerateSubKey() { + if (!CheckGpgVersion(key_list_->GetCurrentGpgContextChannel(), "2.2.0")) { + CommonUtils::RaiseMessageBoxNotSupported(this); + return; + } + auto key = key_list_->GetSelectedGpgKey(); if (key == nullptr) return; @@ -444,10 +452,7 @@ void KeyMgmt::SlotGenerateSubKey() { return; } - (new SubkeyGenerateDialog(key_list_->GetCurrentGpgContextChannel(), key, - this)) - ->exec(); - this->raise(); + new SubkeyGenerateDialog(key_list_->GetCurrentGpgContextChannel(), key, this); } void KeyMgmt::SlotExportAsOpenSSHFormat() { diff --git a/src/ui/main_window/MainWindow.cpp b/src/ui/main_window/MainWindow.cpp index 104f54d8..4b5c71f5 100644 --- a/src/ui/main_window/MainWindow.cpp +++ b/src/ui/main_window/MainWindow.cpp @@ -31,6 +31,8 @@ #include "core/function/GlobalSettingStation.h" #include "core/model/SettingsObject.h" #include "core/module/ModuleManager.h" +#include "core/utils/CommonUtils.h" +#include "core/utils/GpgUtils.h" #include "ui/UISignalStation.h" #include "ui/main_window/GeneralMainWindow.h" #include "ui/struct/settings_object/AppearanceSO.h" @@ -115,6 +117,24 @@ void MainWindow::Init() noexcept { &UISignalStation::SignalMainWindowOpenFile, this, &MainWindow::SlotOpenFile); +#if defined(__linux__) + connect(this, &MainWindow::SignalLoaded, this, [=]() { + QTimer::singleShot(3000, [self = QPointer<MainWindow>(this)]() { + if (self != nullptr && DecidePinentry().isEmpty() && !IsFlatpakENV()) { + QMessageBox::warning( + self, QObject::tr("Pinentry Not Found"), + QObject::tr( + "No suitable pinentry program was found on your system.\n\n" + "Please install 'pinentry-qt' or another compatible pinentry " + "(e.g., pinentry-gnome3, pinentry-gtk2).\n\n" + "Without it, GnuPG cannot prompt for passwords.\n\n" + "Once you have installed it, please restart GpgFrontend. " + "The configuration file will be updated automatically.")); + } + }); + }); +#endif + popup_menu_ = new QMenu(this); popup_menu_->addAction(append_selected_keys_act_); @@ -152,7 +172,6 @@ void MainWindow::Init() noexcept { // loading process is done emit SignalLoaded(); Module::TriggerEvent("APPLICATION_LOADED"); - } catch (...) { LOG_W() << tr("Critical error occur while loading GpgFrontend."); QMessageBox::critical( |