aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsaturneric <[email protected]>2025-04-18 17:11:40 +0000
committersaturneric <[email protected]>2025-04-18 17:11:40 +0000
commit502a43488d51c88be33d95be11ba8f160c2a3fd4 (patch)
tree87ee50bc5fdb1ca89d71ccfc988b1e6f67550f83
parentfeat: add more info check (diff)
downloadGpgFrontend-502a43488d51c88be33d95be11ba8f160c2a3fd4.tar.gz
GpgFrontend-502a43488d51c88be33d95be11ba8f160c2a3fd4.zip
feat: add more basic env checks at init
-rw-r--r--src/core/GpgCoreInit.cpp63
-rw-r--r--src/core/function/gpg/GpgAutomatonHandler.h3
-rw-r--r--src/core/model/GpgKeyGenerateInfo.cpp26
-rw-r--r--src/core/model/GpgKeyGenerateInfo.h6
-rw-r--r--src/core/utils/GpgUtils.cpp19
-rw-r--r--src/core/utils/GpgUtils.h6
-rw-r--r--src/ui/UserInterfaceUtils.cpp8
-rw-r--r--src/ui/UserInterfaceUtils.h7
-rw-r--r--src/ui/dialog/key_generate/KeyGenerateDialog.cpp9
-rw-r--r--src/ui/dialog/key_generate/SubkeyGenerateDialog.cpp7
-rw-r--r--src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp14
-rw-r--r--src/ui/main_window/KeyMgmt.cpp19
-rw-r--r--src/ui/main_window/MainWindow.cpp21
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(