From 8f14fdc7325cb9635e3d92873baaa58f430fca01 Mon Sep 17 00:00:00 2001 From: saturneric Date: Fri, 18 Apr 2025 17:54:54 +0200 Subject: feat: add more info check --- src/core/GpgCoreInit.cpp | 35 ++-- src/core/function/gpg/GpgAdvancedOperator.cpp | 93 +++------- src/core/function/gpg/GpgAdvancedOperator.h | 28 ++- src/core/function/gpg/GpgAssuanHelper.cpp | 38 +++-- src/core/function/gpg/GpgAssuanHelper.h | 6 +- src/core/function/gpg/GpgAutomatonHandler.cpp | 69 ++++---- src/core/function/gpg/GpgAutomatonHandler.h | 8 +- src/core/function/gpg/GpgBasicOperator.cpp | 44 +++-- src/core/function/gpg/GpgCommandExecutor.cpp | 190 ++++++++++++++------- src/core/function/gpg/GpgCommandExecutor.h | 70 +++++++- src/core/function/gpg/GpgComponentInfoGetter.cpp | 64 +++++++ src/core/function/gpg/GpgComponentInfoGetter.h | 72 ++++++++ src/core/function/gpg/GpgFileOpera.cpp | 61 ++++--- src/core/function/gpg/GpgKeyImportExporter.cpp | 2 + src/core/function/gpg/GpgKeyManager.cpp | 26 ++- src/core/function/gpg/GpgKeyManager.h | 3 + src/core/function/gpg/GpgKeyOpera.cpp | 36 ++-- src/core/function/gpg/GpgSmartCardManager.cpp | 96 +++++------ src/core/function/gpg/GpgSmartCardManager.h | 16 +- src/core/function/gpg/GpgUIDOperator.cpp | 19 +-- src/core/function/gpg/GpgUIDOperator.h | 3 + src/core/utils/AsyncUtils.cpp | 28 ++- src/core/utils/AsyncUtils.h | 12 +- src/core/utils/CommonUtils.cpp | 5 + src/core/utils/CommonUtils.h | 10 ++ src/core/utils/GpgUtils.cpp | 32 ++++ src/core/utils/GpgUtils.h | 19 +++ src/init.cpp | 10 +- src/ui/UserInterfaceUtils.cpp | 13 +- src/ui/UserInterfaceUtils.h | 3 +- src/ui/dialog/ADSKsPicker.cpp | 3 +- .../controller/SmartCardControllerDialog.cpp | 73 ++++---- src/ui/function/GpgOperaHelper.cpp | 22 +++ src/ui/main_window/MainWindow.h | 2 +- src/ui/main_window/MainWindowSlotUI.cpp | 80 +++++---- 35 files changed, 826 insertions(+), 465 deletions(-) create mode 100644 src/core/function/gpg/GpgComponentInfoGetter.cpp create mode 100644 src/core/function/gpg/GpgComponentInfoGetter.h diff --git a/src/core/GpgCoreInit.cpp b/src/core/GpgCoreInit.cpp index b544d071..ff9bb231 100644 --- a/src/core/GpgCoreInit.cpp +++ b/src/core/GpgCoreInit.cpp @@ -225,17 +225,17 @@ auto InitGpgME() -> bool { "core", "gpgme.ctx.gnupg_version", QString{}); if (!has_gpgconf) { - FLOG_E() << "cannot get gpgconf backend engine, abort..."; + LOG_E() << "cannot get gpgconf backend engine, abort..."; return false; } if (!has_openpgp) { - FLOG_E() << "cannot get openpgp backend engine, abort..."; + LOG_E() << "cannot get openpgp backend engine, abort..."; return false; } if (!has_cms) { - FLOG_E() << "cannot get cms backend engine, abort..."; + LOG_E() << "cannot get cms backend engine, abort..."; return false; } @@ -520,8 +520,8 @@ auto InitGpgFrontendCore(CoreInitArgs args) -> int { assert(!key_dbs.isEmpty()); if (key_dbs.isEmpty()) { - FLOG_E() << "Cannot find any valid key database!" - << "GpgFrontend cannot start under this situation!"; + LOG_E() << "Cannot find any valid key database!" + << "GpgFrontend cannot start under this situation!"; Module::UpsertRTValue("core", "env.state.ctx", -1); CoreSignalStation::GetInstance()->SignalBadGnupgEnv( QCoreApplication::tr("No valid Key Database")); @@ -549,8 +549,8 @@ auto InitGpgFrontendCore(CoreInitArgs args) -> int { args, kGpgFrontendDefaultChannel)); }); if (!default_ctx.Good()) { - FLOG_E() << "Init GpgME Default Context failed!" - << "GpgFrontend cannot start under this situation!"; + LOG_E() << "Init GpgME Default Context failed!" + << "GpgFrontend cannot start under this situation!"; Module::UpsertRTValue("core", "env.state.ctx", -1); CoreSignalStation::GetInstance()->SignalBadGnupgEnv( QCoreApplication::tr("GpgME Default Context Initiation Failed")); @@ -560,8 +560,8 @@ auto InitGpgFrontendCore(CoreInitArgs args) -> int { Module::UpsertRTValue("core", "env.state.ctx", 1); if (!GpgKeyGetter::GetInstance(kGpgFrontendDefaultChannel).FlushKeyCache()) { - FLOG_E() << "Init GpgME Default Key Database failed!" - << "GpgFrontend cannot start under this situation!"; + LOG_E() << "Init GpgME Default Key Database failed!" + << "GpgFrontend cannot start under this situation!"; Module::UpsertRTValue("core", "env.state.ctx", -1); CoreSignalStation::GetInstance()->SignalBadGnupgEnv( QCoreApplication::tr("Gpg Default Key Database Initiation Failed")); @@ -602,13 +602,13 @@ auto InitGpgFrontendCore(CoreInitArgs args) -> int { }); if (!ctx.Good()) { - FLOG_E() << "gpgme context init failed, index:" << channel_index; + LOG_E() << "gpgme context init failed, index:" << channel_index; continue; } if (!GpgKeyGetter::GetInstance(ctx.GetChannel()).FlushKeyCache()) { - FLOG_E() << "gpgme context init key cache failed, index:" - << channel_index; + LOG_E() << "gpgme context init key cache failed, index:" + << channel_index; continue; } @@ -631,9 +631,16 @@ auto InitGpgFrontendCore(CoreInitArgs args) -> int { .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_Default) ->PostTask(task); - if (!args.unit_test_mode && restart_all_gnupg_components_on_start) { - GpgAdvancedOperator::RestartGpgComponents(nullptr); + const auto size = GpgContext::GetAllChannelId().size(); + for (auto i = 0; i < size; i++) { + if (!args.unit_test_mode && restart_all_gnupg_components_on_start) { + assert(GpgAdvancedOperator::GetInstance().RestartGpgComponents()); + } else { + // ensure gpg-agent is running + assert(GpgAdvancedOperator::GetInstance().LaunchAllGpgComponents()); + } } + return 0; } diff --git a/src/core/function/gpg/GpgAdvancedOperator.cpp b/src/core/function/gpg/GpgAdvancedOperator.cpp index 492297c6..c9af8b59 100644 --- a/src/core/function/gpg/GpgAdvancedOperator.cpp +++ b/src/core/function/gpg/GpgAdvancedOperator.cpp @@ -33,91 +33,38 @@ #include "GpgAdvancedOperator.h" #include "core/function/gpg/GpgCommandExecutor.h" -#include "core/module/ModuleManager.h" -#include "core/utils/GpgUtils.h" - namespace GpgFrontend { -void ExecuteGpgCommand(const QString &operation, const QStringList &extra_args, - OperationCallback cb) { - const auto gpgconf_path = Module::RetrieveRTValueTypedOrDefault<>( - "core", "gpgme.ctx.gpgconf_path", QString{}); - - if (gpgconf_path.isEmpty()) { - FLOG_W("cannot get valid gpgconf path from rt, abort."); - if (cb) cb(-1, TransferParams()); - return; - } - - auto key_dbs = GetGpgKeyDatabaseInfos(); - auto total_tasks = static_cast(key_dbs.size()); - std::atomic completed_tasks{0}; - std::vector results(total_tasks, 0); - - // kill default gpg-agent - key_dbs.push_back({}); - - int task_index = 0; - for (const auto &key_db : key_dbs) { - const int current_index = task_index++; - const auto target_home_dir = - QDir::toNativeSeparators(QFileInfo(key_db.path).canonicalFilePath()); - - QStringList arguments = !target_home_dir.isEmpty() - ? QStringList{"--homedir", target_home_dir} - : QStringList{}; - arguments.append(extra_args); - - GpgCommandExecutor::ExecuteSync( - {gpgconf_path, arguments, - [=, &completed_tasks, &results](int exit_code, const QString &, - const QString &) { - FLOG_D("%s exit code: %d", qPrintable(operation), exit_code); - - results[current_index] = exit_code; - - if (++completed_tasks == total_tasks && cb) { - int final_result = - std::all_of(results.begin(), results.end(), - [](int result) { return result >= 0; }) - ? 0 - : -1; - cb(final_result, TransferParams()); - } - }}); - } -} - -void GpgAdvancedOperator::ClearGpgPasswordCache(OperationCallback cb) { - ExecuteGpgCommand("Clear GPG Password Cache", {"--reload", "gpg-agent"}, - std::move(cb)); +auto GpgAdvancedOperator::ClearGpgPasswordCache() -> bool { + auto [ret, out] = exec_.GpgConfExecuteSync({{"--reload", "gpg-agent"}}); + return ret == 0; } -void GpgAdvancedOperator::ReloadGpgComponents(OperationCallback cb) { - const auto gpgconf_path = Module::RetrieveRTValueTypedOrDefault<>( - "core", "gpgme.ctx.gpgconf_path", QString{}); - ExecuteGpgCommand("Reload GPG Components", {"--reload", "all"}, - std::move(cb)); +auto GpgAdvancedOperator::ReloadAllGpgComponents() -> bool { + auto [ret, out] = exec_.GpgConfExecuteSync({{"--reload", "all"}}); + return ret == 0; } -void GpgAdvancedOperator::KillAllGpgComponents(OperationCallback cb) { - ExecuteGpgCommand("Kill All GPG Components", {"--kill", "all"}, - std::move(cb)); +auto GpgAdvancedOperator::KillAllGpgComponents() -> bool { + auto [ret, out] = exec_.GpgConfExecuteSync({{"--kill", "all"}}); + return ret == 0; } -void GpgAdvancedOperator::ResetConfigures(OperationCallback cb) { - ExecuteGpgCommand("Reset Gnupg Configures", {"--apply-defaults"}, - std::move(cb)); +auto GpgAdvancedOperator::ResetConfigures() -> bool { + auto [ret, out] = exec_.GpgConfExecuteSync({{"--apply-defaults"}}); + return ret == 0; } -void GpgAdvancedOperator::LaunchGpgComponents(OperationCallback cb) { - ExecuteGpgCommand("Launch All GPG Components", {"--launch", "all"}, - std::move(cb)); +auto GpgAdvancedOperator::LaunchAllGpgComponents() -> bool { + auto [ret, out] = exec_.GpgConfExecuteSync({{"--launch", "all"}}); + return ret == 0; } -void GpgAdvancedOperator::RestartGpgComponents(OperationCallback cb) { - KillAllGpgComponents(nullptr); - LaunchGpgComponents(std::move(cb)); +auto GpgAdvancedOperator::RestartGpgComponents() -> bool { + if (!KillAllGpgComponents()) return false; + return LaunchAllGpgComponents(); } +GpgAdvancedOperator::GpgAdvancedOperator(int channel) + : SingletonFunctionObject(channel) {} } // namespace GpgFrontend \ No newline at end of file diff --git a/src/core/function/gpg/GpgAdvancedOperator.h b/src/core/function/gpg/GpgAdvancedOperator.h index 57279adb..1099c3b3 100644 --- a/src/core/function/gpg/GpgAdvancedOperator.h +++ b/src/core/function/gpg/GpgAdvancedOperator.h @@ -32,19 +32,29 @@ #pragma once +#include "core/function/basic/GpgFunctionObject.h" +#include "core/function/gpg/GpgCommandExecutor.h" #include "core/model/DataObject.h" namespace GpgFrontend { -class GPGFRONTEND_CORE_EXPORT GpgAdvancedOperator { +class GPGFRONTEND_CORE_EXPORT GpgAdvancedOperator + : public SingletonFunctionObject { public: + /** + * @brief Construct a new Gpg Advanced Operator object + * + * @param channel + */ + explicit GpgAdvancedOperator(int channel); + /** * @brief * * @return true * @return false */ - static void ClearGpgPasswordCache(OperationCallback); + auto ClearGpgPasswordCache() -> bool; /** * @brief @@ -52,7 +62,7 @@ class GPGFRONTEND_CORE_EXPORT GpgAdvancedOperator { * @return true * @return false */ - static void ReloadGpgComponents(OperationCallback); + auto ReloadAllGpgComponents() -> bool; /** * @brief @@ -60,7 +70,7 @@ class GPGFRONTEND_CORE_EXPORT GpgAdvancedOperator { * @return true * @return false */ - static void RestartGpgComponents(OperationCallback); + auto RestartGpgComponents() -> bool; /** * @brief @@ -68,7 +78,7 @@ class GPGFRONTEND_CORE_EXPORT GpgAdvancedOperator { * @return true * @return false */ - static void ResetConfigures(OperationCallback); + auto ResetConfigures() -> bool; /** * @brief @@ -76,13 +86,17 @@ class GPGFRONTEND_CORE_EXPORT GpgAdvancedOperator { * @return true * @return false */ - static void LaunchGpgComponents(OperationCallback); + auto LaunchAllGpgComponents() -> bool; /** * @brief * */ - static void KillAllGpgComponents(OperationCallback); + auto KillAllGpgComponents() -> bool; + + private: + GpgCommandExecutor& exec_ = + GpgCommandExecutor::GetInstance(SingletonFunctionObject::GetChannel()); }; } // namespace GpgFrontend diff --git a/src/core/function/gpg/GpgAssuanHelper.cpp b/src/core/function/gpg/GpgAssuanHelper.cpp index 0d1b9cdc..128ecaa9 100644 --- a/src/core/function/gpg/GpgAssuanHelper.cpp +++ b/src/core/function/gpg/GpgAssuanHelper.cpp @@ -44,14 +44,14 @@ GpgAssuanHelper::~GpgAssuanHelper() { } } -auto GpgAssuanHelper::ConnectToSocket(GpgComponentType type) -> bool { - if (assuan_ctx_.contains(type)) return true; +auto GpgAssuanHelper::ConnectToSocket(GpgComponentType type) -> GpgError { + if (assuan_ctx_.contains(type)) return GPG_ERR_NO_ERROR; auto socket_path = ctx_.ComponentDirectory(type); if (socket_path.isEmpty()) { LOG_W() << "socket path of component: " << component_type_to_q_string(type) << " is empty"; - return false; + return GPG_ERR_ENOPKG; } QFileInfo info(socket_path); @@ -65,7 +65,7 @@ auto GpgAssuanHelper::ConnectToSocket(GpgComponentType type) -> bool { if (!info.exists()) { LOG_W() << "socket path is still not exists: " << socket_path << "abort..."; - return false; + return GPG_ERR_ENOTSOCK; } } @@ -76,7 +76,7 @@ auto GpgAssuanHelper::ConnectToSocket(GpgComponentType type) -> bool { ASSUAN_INVALID_PID, 0); if (err != GPG_ERR_NO_ERROR) { LOG_W() << "failed to connect to socket:" << CheckGpgError(err); - return false; + return err; } LOG_D() << "connected to socket by assuan protocol: " @@ -86,21 +86,23 @@ auto GpgAssuanHelper::ConnectToSocket(GpgComponentType type) -> bool { nullptr, nullptr, nullptr, nullptr); if (err != GPG_ERR_NO_ERROR) { LOG_W() << "failed to test assuan connection:" << CheckGpgError(err); - return false; + return err; } assuan_ctx_[type] = a_ctx; - return true; + return err; } auto GpgAssuanHelper::SendCommand(GpgComponentType type, const QString& command, DataCallback data_cb, InqueryCallback inquery_cb, - StatusCallback status_cb) -> bool { + StatusCallback status_cb) -> GpgError { if (!assuan_ctx_.contains(type)) { LOG_W() << "haven't connect to: " << component_type_to_q_string(type) << ", trying to make a connection"; - if (!ConnectToSocket(type)) return false; + + auto err = CheckGpgError(ConnectToSocket(type)); + if (err != GPG_ERR_NO_ERROR) return err; } auto context = QSharedPointer::create(); @@ -122,15 +124,15 @@ auto GpgAssuanHelper::SendCommand(GpgComponentType type, const QString& command, if (CheckGpgError(err) == 32877) { assuan_ctx_.remove(type); } - return false; + return err; } - return true; + return err; } auto GpgAssuanHelper::SendStatusCommand(GpgComponentType type, const QString& command) - -> std::tuple { + -> std::tuple { GpgAssuanHelper::DataCallback d_cb = [&](const QSharedPointer& ctx) -> gpg_error_t { @@ -147,29 +149,29 @@ auto GpgAssuanHelper::SendStatusCommand(GpgComponentType type, return 0; }; - QStringList status_lines; + QStringList lines; GpgAssuanHelper::StatusCallback s_cb = [&](const QSharedPointer& ctx) -> gpg_error_t { LOG_D() << "status callback of command: " << command << ": " << ctx->status; - status_lines.append(ctx->status); + lines.append(ctx->status); return 0; }; auto ret = SendCommand(type, command, d_cb, i_cb, s_cb); - return {ret, status_lines}; + return {ret, lines}; } auto GpgAssuanHelper::SendDataCommand(GpgComponentType type, const QString& command) -> std::tuple { - QStringList data_lines; + QStringList lines; GpgAssuanHelper::DataCallback d_cb = [&](const QSharedPointer& ctx) -> gpg_error_t { LOG_D() << "data callback of command " << command << ": " << ctx->buffer; - data_lines.push_back(QString::fromUtf8(ctx->buffer)); + lines.push_back(QString::fromUtf8(ctx->buffer)); return 0; }; @@ -192,7 +194,7 @@ auto GpgAssuanHelper::SendDataCommand(GpgComponentType type, }; auto ret = SendCommand(type, command, d_cb, i_cb, s_cb); - return {ret, data_lines}; + return {ret, lines}; } auto GpgAssuanHelper::default_data_callback(void* opaque, const void* buffer, diff --git a/src/core/function/gpg/GpgAssuanHelper.h b/src/core/function/gpg/GpgAssuanHelper.h index 294d33e0..7f3854b6 100644 --- a/src/core/function/gpg/GpgAssuanHelper.h +++ b/src/core/function/gpg/GpgAssuanHelper.h @@ -81,7 +81,7 @@ class GPGFRONTEND_CORE_EXPORT GpgAssuanHelper * @return true * @return false */ - auto ConnectToSocket(GpgComponentType) -> bool; + auto ConnectToSocket(GpgComponentType) -> GpgError; /** * @brief @@ -96,7 +96,7 @@ class GPGFRONTEND_CORE_EXPORT GpgAssuanHelper */ auto SendCommand(GpgComponentType type, const QString& command, DataCallback data_cb, InqueryCallback inquery_cb, - StatusCallback status_cb) -> bool; + StatusCallback status_cb) -> GpgError; /** * @brief @@ -106,7 +106,7 @@ class GPGFRONTEND_CORE_EXPORT GpgAssuanHelper * @return std::tuple */ auto SendStatusCommand(GpgComponentType type, const QString& command) - -> std::tuple; + -> std::tuple; /** * @brief diff --git a/src/core/function/gpg/GpgAutomatonHandler.cpp b/src/core/function/gpg/GpgAutomatonHandler.cpp index 656bb018..afa55299 100644 --- a/src/core/function/gpg/GpgAutomatonHandler.cpp +++ b/src/core/function/gpg/GpgAutomatonHandler.cpp @@ -39,65 +39,61 @@ GpgAutomatonHandler::GpgAutomatonHandler(int channel) auto InteratorCbFunc(void* handle, const char* status, const char* args, int fd) -> gpgme_error_t { - auto* handle_struct = static_cast(handle); - QString status_s = status; - QString args_s = args; + auto* handel = static_cast(handle); + const auto status_s = QString::fromUtf8(status); + const auto args_s = QString::fromUtf8(args); if (status_s == "KEY_CONSIDERED") { auto tokens = QString(args).split(' '); - if (handle_struct->KeyFpr().isEmpty()) return 0; + if (handel->KeyFpr().isEmpty()) return GPG_ERR_NO_ERROR; - if (tokens.empty() || tokens[0] != handle_struct->KeyFpr()) { - LOG_W() << "handle struct key fpr: " << handle_struct->KeyFpr() + if (tokens.empty() || tokens[0] != handel->KeyFpr()) { + LOG_W() << "handle struct key fpr: " << handel->KeyFpr() << "mismatch token: " << tokens[0] << ", exit..."; - + handel->SetSuccess(false); return -1; } - return 0; + return GPG_ERR_NO_ERROR; } if (status_s == "CARDCTRL") { auto tokens = QString(args).split(' '); - if (handle_struct->SerialNumber().isEmpty()) return 0; + if (handel->SerialNumber().isEmpty()) return GPG_ERR_NO_ERROR; - if (tokens.empty() || tokens[0] != handle_struct->SerialNumber()) { - LOG_W() << "handle struct serial number: " - << handle_struct->SerialNumber() + if (tokens.empty() || tokens[0] != handel->SerialNumber()) { + LOG_W() << "handle struct serial number: " << handel->SerialNumber() << "mismatch token: " << tokens[0] << ", exit..."; - + handel->SetSuccess(false); return -1; } - return 0; + return GPG_ERR_NO_ERROR; } if (status_s == "GOT_IT" || status_s.isEmpty()) { FLOG_D("gpg reply is GOT_IT, continue..."); - return 0; + return GPG_ERR_NO_ERROR; } - LOG_D() << "current state" << handle_struct->CurrentStatus() + LOG_D() << "current state" << handel->CurrentStatus() << "gpg status: " << status_s << ", args: " << args_s; - handle_struct->SetPromptStatus(status_s, args_s); + handel->SetPromptStatus(status_s, args_s); - AutomatonState next_state = handle_struct->NextState(status_s, args_s); + AutomatonState next_state = handel->NextState(status_s, args_s); if (next_state == GpgAutomatonHandler::kAS_ERROR) { - FLOG_D("handle struct next state caught error, abort..."); + FLOG_D("handel next state caught error, abort..."); + handel->SetSuccess(false); return -1; } - LOG_D() << "next state" << next_state; - - if (next_state == GpgAutomatonHandler::kAS_SAVE) { - handle_struct->SetSuccess(true); - } + LOG_D() << "next state:" << next_state; // set state and preform action - handle_struct->SetStatus(next_state); - GpgAutomatonHandler::Command cmd = handle_struct->Action(); + handel->SetStatus(next_state); + GpgAutomatonHandler::Command cmd = handel->Action(); LOG_D() << "next action, cmd:" << cmd; @@ -110,32 +106,33 @@ auto InteratorCbFunc(void* handle, const char* status, const char* args, return GPG_ERR_FALSE; } - return 0; + return GPG_ERR_NO_ERROR; } auto DoInteractImpl(GpgContext& ctx_, const GpgKeyPtr& key, bool card_edit, const QString& id, AutomatonNextStateHandler next_state_handler, - AutomatonActionHandler action_handler, int flags) -> bool { + AutomatonActionHandler action_handler, + int flags) -> std::tuple { gpgme_key_t p_key = key == nullptr ? nullptr : static_cast(*key); - AutomatonHandelStruct handel_struct(card_edit, id); - handel_struct.SetHandler(std::move(next_state_handler), - std::move(action_handler)); + AutomatonHandelStruct handel(card_edit, id); + handel.SetHandler(std::move(next_state_handler), std::move(action_handler)); GpgData data_out; auto err = gpgme_op_interact(ctx_.DefaultContext(), p_key, flags, InteratorCbFunc, - static_cast(&handel_struct), data_out); - return CheckGpgError(err) == GPG_ERR_NO_ERROR && handel_struct.Success(); + static_cast(&handel), data_out); + return {err, handel.Success()}; } auto GpgAutomatonHandler::DoInteract( const GpgKeyPtr& key, AutomatonNextStateHandler next_state_handler, - AutomatonActionHandler action_handler, int flags) -> bool { + AutomatonActionHandler action_handler, + int flags) -> std::tuple { assert(key != nullptr); - if (key == nullptr) return false; + if (key == nullptr) return {GPG_ERR_USER_1, false}; return DoInteractImpl(ctx_, key, false, key->ID(), std::move(next_state_handler), std::move(action_handler), flags); @@ -143,7 +140,7 @@ auto GpgAutomatonHandler::DoInteract( auto GpgAutomatonHandler::DoCardInteract( const QString& serial_number, AutomatonNextStateHandler next_state_handler, - AutomatonActionHandler action_handler) -> bool { + AutomatonActionHandler action_handler) -> std::tuple { return DoInteractImpl(ctx_, nullptr, true, serial_number, std::move(next_state_handler), std::move(action_handler), GPGME_INTERACT_CARD); diff --git a/src/core/function/gpg/GpgAutomatonHandler.h b/src/core/function/gpg/GpgAutomatonHandler.h index 4363cf30..7ab2bf44 100644 --- a/src/core/function/gpg/GpgAutomatonHandler.h +++ b/src/core/function/gpg/GpgAutomatonHandler.h @@ -83,7 +83,7 @@ class GpgAutomatonHandler AutomatonState current_state_ = kAS_START; AutomatonNextStateHandler next_state_handler_; AutomatonActionHandler action_handler_; - bool success_ = false; + bool success_ = true; bool card_edit_; QString id_; QString prompt_status_; @@ -110,7 +110,8 @@ class GpgAutomatonHandler */ auto DoInteract(const GpgKeyPtr& key, AutomatonNextStateHandler next_state_handler, - AutomatonActionHandler action_handler, int flags = 0) -> bool; + AutomatonActionHandler action_handler, + int flags = 0) -> std::tuple; /** * @brief @@ -122,7 +123,8 @@ class GpgAutomatonHandler */ auto DoCardInteract(const QString& serial_number, AutomatonNextStateHandler next_state_handler, - AutomatonActionHandler action_handler) -> bool; + AutomatonActionHandler action_handler) + -> std::tuple; private: GpgContext& ctx_ = diff --git a/src/core/function/gpg/GpgBasicOperator.cpp b/src/core/function/gpg/GpgBasicOperator.cpp index 2f624b60..bdb687bc 100644 --- a/src/core/function/gpg/GpgBasicOperator.cpp +++ b/src/core/function/gpg/GpgBasicOperator.cpp @@ -88,39 +88,43 @@ void GpgBasicOperator::Encrypt(const GpgAbstractKeyPtrList& keys, const GFBuffer& in_buffer, bool ascii, const GpgOperationCallback& cb) { RunGpgOperaAsync( + GetChannel(), [=](const DataObjectPtr& data_object) { return EncryptImpl(ctx_, keys, in_buffer, ascii, data_object); }, - cb, "gpgme_op_encrypt", "2.1.0"); + cb, "gpgme_op_encrypt", "2.2.0"); } auto GpgBasicOperator::EncryptSync(const GpgAbstractKeyPtrList& keys, const GFBuffer& in_buffer, bool ascii) -> std::tuple { return RunGpgOperaSync( + GetChannel(), [=](const DataObjectPtr& data_object) { return EncryptImpl(ctx_, keys, in_buffer, ascii, data_object); }, - "gpgme_op_encrypt", "2.1.0"); + "gpgme_op_encrypt", "2.2.0"); } void GpgBasicOperator::EncryptSymmetric(const GFBuffer& in_buffer, bool ascii, const GpgOperationCallback& cb) { RunGpgOperaAsync( + GetChannel(), [=](const DataObjectPtr& data_object) { return EncryptImpl(ctx_, {}, in_buffer, ascii, data_object); }, - cb, "gpgme_op_encrypt_symmetric", "2.1.0"); + cb, "gpgme_op_encrypt_symmetric", "2.2.0"); } auto GpgBasicOperator::EncryptSymmetricSync(const GFBuffer& in_buffer, bool ascii) -> std::tuple { return RunGpgOperaSync( + GetChannel(), [=](const DataObjectPtr& data_object) { return EncryptImpl(ctx_, {}, in_buffer, ascii, data_object); }, - "gpgme_op_encrypt_symmetric", "2.1.0"); + "gpgme_op_encrypt_symmetric", "2.2.0"); } auto DecryptImpl(GpgContext& ctx_, const GFBuffer& in_buffer, @@ -141,19 +145,21 @@ auto DecryptImpl(GpgContext& ctx_, const GFBuffer& in_buffer, void GpgBasicOperator::Decrypt(const GFBuffer& in_buffer, const GpgOperationCallback& cb) { RunGpgOperaAsync( + GetChannel(), [=](const DataObjectPtr& data_object) { return DecryptImpl(ctx_, in_buffer, data_object); }, - cb, "gpgme_op_decrypt", "2.1.0"); + cb, "gpgme_op_decrypt", "2.2.0"); } auto GpgBasicOperator::DecryptSync(const GFBuffer& in_buffer) -> std::tuple { return RunGpgOperaSync( + GetChannel(), [=](const DataObjectPtr& data_object) { return DecryptImpl(ctx_, in_buffer, data_object); }, - "gpgme_op_decrypt", "2.1.0"); + "gpgme_op_decrypt", "2.2.0"); } auto VerifyImpl(GpgContext& ctx_, const GFBuffer& in_buffer, @@ -185,20 +191,22 @@ void GpgBasicOperator::Verify(const GFBuffer& in_buffer, const GFBuffer& sig_buffer, const GpgOperationCallback& cb) { RunGpgOperaAsync( + GetChannel(), [=](const DataObjectPtr& data_object) -> GpgError { return VerifyImpl(ctx_, in_buffer, sig_buffer, data_object); }, - cb, "gpgme_op_verify", "2.1.0"); + cb, "gpgme_op_verify", "2.2.0"); } auto GpgBasicOperator::VerifySync(const GFBuffer& in_buffer, const GFBuffer& sig_buffer) -> std::tuple { return RunGpgOperaSync( + GetChannel(), [=](const DataObjectPtr& data_object) { return VerifyImpl(ctx_, in_buffer, sig_buffer, data_object); }, - "gpgme_op_verify", "2.1.0"); + "gpgme_op_verify", "2.2.0"); } auto SignImpl(GpgContext& ctx_, const GpgAbstractKeyPtrList& signers, @@ -228,20 +236,22 @@ void GpgBasicOperator::Sign(const GpgAbstractKeyPtrList& signers, const GFBuffer& in_buffer, GpgSignMode mode, bool ascii, const GpgOperationCallback& cb) { RunGpgOperaAsync( + GetChannel(), [=](const DataObjectPtr& data_object) { return SignImpl(ctx_, signers, in_buffer, mode, ascii, data_object); }, - cb, "gpgme_op_sign", "2.1.0"); + cb, "gpgme_op_sign", "2.2.0"); } auto GpgBasicOperator::SignSync( const GpgAbstractKeyPtrList& signers, const GFBuffer& in_buffer, GpgSignMode mode, bool ascii) -> std::tuple { return RunGpgOperaSync( + GetChannel(), [=](const DataObjectPtr& data_object) { return SignImpl(ctx_, signers, in_buffer, mode, ascii, data_object); }, - "gpgme_op_sign", "2.1.0"); + "gpgme_op_sign", "2.2.0"); } auto DecryptVerifyImpl(GpgContext& ctx_, const GFBuffer& in_buffer, @@ -266,19 +276,21 @@ auto DecryptVerifyImpl(GpgContext& ctx_, const GFBuffer& in_buffer, void GpgBasicOperator::DecryptVerify(const GFBuffer& in_buffer, const GpgOperationCallback& cb) { RunGpgOperaAsync( + GetChannel(), [=](const DataObjectPtr& data_object) { return DecryptVerifyImpl(ctx_, in_buffer, data_object); }, - cb, "gpgme_op_decrypt_verify", "2.1.0"); + cb, "gpgme_op_decrypt_verify", "2.2.0"); } auto GpgBasicOperator::DecryptVerifySync(const GFBuffer& in_buffer) -> std::tuple { return RunGpgOperaSync( + GetChannel(), [=](const DataObjectPtr& data_object) -> GpgError { return DecryptVerifyImpl(ctx_, in_buffer, data_object); }, - "gpgme_op_decrypt_verify", "2.1.0"); + "gpgme_op_decrypt_verify", "2.2.0"); } auto EncryptSignImpl(GpgContext& ctx_, const GpgAbstractKeyPtrList& keys, @@ -315,11 +327,12 @@ void GpgBasicOperator::EncryptSign(const GpgAbstractKeyPtrList& keys, const GFBuffer& in_buffer, bool ascii, const GpgOperationCallback& cb) { RunGpgOperaAsync( + GetChannel(), [=](const DataObjectPtr& data_object) -> GpgError { return EncryptSignImpl(ctx_, keys, signers, in_buffer, ascii, data_object); }, - cb, "gpgme_op_encrypt_sign", "2.1.0"); + cb, "gpgme_op_encrypt_sign", "2.2.0"); } auto GpgBasicOperator::EncryptSignSync(const GpgAbstractKeyPtrList& keys, @@ -327,11 +340,12 @@ auto GpgBasicOperator::EncryptSignSync(const GpgAbstractKeyPtrList& keys, const GFBuffer& in_buffer, bool ascii) -> std::tuple { return RunGpgOperaSync( + GetChannel(), [=](const DataObjectPtr& data_object) -> GpgError { return EncryptSignImpl(ctx_, keys, signers, in_buffer, ascii, data_object); }, - "gpgme_op_encrypt_sign", "2.1.0"); + "gpgme_op_encrypt_sign", "2.2.0"); } void GpgBasicOperator::SetSigners(const GpgAbstractKeyPtrList& signers, @@ -346,7 +360,7 @@ auto GpgBasicOperator::GetSigners(bool ascii) -> KeyArgsList { auto signers = KeyArgsList{}; for (auto i = 0U; i < count; i++) { auto key = GpgKey(gpgme_signers_enum(ctx, i)); - signers.push_back(GpgKey(std::move(key))); + signers.push_back(GpgKey(key)); } return signers; } diff --git a/src/core/function/gpg/GpgCommandExecutor.cpp b/src/core/function/gpg/GpgCommandExecutor.cpp index dd8a500e..72988a55 100644 --- a/src/core/function/gpg/GpgCommandExecutor.cpp +++ b/src/core/function/gpg/GpgCommandExecutor.cpp @@ -41,26 +41,25 @@ auto BuildTaskFromExecCtx(const GpgCommandExecutor::ExecuteContext &context) -> Thread::Task * { const auto &cmd = context.cmd; const auto &arguments = context.arguments; - const auto &interact_function = context.int_func; - const auto &cmd_executor_callback = context.cb_func; + const auto &int_func = context.int_func; + const auto &cb = context.cb_func; - Thread::Task::TaskCallback result_callback = - [cmd](int /*rtn*/, const DataObjectPtr &data_object) { - LOG_D() << "data object args count of cmd executor result callback:" - << data_object->GetObjectSize(); + Thread::Task::TaskCallback result_callback = [cmd](int /*rtn*/, + const DataObjectPtr &obj) { + LOG_D() << "data object args count of cmd executor result callback:" + << obj->GetObjectSize(); - if (!data_object->Check()) { - FLOG_W("data object checking failed"); - return; - } + if (!obj->Check()) { + FLOG_W("data object checking failed"); + return; + } - auto exit_code = ExtractParams(data_object, 0); - auto process_stdout = ExtractParams(data_object, 1); - auto callback = - ExtractParams(data_object, 2); + auto code = ExtractParams(obj, 0); + auto out = ExtractParams(obj, 1); + auto cb = ExtractParams(obj, 2); - callback(exit_code, process_stdout, {}); - }; + cb(code, out, {}); + }; Thread::Task::TaskRunnable runner = [](const DataObjectPtr &data_object) -> int { @@ -82,71 +81,67 @@ auto BuildTaskFromExecCtx(const GpgCommandExecutor::ExecuteContext &context) const QString joined_argument = arguments.join(" "); // create process - auto *cmd_process = new QProcess(); + auto *pcs = new QProcess(); // move to current thread // - cmd_process->moveToThread(QThread::currentThread()); + pcs->moveToThread(QThread::currentThread()); // set process channel mode // this is to make sure we can get all output from stdout and stderr - cmd_process->setProcessChannelMode(QProcess::MergedChannels); - cmd_process->setProgram(cmd); + pcs->setProcessChannelMode(QProcess::MergedChannels); + pcs->setProgram(cmd); // set arguments QStringList q_arguments; for (const auto &argument : arguments) { q_arguments.append(argument); } - cmd_process->setArguments(q_arguments); + pcs->setArguments(q_arguments); + QObject::connect(pcs, &QProcess::started, [cmd, joined_argument]() -> void { + LOG_D() << "\n== Process Execute Started ==\nCommand: " << cmd + << "\nArguments: " << joined_argument + << " \n========================"; + }); + QObject::connect(pcs, &QProcess::readyReadStandardOutput, + [interact_func, pcs]() { interact_func(pcs); }); QObject::connect( - cmd_process, &QProcess::started, [cmd, joined_argument]() -> void { - LOG_D() << "\n== Process Execute Started ==\nCommand: " << cmd - << "\nArguments: " << joined_argument - << " \n========================"; + pcs, &QProcess::errorOccurred, [=](QProcess::ProcessError error) { + LOG_W() << "caught error while executing command: " << cmd + << joined_argument << ", error:" << error; }); - QObject::connect( - cmd_process, &QProcess::readyReadStandardOutput, - [interact_func, cmd_process]() { interact_func(cmd_process); }); - QObject::connect(cmd_process, &QProcess::errorOccurred, - [=](QProcess::ProcessError error) { - LOG_W() - << "caught error while executing command: " << cmd - << joined_argument << ", error:" << error; - }); LOG_D() << "\n== Process Execute Ready ==\nCommand: " << cmd << "\nArguments: " << joined_argument << "\n========================"; - cmd_process->start(); - cmd_process->waitForFinished(); + pcs->start(); + pcs->waitForFinished(); - QString process_stdout = cmd_process->readAllStandardOutput(); - int exit_code = cmd_process->exitCode(); + auto out = pcs->readAllStandardOutput(); + auto code = pcs->exitCode(); LOG_D() << "\n==== Process Execution Summary ====\n" << "Command: " << cmd << "\n" << "Arguments: " << joined_argument << "\n" - << "Exit Code: " << exit_code << "\n" + << "Exit Code: " << code << "\n" << "---- Standard Output ----\n" - << process_stdout << "\n" + << out << "\n" << "==============================="; - cmd_process->close(); - cmd_process->deleteLater(); + pcs->close(); + pcs->deleteLater(); - data_object->Swap({exit_code, process_stdout, callback}); + data_object->Swap({code, out, callback}); return 0; }; return new Thread::Task( std::move(runner), QString("GpgCommamdExecutor(%1){%2}").arg(cmd).arg(arguments.join(' ')), - TransferParams(cmd, arguments, interact_function, cmd_executor_callback), - std::move(result_callback)); + TransferParams(cmd, arguments, int_func, cb), std::move(result_callback)); } -void GpgCommandExecutor::ExecuteSync(ExecuteContext context) { +void GpgCommandExecutor::ExecuteSync(const ExecuteContext &context) { Thread::Task *task = BuildTaskFromExecCtx(context); QPointer p_t = task; @@ -174,8 +169,9 @@ void GpgCommandExecutor::ExecuteSync(ExecuteContext context) { looper->deleteLater(); } -void GpgCommandExecutor::ExecuteConcurrentlyAsync(ExecuteContexts contexts) { - for (auto &context : contexts) { +void GpgCommandExecutor::ExecuteConcurrentlyAsync( + const ExecuteContexts &contexts) { + for (const auto &context : contexts) { Thread::Task *task = BuildTaskFromExecCtx(context); if (context.task_runner != nullptr) { @@ -189,12 +185,13 @@ void GpgCommandExecutor::ExecuteConcurrentlyAsync(ExecuteContexts contexts) { } } -void GpgCommandExecutor::ExecuteConcurrentlySync(ExecuteContexts contexts) { +void GpgCommandExecutor::ExecuteConcurrentlySync( + const ExecuteContexts &contexts) { QEventLoop looper; auto remaining_tasks = contexts.size(); Thread::TaskRunnerPtr target_task_runner = nullptr; - for (auto &context : contexts) { + for (const auto &context : contexts) { const auto &cmd = context.cmd; LOG_D() << "gpg concurrently called cmd: " << cmd; @@ -235,24 +232,30 @@ GpgCommandExecutor::ExecuteContext::ExecuteContext( int_func(std::move(int_func)), task_runner(std::move(task_runner)) {} +GpgCommandExecutor::ExecuteContext::ExecuteContext( + QStringList arguments, GpgCommandExecutorCallback callback, + Module::TaskRunnerPtr task_runner, GpgCommandExecutorInterator int_func) + : arguments(std::move(arguments)), + cb_func(std::move(callback)), + int_func(std::move(int_func)), + task_runner(std::move(task_runner)) {} + GpgCommandExecutor::GpgCommandExecutor(int channel) : GpgFrontend::SingletonFunctionObject(channel) {} -void GpgCommandExecutor::GpgExecuteSync(const ExecuteContext &context) { - const auto gpg_path = Module::RetrieveRTValueTypedOrDefault<>( - "core", "gpgme.ctx.app_path", QString{}); - - if (context.cmd.isEmpty() && gpg_path.isEmpty()) { +auto PrepareContext(const GpgContext &ctx_, const QString &path, + const GpgCommandExecutor::ExecuteContext &context) + -> std::tuple { + if (context.cmd.isEmpty() && path.isEmpty()) { LOG_E() << "failed to execute gpg command, gpg binary path is empty."; - return; + return {false, {}}; } - LOG_D() << "got gpg binary path:" << gpg_path; - LOG_D() << "context channel:" << GetChannel() + LOG_D() << "got path:" << path << "context channel:" << ctx_.GetChannel() << "home path: " << ctx_.HomeDirectory(); - ExecuteContext ctx = { - context.cmd.isEmpty() ? gpg_path : context.cmd, + GpgCommandExecutor::ExecuteContext ctx = { + context.cmd.isEmpty() ? path : context.cmd, context.arguments, context.cb_func, context.task_runner, @@ -260,10 +263,71 @@ void GpgCommandExecutor::GpgExecuteSync(const ExecuteContext &context) { }; if (!ctx.arguments.contains("--homedir") && !ctx_.HomeDirectory().isEmpty()) { - ctx.arguments.append("--homedir"); - ctx.arguments.append(ctx_.HomeDirectory()); + ctx.arguments.prepend(QDir::toNativeSeparators((ctx_.HomeDirectory()))); + ctx.arguments.prepend("--homedir"); + } + + return {true, ctx}; +} + +auto PrepareExecuteSyncContext(const GpgContext &ctx_, const QString &path, + const GpgCommandExecutor::ExecuteContext + &context) -> std::tuple { + auto ctx = context; + + int pcs_exit_code; + QString pcs_stdout; + + // proxy + ctx.cb_func = [&](int exit_code, const QString &out, const QString &) { + pcs_exit_code = exit_code; + pcs_stdout = out; + }; + + auto [ret, ctx2] = PrepareContext(ctx_, path, ctx); + if (ret) { + GpgFrontend::GpgCommandExecutor::ExecuteSync(ctx2); + return {pcs_exit_code, pcs_stdout}; } + return {-1, "invalid context"}; +} + +void PrepareExecuteAsyncContext( + const GpgContext &ctx_, const QString &path, + const GpgCommandExecutor::ExecuteContext &context) { + auto [ret, ctx] = PrepareContext(ctx_, path, context); + GpgFrontend::GpgCommandExecutor::ExecuteConcurrentlyAsync({ctx}); +} + +auto GpgCommandExecutor::GpgExecuteSync(const ExecuteContext &context) + -> std::tuple { + return PrepareExecuteSyncContext(ctx_, + Module::RetrieveRTValueTypedOrDefault<>( + "core", "gpgme.ctx.app_path", QString{}), + context); +} + +auto GpgCommandExecutor::GpgConfExecuteSync(const ExecuteContext &context) + + -> std::tuple { + return PrepareExecuteSyncContext( + ctx_, + Module::RetrieveRTValueTypedOrDefault<>("core", "gpgme.ctx.gpgconf_path", + QString{}), + context); +} + +void GpgCommandExecutor::GpgExecuteAsync(const ExecuteContext &context) { + PrepareExecuteAsyncContext(ctx_, + Module::RetrieveRTValueTypedOrDefault<>( + "core", "gpgme.ctx.app_path", QString{}), + context); +} - return ExecuteSync(ctx); +void GpgCommandExecutor::GpgConfExecuteAsync(const ExecuteContext &context) { + PrepareExecuteAsyncContext(ctx_, + Module::RetrieveRTValueTypedOrDefault<>( + "core", "gpgme.ctx.gpgconf_path", QString{}), + context); } } // namespace GpgFrontend \ No newline at end of file diff --git a/src/core/function/gpg/GpgCommandExecutor.h b/src/core/function/gpg/GpgCommandExecutor.h index fd2181d3..046b61e4 100644 --- a/src/core/function/gpg/GpgCommandExecutor.h +++ b/src/core/function/gpg/GpgCommandExecutor.h @@ -51,12 +51,42 @@ class GPGFRONTEND_CORE_EXPORT GpgCommandExecutor GpgCommandExecutorInterator int_func; Module::TaskRunnerPtr task_runner = nullptr; + /** + * @brief Construct a new Execute Context object + * + */ + ExecuteContext() = default; + + /** + * @brief Construct a new Execute Context object + * + * @param cmd + * @param arguments + * @param callback + * @param task_runner + * @param int_func + */ ExecuteContext( QString cmd, QStringList arguments, GpgCommandExecutorCallback callback = [](int, const QString &, const QString &) {}, Module::TaskRunnerPtr task_runner = nullptr, GpgCommandExecutorInterator int_func = [](QProcess *) {}); + + /** + * @brief Construct a new Execute Context object + * + * @param arguments + * @param callback + * @param task_runner + * @param int_func + */ + ExecuteContext( + QStringList arguments, + GpgCommandExecutorCallback callback = [](int, const QString &, + const QString &) {}, + Module::TaskRunnerPtr task_runner = nullptr, + GpgCommandExecutorInterator int_func = [](QProcess *) {}); }; using ExecuteContexts = QContainer; @@ -69,13 +99,45 @@ class GPGFRONTEND_CORE_EXPORT GpgCommandExecutor * @param arguments Command parameters * @param interact_func Command answering function */ - static void ExecuteSync(ExecuteContext); + static void ExecuteSync(const ExecuteContext &); + + /** + * @brief + * + */ + static void ExecuteConcurrentlyAsync(const ExecuteContexts &); + + /** + * @brief + * + */ + static void ExecuteConcurrentlySync(const ExecuteContexts &); - static void ExecuteConcurrentlyAsync(ExecuteContexts); + /** + * @brief + * + */ + auto GpgExecuteSync(const ExecuteContext &) -> std::tuple; + + /** + * @brief + * + */ + auto GpgConfExecuteSync(const ExecuteContext &) -> std::tuple; - static void ExecuteConcurrentlySync(ExecuteContexts); + /** + * @brief + * + * @param context + */ + void GpgExecuteAsync(const ExecuteContext &); - void GpgExecuteSync(const ExecuteContext &); + /** + * @brief + * + * @param context + */ + void GpgConfExecuteAsync(const ExecuteContext &); private: GpgContext &ctx_ = diff --git a/src/core/function/gpg/GpgComponentInfoGetter.cpp b/src/core/function/gpg/GpgComponentInfoGetter.cpp new file mode 100644 index 00000000..317f334f --- /dev/null +++ b/src/core/function/gpg/GpgComponentInfoGetter.cpp @@ -0,0 +1,64 @@ +/** + * Copyright (C) 2021-2024 Saturneric + * + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GpgFrontend. If not, see . + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "GpgComponentInfoGetter.h" + +namespace GpgFrontend { + +GpgComponentInfoGetter::GpgComponentInfoGetter(int channel) + : GpgFrontend::SingletonFunctionObject(channel) {} + +auto GpgComponentInfoGetter::GetGpgAgentVersion() -> QString { + if (!gpg_agent_version_.isEmpty()) return gpg_agent_version_; + + auto [r, s] = + assuan_.SendDataCommand(GpgComponentType::kGPG_AGENT, "GETINFO version"); + if (s.isEmpty()) { + LOG_D() << "invalid response of GETINFO version: " << s; + return {}; + } + + gpg_agent_version_ = s.front(); + return gpg_agent_version_; +} + +auto GpgComponentInfoGetter::GetScdaemonVersion() -> QString { + if (!scdaemon_version_.isEmpty()) return scdaemon_version_; + + auto [r, s] = assuan_.SendDataCommand(GpgComponentType::kGPG_AGENT, + "SCD GETINFO version"); + if (s.isEmpty()) { + LOG_D() << "invalid response of SCD GETINFO version: " << s; + return {}; + } + + scdaemon_version_ = s.front(); + return scdaemon_version_; +} + +} // namespace GpgFrontend \ No newline at end of file diff --git a/src/core/function/gpg/GpgComponentInfoGetter.h b/src/core/function/gpg/GpgComponentInfoGetter.h new file mode 100644 index 00000000..3f8b560b --- /dev/null +++ b/src/core/function/gpg/GpgComponentInfoGetter.h @@ -0,0 +1,72 @@ +/** + * Copyright (C) 2021-2024 Saturneric + * + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GpgFrontend. If not, see . + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +#include "core/function/gpg/GpgAssuanHelper.h" +#include "core/function/gpg/GpgContext.h" + +namespace GpgFrontend { + +class GPGFRONTEND_CORE_EXPORT GpgComponentInfoGetter + : public SingletonFunctionObject { + public: + /** + * @brief Construct a new Gpg Assuan Helper object + * + * @param channel + */ + explicit GpgComponentInfoGetter(int channel); + + /** + * @brief + * + * @return true + * @return false + */ + auto GetGpgAgentVersion() -> QString; + + /** + * @brief + * + * @return true + * @return false + */ + auto GetScdaemonVersion() -> QString; + + private: + GpgContext& ctx_ = + GpgContext::GetInstance(SingletonFunctionObject::GetChannel()); + GpgAssuanHelper& assuan_ = + GpgAssuanHelper::GetInstance(SingletonFunctionObject::GetChannel()); + + QString gpg_agent_version_; + QString scdaemon_version_; +}; + +}; // namespace GpgFrontend \ No newline at end of file diff --git a/src/core/function/gpg/GpgFileOpera.cpp b/src/core/function/gpg/GpgFileOpera.cpp index 334aae6f..b498461f 100644 --- a/src/core/function/gpg/GpgFileOpera.cpp +++ b/src/core/function/gpg/GpgFileOpera.cpp @@ -32,7 +32,6 @@ #include "core/model/GpgData.h" #include "core/model/GpgDecryptResult.h" #include "core/model/GpgEncryptResult.h" -#include "core/model/GpgKey.h" #include "core/model/GpgSignResult.h" #include "core/model/GpgVerifyResult.h" #include "core/utils/AsyncUtils.h" @@ -95,22 +94,24 @@ void GpgFileOpera::EncryptFile(const GpgAbstractKeyPtrList& keys, const QString& out_path, const GpgOperationCallback& cb) { RunGpgOperaAsync( + GetChannel(), [=](const DataObjectPtr& data_object) { return EncryptFileImpl(ctx_, keys, in_path, ascii, out_path, data_object); }, - cb, "gpgme_op_encrypt", "2.1.0"); + cb, "gpgme_op_encrypt", "2.2.0"); } auto GpgFileOpera::EncryptFileSync( const GpgAbstractKeyPtrList& keys, const QString& in_path, bool ascii, const QString& out_path) -> std::tuple { return RunGpgOperaSync( + GetChannel(), [=](const DataObjectPtr& data_object) { return EncryptFileImpl(ctx_, keys, in_path, ascii, out_path, data_object); }, - "gpgme_op_encrypt", "2.1.0"); + "gpgme_op_encrypt", "2.2.0"); } void GpgFileOpera::EncryptDirectory(const GpgAbstractKeyPtrList& keys, @@ -120,6 +121,7 @@ void GpgFileOpera::EncryptDirectory(const GpgAbstractKeyPtrList& keys, auto ex = CreateStandardGFDataExchanger(); RunGpgOperaAsync( + GetChannel(), [=](const DataObjectPtr& data_object) -> GpgError { GpgData data_in(ex); GpgData data_out(out_path, false); @@ -127,7 +129,7 @@ void GpgFileOpera::EncryptDirectory(const GpgAbstractKeyPtrList& keys, return EncryptFileGpgDataImpl(ctx_, keys, data_in, ascii, data_out, data_object); }, - cb, "gpgme_op_encrypt", "2.1.0"); + cb, "gpgme_op_encrypt", "2.2.0"); CreateArchiveHelper(in_path, ex); } @@ -155,20 +157,22 @@ auto DecryptFileImpl(GpgContext& ctx_, const QString& in_path, void GpgFileOpera::DecryptFile(const QString& in_path, const QString& out_path, const GpgOperationCallback& cb) { RunGpgOperaAsync( + GetChannel(), [=](const DataObjectPtr& data_object) { return DecryptFileImpl(ctx_, in_path, out_path, data_object); }, - cb, "gpgme_op_decrypt", "2.1.0"); + cb, "gpgme_op_decrypt", "2.2.0"); } auto GpgFileOpera::DecryptFileSync(const QString& in_path, const QString& out_path) -> std::tuple { return RunGpgOperaSync( + GetChannel(), [=](const DataObjectPtr& data_object) { return DecryptFileImpl(ctx_, in_path, out_path, data_object); }, - "gpgme_op_decrypt", "2.1.0"); + "gpgme_op_decrypt", "2.2.0"); } void GpgFileOpera::DecryptArchive(const QString& in_path, @@ -177,13 +181,14 @@ void GpgFileOpera::DecryptArchive(const QString& in_path, auto ex = ExtractArchiveHelper(out_path); RunGpgOperaAsync( + GetChannel(), [=](const DataObjectPtr& data_object) -> GpgError { GpgData data_in(in_path, true); GpgData data_out(ex); return DecryptFileGpgDataImpl(ctx_, data_in, data_out, data_object); }, - cb, "gpgme_op_decrypt", "2.1.0"); + cb, "gpgme_op_decrypt", "2.2.0"); } auto SignFileGpgDataImpl(GpgContext& ctx_, GpgBasicOperator& basic_opera_, @@ -221,22 +226,24 @@ void GpgFileOpera::SignFile(const GpgAbstractKeyPtrList& keys, const QString& out_path, const GpgOperationCallback& cb) { RunGpgOperaAsync( + GetChannel(), [=](const DataObjectPtr& data_object) { return SignFileImpl(ctx_, basic_opera_, keys, in_path, ascii, out_path, data_object); }, - cb, "gpgme_op_sign", "2.1.0"); + cb, "gpgme_op_sign", "2.2.0"); } auto GpgFileOpera::SignFileSync( const GpgAbstractKeyPtrList& keys, const QString& in_path, bool ascii, const QString& out_path) -> std::tuple { return RunGpgOperaSync( + GetChannel(), [=](const DataObjectPtr& data_object) { return SignFileImpl(ctx_, basic_opera_, keys, in_path, ascii, out_path, data_object); }, - "gpgme_op_sign", "2.1.0"); + "gpgme_op_sign", "2.2.0"); } auto VerifyFileImpl(GpgContext& ctx_, const QString& data_path, @@ -266,20 +273,22 @@ void GpgFileOpera::VerifyFile(const QString& data_path, const QString& sign_path, const GpgOperationCallback& cb) { RunGpgOperaAsync( + GetChannel(), [=](const DataObjectPtr& data_object) -> GpgError { return VerifyFileImpl(ctx_, data_path, sign_path, data_object); }, - cb, "gpgme_op_verify", "2.1.0"); + cb, "gpgme_op_verify", "2.2.0"); } auto GpgFileOpera::VerifyFileSync(const QString& data_path, const QString& sign_path) -> std::tuple { return RunGpgOperaSync( + GetChannel(), [=](const DataObjectPtr& data_object) -> GpgError { return VerifyFileImpl(ctx_, data_path, sign_path, data_object); }, - "gpgme_op_verify", "2.1.0"); + "gpgme_op_verify", "2.2.0"); } auto EncryptSignFileGpgDataImpl(GpgContext& ctx_, @@ -324,11 +333,12 @@ void GpgFileOpera::EncryptSignFile(const GpgAbstractKeyPtrList& keys, const QString& out_path, const GpgOperationCallback& cb) { RunGpgOperaAsync( + GetChannel(), [=](const DataObjectPtr& data_object) { return EncryptSignFileImpl(ctx_, basic_opera_, keys, signer_keys, in_path, ascii, out_path, data_object); }, - cb, "gpgme_op_encrypt_sign", "2.1.0"); + cb, "gpgme_op_encrypt_sign", "2.2.0"); } auto GpgFileOpera::EncryptSignFileSync( @@ -336,11 +346,12 @@ auto GpgFileOpera::EncryptSignFileSync( const QString& in_path, bool ascii, const QString& out_path) -> std::tuple { return RunGpgOperaSync( + GetChannel(), [=](const DataObjectPtr& data_object) { return EncryptSignFileImpl(ctx_, basic_opera_, keys, signer_keys, in_path, ascii, out_path, data_object); }, - "gpgme_op_encrypt_sign", "2.1.0"); + "gpgme_op_encrypt_sign", "2.2.0"); } void GpgFileOpera::EncryptSignDirectory( @@ -350,6 +361,7 @@ void GpgFileOpera::EncryptSignDirectory( auto ex = CreateStandardGFDataExchanger(); RunGpgOperaAsync( + GetChannel(), [=](const DataObjectPtr& data_object) -> GpgError { GpgData data_in(ex); GpgData data_out(out_path, false); @@ -358,7 +370,7 @@ void GpgFileOpera::EncryptSignDirectory( data_in, ascii, data_out, data_object); }, - cb, "gpgme_op_encrypt_sign", "2.1.0"); + cb, "gpgme_op_encrypt_sign", "2.2.0"); CreateArchiveHelper(in_path, ex); } @@ -389,20 +401,22 @@ void GpgFileOpera::DecryptVerifyFile(const QString& in_path, const QString& out_path, const GpgOperationCallback& cb) { RunGpgOperaAsync( + GetChannel(), [=](const DataObjectPtr& data_object) -> GpgError { return DecryptVerifyFileImpl(ctx_, in_path, out_path, data_object); }, - cb, "gpgme_op_decrypt_verify", "2.1.0"); + cb, "gpgme_op_decrypt_verify", "2.2.0"); } auto GpgFileOpera::DecryptVerifyFileSync(const QString& in_path, const QString& out_path) -> std::tuple { return RunGpgOperaSync( + GetChannel(), [=](const DataObjectPtr& data_object) -> GpgError { return DecryptVerifyFileImpl(ctx_, in_path, out_path, data_object); }, - "gpgme_op_decrypt_verify", "2.1.0"); + "gpgme_op_decrypt_verify", "2.2.0"); } void GpgFileOpera::DecryptVerifyArchive(const QString& in_path, @@ -411,33 +425,36 @@ void GpgFileOpera::DecryptVerifyArchive(const QString& in_path, auto ex = ExtractArchiveHelper(out_path); RunGpgOperaAsync( + GetChannel(), [=](const DataObjectPtr& data_object) -> GpgError { GpgData data_in(in_path, true); GpgData data_out(ex); return DecryptVerifyFileGpgDataImpl(ctx_, data_in, data_out, data_object); }, - cb, "gpgme_op_decrypt_verify", "2.1.0"); + cb, "gpgme_op_decrypt_verify", "2.2.0"); } void GpgFileOpera::EncryptFileSymmetric(const QString& in_path, bool ascii, const QString& out_path, const GpgOperationCallback& cb) { RunGpgOperaAsync( + GetChannel(), [=](const DataObjectPtr& data_object) -> GpgError { return EncryptFileImpl(ctx_, {}, in_path, ascii, out_path, data_object); }, - cb, "gpgme_op_encrypt_symmetric", "2.1.0"); + cb, "gpgme_op_encrypt_symmetric", "2.2.0"); } auto GpgFileOpera::EncryptFileSymmetricSync(const QString& in_path, bool ascii, const QString& out_path) -> std::tuple { return RunGpgOperaSync( + GetChannel(), [=](const DataObjectPtr& data_object) -> GpgError { return EncryptFileImpl(ctx_, {}, in_path, ascii, out_path, data_object); }, - "gpgme_op_encrypt_symmetric", "2.1.0"); + "gpgme_op_encrypt_symmetric", "2.2.0"); } void GpgFileOpera::EncryptDirectorySymmetric(const QString& in_path, bool ascii, @@ -446,6 +463,7 @@ void GpgFileOpera::EncryptDirectorySymmetric(const QString& in_path, bool ascii, auto ex = CreateStandardGFDataExchanger(); RunGpgOperaAsync( + GetChannel(), [=](const DataObjectPtr& data_object) { GpgData data_in(ex); GpgData data_out(out_path, false); @@ -453,7 +471,7 @@ void GpgFileOpera::EncryptDirectorySymmetric(const QString& in_path, bool ascii, return EncryptFileGpgDataImpl(ctx_, {}, data_in, ascii, data_out, data_object); }, - cb, "gpgme_op_encrypt_symmetric", "2.1.0"); + cb, "gpgme_op_encrypt_symmetric", "2.2.0"); CreateArchiveHelper(in_path, ex); } @@ -466,6 +484,7 @@ auto GpgFileOpera::EncryptDirectorySymmetricSync( CreateArchiveHelper(in_path, ex); return RunGpgOperaSync( + GetChannel(), [=](const DataObjectPtr& data_object) -> GpgError { GpgData data_in(ex); GpgData data_out(out_path, false); @@ -473,7 +492,7 @@ auto GpgFileOpera::EncryptDirectorySymmetricSync( return EncryptFileGpgDataImpl(ctx_, {}, data_in, ascii, data_out, data_object); }, - "gpgme_op_encrypt_symmetric", "2.1.0"); + "gpgme_op_encrypt_symmetric", "2.2.0"); } } // namespace GpgFrontend \ No newline at end of file diff --git a/src/core/function/gpg/GpgKeyImportExporter.cpp b/src/core/function/gpg/GpgKeyImportExporter.cpp index eda36273..4e306233 100644 --- a/src/core/function/gpg/GpgKeyImportExporter.cpp +++ b/src/core/function/gpg/GpgKeyImportExporter.cpp @@ -105,6 +105,7 @@ void GpgKeyImportExporter::ExportKeys(const GpgAbstractKeyPtrList& keys, bool ssh_mode, const GpgOperationCallback& cb) const { RunGpgOperaAsync( + GetChannel(), [=](const DataObjectPtr& data_object) -> GpgError { if (keys.empty()) return GPG_ERR_CANCELED; @@ -139,6 +140,7 @@ void GpgKeyImportExporter::ExportAllKeys(const GpgAbstractKeyPtrList& keys, bool secret, bool ascii, const GpgOperationCallback& cb) const { RunGpgOperaAsync( + GetChannel(), [=](const DataObjectPtr& data_object) -> GpgError { if (keys.empty()) return GPG_ERR_CANCELED; diff --git a/src/core/function/gpg/GpgKeyManager.cpp b/src/core/function/gpg/GpgKeyManager.cpp index 1fa050bb..5fca4ed4 100644 --- a/src/core/function/gpg/GpgKeyManager.cpp +++ b/src/core/function/gpg/GpgKeyManager.cpp @@ -31,7 +31,6 @@ #include "core/function/gpg/GpgAutomatonHandler.h" #include "core/function/gpg/GpgBasicOperator.h" #include "core/function/gpg/GpgKeyGetter.h" -#include "core/model/GpgData.h" #include "core/utils/GpgUtils.h" namespace GpgFrontend { @@ -69,9 +68,9 @@ auto GpgKeyManager::RevSign(const GpgKeyPtr& key, auto signing_key = key_getter.GetKey(sign_id.first); assert(signing_key.IsGood()); - auto err = CheckGpgError( - gpgme_op_revsig(ctx_.DefaultContext(), gpgme_key_t(*key), - gpgme_key_t(signing_key), sign_id.second.toUtf8(), 0)); + auto err = CheckGpgError(gpgme_op_revsig( + ctx_.DefaultContext(), static_cast(*key), + static_cast(signing_key), sign_id.second.toUtf8(), 0)); if (CheckGpgError(err) != GPG_ERR_NO_ERROR) return false; } return true; @@ -102,7 +101,7 @@ auto GpgKeyManager::SetOwnerTrustLevel(const GpgKeyPtr& key, } GpgAutomatonHandler::AutomatonNextStateHandler next_state_handler = - [](AutomatonState state, QString status, QString args) { + [](AutomatonState state, const QString& status, const QString& args) { auto tokens = args.split(' '); switch (state) { @@ -162,15 +161,14 @@ auto GpgKeyManager::SetOwnerTrustLevel(const GpgKeyPtr& key, return QString("Y"); case GpgAutomatonHandler::kAS_START: case GpgAutomatonHandler::kAS_ERROR: - return QString(""); default: return QString(""); } return QString(""); }; - return GpgAutomatonHandler::GetInstance(GetChannel()) - .DoInteract(key, next_state_handler, action_handler); + auto [err, succ] = auto_.DoInteract(key, next_state_handler, action_handler); + return err == GPG_ERR_NO_ERROR && !succ; } auto GpgKeyManager::DeleteSubkey(const GpgKeyPtr& key, @@ -182,7 +180,7 @@ auto GpgKeyManager::DeleteSubkey(const GpgKeyPtr& key, } AutomatonNextStateHandler next_state_handler = - [](AutomatonState state, QString status, QString args) { + [](AutomatonState state, const QString& status, const QString& args) { auto tokens = args.split(' '); switch (state) { @@ -247,8 +245,8 @@ auto GpgKeyManager::DeleteSubkey(const GpgKeyPtr& key, return QString(""); }; - return GpgAutomatonHandler::GetInstance(GetChannel()) - .DoInteract(key, next_state_handler, action_handler); + auto [err, succ] = auto_.DoInteract(key, next_state_handler, action_handler); + return err == GPG_ERR_NO_ERROR && !succ; } auto GpgKeyManager::RevokeSubkey(const GpgKeyPtr& key, int subkey_index, @@ -270,7 +268,7 @@ auto GpgKeyManager::RevokeSubkey(const GpgKeyPtr& key, int subkey_index, reason_text.split('\n', Qt::SkipEmptyParts)); AutomatonNextStateHandler next_state_handler = - [](AutomatonState state, QString status, QString args) { + [](AutomatonState state, const QString& status, const QString& args) { auto tokens = args.split(' '); switch (state) { @@ -363,8 +361,8 @@ auto GpgKeyManager::RevokeSubkey(const GpgKeyPtr& key, int subkey_index, return QString(""); }; - return GpgAutomatonHandler::GetInstance(GetChannel()) - .DoInteract(key, next_state_handler, action_handler); + auto [err, succ] = auto_.DoInteract(key, next_state_handler, action_handler); + return err == GPG_ERR_NO_ERROR && !succ; } } // namespace GpgFrontend \ No newline at end of file diff --git a/src/core/function/gpg/GpgKeyManager.h b/src/core/function/gpg/GpgKeyManager.h index ccf69b53..384319f8 100644 --- a/src/core/function/gpg/GpgKeyManager.h +++ b/src/core/function/gpg/GpgKeyManager.h @@ -29,6 +29,7 @@ #pragma once #include "core/function/basic/GpgFunctionObject.h" +#include "core/function/gpg/GpgAutomatonHandler.h" #include "core/function/gpg/GpgContext.h" #include "core/typedef/GpgTypedef.h" @@ -114,6 +115,8 @@ class GPGFRONTEND_CORE_EXPORT GpgKeyManager private: GpgContext& ctx_ = GpgContext::GetInstance(SingletonFunctionObject::GetChannel()); ///< + GpgAutomatonHandler& auto_ = GpgAutomatonHandler::GetInstance( + SingletonFunctionObject::GetChannel()); ///< }; } // namespace GpgFrontend diff --git a/src/core/function/gpg/GpgKeyOpera.cpp b/src/core/function/gpg/GpgKeyOpera.cpp index e97eebd8..bcc3cc44 100644 --- a/src/core/function/gpg/GpgKeyOpera.cpp +++ b/src/core/function/gpg/GpgKeyOpera.cpp @@ -215,19 +215,21 @@ auto GenerateKeyImpl(GpgContext& ctx, void GpgKeyOpera::GenerateKey(const QSharedPointer& params, const GpgOperationCallback& callback) { RunGpgOperaAsync( + GetChannel(), [=](const DataObjectPtr& data_object) -> GpgError { return GenerateKeyImpl(ctx_, params, data_object); }, - callback, "gpgme_op_createkey", "2.1.0"); + callback, "gpgme_op_createkey", "2.2.0"); } auto GpgKeyOpera::GenerateKeySync(const QSharedPointer& params) -> std::tuple { return RunGpgOperaSync( + GetChannel(), [=](const DataObjectPtr& data_object) -> GpgError { return GenerateKeyImpl(ctx_, params, data_object); }, - "gpgme_op_createkey", "2.1.0"); + "gpgme_op_createkey", "2.2.0"); } auto GenerateSubKeyImpl(GpgContext& ctx, const GpgKeyPtr& key, @@ -270,6 +272,7 @@ void GpgKeyOpera::GenerateSubkey(const GpgKeyPtr& key, const QSharedPointer& params, const GpgOperationCallback& callback) { RunGpgOperaAsync( + GetChannel(), [=](const DataObjectPtr& data_object) -> GpgError { return GenerateSubKeyImpl(ctx_, key, params, data_object); }, @@ -280,6 +283,7 @@ auto GpgKeyOpera::GenerateSubkeySync( const GpgKeyPtr& key, const QSharedPointer& params) -> std::tuple { return RunGpgOperaSync( + GetChannel(), [=](const DataObjectPtr& data_object) -> GpgError { return GenerateSubKeyImpl(ctx_, key, params, data_object); }, @@ -318,11 +322,12 @@ void GpgKeyOpera::GenerateKeyWithSubkey( const QSharedPointer& s_params, const GpgOperationCallback& callback) { RunGpgOperaAsync( + GetChannel(), [=](const DataObjectPtr& data_object) -> GpgError { return GenerateKeyWithSubkeyImpl(ctx_, key_getter_, p_params, s_params, data_object); }, - callback, "gpgme_op_createkey&gpgme_op_createsubkey", "2.1.0"); + callback, "gpgme_op_createkey&gpgme_op_createsubkey", "2.2.0"); } auto GpgKeyOpera::GenerateKeyWithSubkeySync( @@ -330,36 +335,35 @@ auto GpgKeyOpera::GenerateKeyWithSubkeySync( const QSharedPointer& s_params) -> std::tuple { return RunGpgOperaSync( + GetChannel(), [=](const DataObjectPtr& data_object) -> GpgError { return GenerateKeyWithSubkeyImpl(ctx_, key_getter_, p_params, s_params, data_object); }, - "gpgme_op_createkey&gpgme_op_createsubkey", "2.1.0"); + "gpgme_op_createkey&gpgme_op_createsubkey", "2.2.0"); } void GpgKeyOpera::ModifyPassword(const GpgKeyPtr& key, const GpgOperationCallback& callback) { RunGpgOperaAsync( + GetChannel(), [&key, &ctx = ctx_](const DataObjectPtr&) -> GpgError { return gpgme_op_passwd(ctx.DefaultContext(), static_cast(*key), 0); }, - callback, "gpgme_op_passwd", "2.0.15"); + callback, "gpgme_op_passwd", "2.2.0"); } auto GpgKeyOpera::ModifyTOFUPolicy( const GpgKeyPtr& key, gpgme_tofu_policy_t tofu_policy) -> GpgError { - const auto gnupg_version = Module::RetrieveRTValueTypedOrDefault<>( - "core", "gpgme.ctx.gnupg_version", QString{"2.0.0"}); - LOG_D() << "got gnupg version from rt: " << gnupg_version; - - if (GFCompareSoftwareVersion(gnupg_version, "2.1.10") < 0) { - FLOG_W("operator not support"); - return GPG_ERR_NOT_SUPPORTED; - } + auto [err, obj] = RunGpgOperaSync( + GetChannel(), + [=](const DataObjectPtr&) -> GpgError { + return gpgme_op_tofu_policy( + ctx_.DefaultContext(), static_cast(*key), tofu_policy); + }, + "gpgme_op_tofu_policy", "2.2.0"); - auto err = gpgme_op_tofu_policy(ctx_.DefaultContext(), - static_cast(*key), tofu_policy); return CheckGpgError(err); } @@ -388,6 +392,7 @@ auto AddADSKImpl(GpgContext& ctx, const GpgKeyPtr& key, const GpgSubKey& adsk, void GpgKeyOpera::AddADSK(const GpgKeyPtr& key, const GpgSubKey& adsk, const GpgOperationCallback& callback) { RunGpgOperaAsync( + GetChannel(), [=](const DataObjectPtr& data_object) -> GpgError { return AddADSKImpl(ctx_, key, adsk, data_object); }, @@ -397,6 +402,7 @@ void GpgKeyOpera::AddADSK(const GpgKeyPtr& key, const GpgSubKey& adsk, auto GpgKeyOpera::AddADSKSync(const GpgKeyPtr& key, const GpgSubKey& adsk) -> std::tuple { return RunGpgOperaSync( + GetChannel(), [=](const DataObjectPtr& data_object) -> GpgError { return AddADSKImpl(ctx_, key, adsk, data_object); }, diff --git a/src/core/function/gpg/GpgSmartCardManager.cpp b/src/core/function/gpg/GpgSmartCardManager.cpp index 5442ea88..203c36ec 100644 --- a/src/core/function/gpg/GpgSmartCardManager.cpp +++ b/src/core/function/gpg/GpgSmartCardManager.cpp @@ -30,17 +30,16 @@ #include "core/function/gpg/GpgAutomatonHandler.h" #include "core/utils/CommonUtils.h" +#include "core/utils/GpgUtils.h" namespace GpgFrontend { GpgSmartCardManager::GpgSmartCardManager(int channel) : SingletonFunctionObject(channel) {} -auto GpgSmartCardManager::Fetch(const QString& serial_number) -> bool { +auto GpgSmartCardManager::Fetch(const QString& serial_number) -> GpgError { GpgAutomatonHandler::AutomatonNextStateHandler next_state_handler = - [=](AutomatonState state, QString status, QString args) { - auto tokens = args.split(' '); - + [=](AutomatonState state, const QString& status, const QString& args) { switch (state) { case GpgAutomatonHandler::kAS_START: if (status == "GET_LINE" && args == "cardedit.prompt") { @@ -63,7 +62,7 @@ auto GpgSmartCardManager::Fetch(const QString& serial_number) -> bool { }; }; - AutomatonActionHandler action_handler = [](AutomatonHandelStruct& handler, + AutomatonActionHandler action_handler = [](AutomatonHandelStruct&, AutomatonState state) { switch (state) { case GpgAutomatonHandler::kAS_COMMAND: @@ -78,25 +77,22 @@ auto GpgSmartCardManager::Fetch(const QString& serial_number) -> bool { return QString(""); }; - return GpgAutomatonHandler::GetInstance(GetChannel()) - .DoCardInteract(serial_number, next_state_handler, action_handler); + auto [err, succ] = + GpgAutomatonHandler::GetInstance(GetChannel()) + .DoCardInteract(serial_number, next_state_handler, action_handler); + + if (err == GPG_ERR_NO_ERROR && !succ) return GPG_ERR_USER_1; + return err; } auto GpgSmartCardManager::IsSCDVersionSupported() -> bool { - auto [r, s] = assuan_.SendDataCommand(GpgComponentType::kGPG_AGENT, - "SCD GETINFO version"); - if (s.isEmpty()) { - LOG_D() << "invalid response of SCD GETINFO version: " << s; - return false; - } - - return GFCompareSoftwareVersion(s.front(), "2.3.0") > 0; + return GFSoftwareVersionGreaterThan(info_.GetScdaemonVersion(), "2.3.0"); } auto GpgSmartCardManager::GetSerialNumbers() -> QStringList { auto [r, s] = assuan_.SendStatusCommand(GpgComponentType::kGPG_AGENT, "SCD SERIALNO --all"); - if (!r) { + if (r != GPG_ERR_NO_ERROR) { cached_scd_serialno_status_hash_.clear(); cache_scd_card_serial_numbers_.clear(); return {}; @@ -112,9 +108,9 @@ auto GpgSmartCardManager::GetSerialNumbers() -> QStringList { cached_scd_serialno_status_hash_.clear(); cache_scd_card_serial_numbers_.clear(); - auto [ret, status] = assuan_.SendStatusCommand(GpgComponentType::kGPG_AGENT, + auto [err, status] = assuan_.SendStatusCommand(GpgComponentType::kGPG_AGENT, "SCD GETINFO all_active_apps"); - if (!ret || status.empty()) { + if (err != GPG_ERR_NO_ERROR || status.empty()) { LOG_D() << "command SCD GETINFO all_active_apps failed, resetting..."; return {}; } @@ -142,14 +138,14 @@ auto GpgSmartCardManager::GetSerialNumbers() -> QStringList { } auto GpgSmartCardManager::SelectCardBySerialNumber(const QString& serial_number) - -> std::tuple { + -> std::tuple { if (serial_number.isEmpty()) return {false, "Serial Number is empty."}; - auto [ret, status] = assuan_.SendStatusCommand( + auto [err, status] = assuan_.SendStatusCommand( GpgComponentType::kGPG_AGENT, QString("SCD SERIALNO --demand=%1 openpgp").arg(serial_number)); - if (!ret || status.isEmpty()) { - return {false, status.join(' ')}; + if (err != GPG_ERR_NO_ERROR || status.isEmpty()) { + return {err, status.join(' ')}; } auto line = status.front(); @@ -157,22 +153,21 @@ auto GpgSmartCardManager::SelectCardBySerialNumber(const QString& serial_number) if (token.size() != 2) { LOG_E() << "invalid response of command SERIALNO: " << line; - return {false, line}; + return {GPG_ERR_USER_1, line}; } LOG_D() << "selected smart card by serial number: " << serial_number; - - return {true, {}}; + return {err, {}}; } auto GpgSmartCardManager::FetchCardInfoBySerialNumber( const QString& serial_number) -> QSharedPointer { if (serial_number.trimmed().isEmpty()) return nullptr; - auto [ret, status] = assuan_.SendStatusCommand( + auto [err, status] = assuan_.SendStatusCommand( GpgComponentType::kGPG_AGENT, "SCD LEARN --force " + serial_number); - if (!ret || status.isEmpty()) { - LOG_E() << "scd learn failed: " << status; + if (err != GPG_ERR_NO_ERROR || status.isEmpty()) { + LOG_E() << "scd learn failed, err: " << CheckGpgError(err) << "" << status; return nullptr; } @@ -201,7 +196,7 @@ auto PercentDataEscape(const QByteArray& data, bool plus_escape = false, } } - for (unsigned char ch : data) { + for (char ch : data) { if (ch == '\0') { result += "%00"; } else if (ch == '%') { @@ -219,29 +214,25 @@ auto PercentDataEscape(const QByteArray& data, bool plus_escape = false, } auto GpgSmartCardManager::ModifyAttr(const QString& attr, const QString& value) - -> std::tuple { + -> std::tuple { if (attr.trimmed().isEmpty() || value.trimmed().isEmpty()) { - return {false, "ATTR or Value is empty"}; + return {GPG_ERR_INV_ARG, "ATTR or Value is empty"}; } const auto command = QString("SCD SETATTR %1 ").arg(attr); const auto escaped_command = PercentDataEscape(value.trimmed().toUtf8(), true, command); - auto [r, s] = + auto [err, status] = assuan_.SendStatusCommand(GpgComponentType::kGPG_AGENT, escaped_command); - - if (!r) { - LOG_E() << "SCD SETATTR command failed for attr" << attr; - return {false, s.join(' ')}; - } - - return {true, {}}; + return {err, status.join(' ')}; } auto GpgSmartCardManager::ModifyPin(const QString& pin_ref) - -> std::tuple { - if (pin_ref.trimmed().isEmpty()) return {false, "PIN Reference is empty"}; + -> std::tuple { + if (pin_ref.trimmed().isEmpty()) { + return {GPG_ERR_INV_ARG, "PIN Reference is empty"}; + } QString command; if (pin_ref == "OPENPGP.1") { @@ -254,23 +245,17 @@ auto GpgSmartCardManager::ModifyPin(const QString& pin_ref) command = QString("SCD PASSWD %1").arg(pin_ref); } - auto [success, status] = + auto [err, status] = assuan_.SendStatusCommand(GpgComponentType::kGPG_AGENT, command); - - if (!success) { - LOG_E() << "modify pin of smart failed: " << status; - return {false, status.join(' ')}; - } - - return {true, {}}; + return {err, status.join(' ')}; } auto GpgSmartCardManager::GenerateKey( const QString& serial_number, const QString& name, const QString& email, const QString& comment, const QDateTime& expire, - bool non_expire) -> std::tuple { + bool non_expire) -> std::tuple { if (name.isEmpty() || email.isEmpty()) { - return {false, "name or email is empty"}; + return {GPG_ERR_INV_ARG, "name or email is empty"}; } qint64 days_before_expire = 0; @@ -280,8 +265,6 @@ auto GpgSmartCardManager::GenerateKey( GpgAutomatonHandler::AutomatonNextStateHandler next_state_handler = [=](AutomatonState state, const QString& status, const QString& args) { - auto tokens = args.split(' '); - switch (state) { case GpgAutomatonHandler::kAS_START: if (status == "GET_LINE" && args == "cardedit.prompt") { @@ -382,9 +365,10 @@ auto GpgSmartCardManager::GenerateKey( return QString{}; }; - return { + auto [err, succ] = GpgAutomatonHandler::GetInstance(GetChannel()) - .DoCardInteract(serial_number, next_state_handler, action_handler), - "unknown error"}; + .DoCardInteract(serial_number, next_state_handler, action_handler); + if (err == GPG_ERR_NO_ERROR && !succ) return {GPG_ERR_USER_1, {}}; + return {err, {}}; } } // namespace GpgFrontend \ No newline at end of file diff --git a/src/core/function/gpg/GpgSmartCardManager.h b/src/core/function/gpg/GpgSmartCardManager.h index 2fe194f3..02b07fa2 100644 --- a/src/core/function/gpg/GpgSmartCardManager.h +++ b/src/core/function/gpg/GpgSmartCardManager.h @@ -30,9 +30,9 @@ #include "core/function/basic/GpgFunctionObject.h" #include "core/function/gpg/GpgAssuanHelper.h" +#include "core/function/gpg/GpgComponentInfoGetter.h" #include "core/function/gpg/GpgContext.h" #include "core/model/GpgOpenPGPCard.h" -#include "core/typedef/GpgTypedef.h" namespace GpgFrontend { @@ -63,7 +63,8 @@ class GPGFRONTEND_CORE_EXPORT GpgSmartCardManager * * @return std::tuple */ - auto SelectCardBySerialNumber(const QString&) -> std::tuple; + auto SelectCardBySerialNumber(const QString&) + -> std::tuple; /** * @brief @@ -81,7 +82,7 @@ class GPGFRONTEND_CORE_EXPORT GpgSmartCardManager * @return true * @return false */ - auto Fetch(const QString& serial_number) -> bool; + auto Fetch(const QString& serial_number) -> GpgError; /** * @brief @@ -89,7 +90,7 @@ class GPGFRONTEND_CORE_EXPORT GpgSmartCardManager * @return std::tuple */ auto ModifyAttr(const QString& attr, - const QString& value) -> std::tuple; + const QString& value) -> std::tuple; /** * @brief @@ -97,7 +98,7 @@ class GPGFRONTEND_CORE_EXPORT GpgSmartCardManager * @param pin_ref * @return std::tuple */ - auto ModifyPin(const QString& pin_ref) -> std::tuple; + auto ModifyPin(const QString& pin_ref) -> std::tuple; /** * @brief @@ -107,7 +108,7 @@ class GPGFRONTEND_CORE_EXPORT GpgSmartCardManager auto GenerateKey(const QString& serial_number, const QString& name, const QString& email, const QString& comment, const QDateTime& expire, - bool non_expire) -> std::tuple; + bool non_expire) -> std::tuple; /** * @brief @@ -122,6 +123,9 @@ class GPGFRONTEND_CORE_EXPORT GpgSmartCardManager GpgContext::GetInstance(SingletonFunctionObject::GetChannel()); ///< GpgAssuanHelper& assuan_ = GpgAssuanHelper::GetInstance(SingletonFunctionObject::GetChannel()); ///< + GpgComponentInfoGetter& info_ = GpgComponentInfoGetter::GetInstance( + SingletonFunctionObject::GetChannel()); ///< + QString cached_scd_serialno_status_hash_; QContainer cache_scd_card_serial_numbers_; }; diff --git a/src/core/function/gpg/GpgUIDOperator.cpp b/src/core/function/gpg/GpgUIDOperator.cpp index e07b4192..ca056be0 100644 --- a/src/core/function/gpg/GpgUIDOperator.cpp +++ b/src/core/function/gpg/GpgUIDOperator.cpp @@ -29,7 +29,6 @@ #include "GpgUIDOperator.h" #include "core/function/gpg/GpgAutomatonHandler.h" -#include "core/model/GpgData.h" #include "core/utils/GpgUtils.h" namespace GpgFrontend { @@ -65,8 +64,8 @@ auto GpgUIDOperator::DeleteUID(const GpgKeyPtr& key, int uid_index) -> bool { } AutomatonNextStateHandler next_state_handler = [](AutomatonState state, - QString status, - QString args) { + const QString& status, + const QString& args) { auto tokens = args.split(' '); switch (state) { @@ -124,15 +123,14 @@ auto GpgUIDOperator::DeleteUID(const GpgKeyPtr& key, int uid_index) -> bool { return QString("Y"); case GpgAutomatonHandler::kAS_START: case GpgAutomatonHandler::kAS_ERROR: - return QString(""); default: return QString(""); } return QString(""); }; - return GpgAutomatonHandler::GetInstance(GetChannel()) - .DoInteract(key, next_state_handler, action_handler); + auto [err, succ] = auto_.DoInteract(key, next_state_handler, action_handler); + return err == GPG_ERR_NO_ERROR && !succ; } auto GpgUIDOperator::RevokeUID(const GpgKeyPtr& key, int uid_index, @@ -153,8 +151,8 @@ auto GpgUIDOperator::RevokeUID(const GpgKeyPtr& key, int uid_index, reason_text.split('\n', Qt::SkipEmptyParts)); AutomatonNextStateHandler next_state_handler = [](AutomatonState state, - QString status, - QString args) { + const QString& status, + const QString& args) { auto tokens = args.split(' '); switch (state) { @@ -240,15 +238,14 @@ auto GpgUIDOperator::RevokeUID(const GpgKeyPtr& key, int uid_index, return QString("Y"); case GpgAutomatonHandler::kAS_START: case GpgAutomatonHandler::kAS_ERROR: - return QString(""); default: return QString(""); } return QString(""); }; - return GpgAutomatonHandler::GetInstance(GetChannel()) - .DoInteract(key, next_state_handler, action_handler); + auto [err, succ] = auto_.DoInteract(key, next_state_handler, action_handler); + return err == GPG_ERR_NO_ERROR && !succ; } } // namespace GpgFrontend diff --git a/src/core/function/gpg/GpgUIDOperator.h b/src/core/function/gpg/GpgUIDOperator.h index e5e2f190..0e222388 100644 --- a/src/core/function/gpg/GpgUIDOperator.h +++ b/src/core/function/gpg/GpgUIDOperator.h @@ -28,6 +28,7 @@ #pragma once +#include "core/function/gpg/GpgAutomatonHandler.h" #include "core/function/gpg/GpgContext.h" #include "core/typedef/GpgTypedef.h" @@ -100,6 +101,8 @@ class GPGFRONTEND_CORE_EXPORT GpgUIDOperator private: GpgContext& ctx_ = GpgContext::GetInstance(SingletonFunctionObject::GetChannel()); ///< + GpgAutomatonHandler& auto_ = GpgAutomatonHandler::GetInstance( + SingletonFunctionObject::GetChannel()); ///< }; } // namespace GpgFrontend diff --git a/src/core/utils/AsyncUtils.cpp b/src/core/utils/AsyncUtils.cpp index a4bc66fa..a3ab9eb8 100644 --- a/src/core/utils/AsyncUtils.cpp +++ b/src/core/utils/AsyncUtils.cpp @@ -28,24 +28,20 @@ #include "AsyncUtils.h" +#include "core/model/DataObject.h" #include "core/module/ModuleManager.h" #include "core/thread/Task.h" #include "core/thread/TaskRunnerGetter.h" -#include "core/utils/CommonUtils.h" -#include "model/DataObject.h" +#include "core/utils/GpgUtils.h" namespace GpgFrontend { -auto RunGpgOperaAsync(const GpgOperaRunnable& runnable, +auto RunGpgOperaAsync(int channel, const GpgOperaRunnable& runnable, const GpgOperationCallback& callback, - const QString& operation, const QString& minial_version) + const QString& operation, const QString& minimal_version) -> Thread::Task::TaskHandler { - const auto gnupg_version = Module::RetrieveRTValueTypedOrDefault<>( - "core", "gpgme.ctx.gnupg_version", minial_version); - - if (GFCompareSoftwareVersion(gnupg_version, minial_version) < 0) { - LOG_W() << "operation" << operation - << " not support for gnupg version: " << gnupg_version; + if (!CheckGpgVersion(channel, minimal_version)) { + LOG_W() << "operation: " << operation << "is not supported."; callback(GPG_ERR_NOT_SUPPORTED, TransferParams()); return Thread::Task::TaskHandler(nullptr); } @@ -75,15 +71,11 @@ auto RunGpgOperaAsync(const GpgOperaRunnable& runnable, return handler; } -auto RunGpgOperaSync(const GpgOperaRunnable& runnable, const QString& operation, - const QString& minial_version) +auto RunGpgOperaSync(int channel, const GpgOperaRunnable& runnable, + const QString& operation, const QString& minimal_version) -> std::tuple { - const auto gnupg_version = Module::RetrieveRTValueTypedOrDefault<>( - "core", "gpgme.ctx.gnupg_version", minial_version); - - if (GFCompareSoftwareVersion(gnupg_version, minial_version) < 0) { - LOG_W() << "operation" << operation - << " not support for gnupg version: " << gnupg_version; + if (!CheckGpgVersion(channel, minimal_version)) { + LOG_W() << "operation: " << operation << "is not supported."; return {GPG_ERR_NOT_SUPPORTED, TransferParams()}; } diff --git a/src/core/utils/AsyncUtils.h b/src/core/utils/AsyncUtils.h index eb55cf89..5be3b230 100644 --- a/src/core/utils/AsyncUtils.h +++ b/src/core/utils/AsyncUtils.h @@ -41,24 +41,24 @@ namespace GpgFrontend { * @param runnable * @param callback * @param operation - * @param minial_version + * @param minimal_version */ auto GPGFRONTEND_CORE_EXPORT -RunGpgOperaAsync(const GpgOperaRunnable& runnable, +RunGpgOperaAsync(int channel, const GpgOperaRunnable& runnable, const GpgOperationCallback& callback, const QString& operation, - const QString& minial_version) -> Thread::Task::TaskHandler; + const QString& minimal_version) -> Thread::Task::TaskHandler; /** * @brief * * @param runnable * @param operation - * @param minial_version + * @param minimal_version * @return std::tuple */ auto GPGFRONTEND_CORE_EXPORT RunGpgOperaSync( - const GpgOperaRunnable& runnable, const QString& operation, - const QString& minial_version) -> std::tuple; + int channel, const GpgOperaRunnable& runnable, const QString& operation, + const QString& minimal_version) -> std::tuple; /** * @brief diff --git a/src/core/utils/CommonUtils.cpp b/src/core/utils/CommonUtils.cpp index ce36c71e..eec5deef 100644 --- a/src/core/utils/CommonUtils.cpp +++ b/src/core/utils/CommonUtils.cpp @@ -74,6 +74,11 @@ auto GFCompareSoftwareVersion(const QString& a, const QString& b) -> int { return 0; } +auto GFSoftwareVersionGreaterThan(const QString& a, const QString& b) -> bool { + if (a.isEmpty()) return false; + return GFCompareSoftwareVersion(a, b) > 0; +} + auto GFStrDup(const QString& s) -> char* { if (s.isEmpty()) return nullptr; diff --git a/src/core/utils/CommonUtils.h b/src/core/utils/CommonUtils.h index d62f4867..b7d18891 100644 --- a/src/core/utils/CommonUtils.h +++ b/src/core/utils/CommonUtils.h @@ -90,4 +90,14 @@ auto GPGFRONTEND_CORE_EXPORT ParseHexEncodedVersionTuple(const QString &s) */ auto GPGFRONTEND_CORE_EXPORT IsEmailAddress(const QString &) -> bool; +/** + * @brief if a > b + * + * @param a + * @param b + * @return auto + */ +auto GPGFRONTEND_CORE_EXPORT +GFSoftwareVersionGreaterThan(const QString &a, const QString &b) -> bool; + } // namespace GpgFrontend \ No newline at end of file diff --git a/src/core/utils/GpgUtils.cpp b/src/core/utils/GpgUtils.cpp index b8824673..13f6ef05 100644 --- a/src/core/utils/GpgUtils.cpp +++ b/src/core/utils/GpgUtils.cpp @@ -30,12 +30,15 @@ #include "core/function/GlobalSettingStation.h" #include "core/function/gpg/GpgAbstractKeyGetter.h" +#include "core/function/gpg/GpgComponentInfoGetter.h" #include "core/model/GpgKey.h" #include "core/model/GpgKeyGroup.h" #include "core/model/KeyDatabaseInfo.h" #include "core/model/SettingsObject.h" #include "core/module/ModuleManager.h" #include "core/struct/settings_object/KeyDatabaseListSO.h" +#include "core/utils/CommonUtils.h" + namespace GpgFrontend { inline auto Trim(QString& s) -> QString { return s.trimmed(); } @@ -424,4 +427,33 @@ auto GPGFRONTEND_CORE_EXPORT IsKeyGroupID(const KeyId& id) -> bool { return id.startsWith("#&"); } +auto GPGFRONTEND_CORE_EXPORT +GpgAgentVersionGreaterThan(int channel, const QString& v) -> bool { + return GFSoftwareVersionGreaterThan( + GpgComponentInfoGetter::GetInstance(channel).GetGpgAgentVersion(), v); +} + +auto GPGFRONTEND_CORE_EXPORT CheckGpgVersion(int channel, + const QString& v) -> bool { + const auto ver = + GpgComponentInfoGetter::GetInstance(channel).GetGpgAgentVersion(); + + if (ver.isEmpty() || !GFSoftwareVersionGreaterThan(ver, v)) { + LOG_W() << "operation not support for gpg-agent version: " << ver + << "minimal version: " << v; + return false; + } + + const auto gnupg_version = Module::RetrieveRTValueTypedOrDefault<>( + "core", "gpgme.ctx.gnupg_version", QString{}); + + if (gnupg_version.isEmpty() || + GFCompareSoftwareVersion(gnupg_version, v) < 0) { + LOG_W() << "operation not support for gnupg version: " << gnupg_version + << "minimal version: " << v; + return false; + } + + return true; +} } // namespace GpgFrontend diff --git a/src/core/utils/GpgUtils.h b/src/core/utils/GpgUtils.h index 13612b4f..d0fe1701 100644 --- a/src/core/utils/GpgUtils.h +++ b/src/core/utils/GpgUtils.h @@ -202,4 +202,23 @@ auto GPGFRONTEND_CORE_EXPORT GetGpgKeyByGpgAbstractKey(GpgAbstractKey*) * @return false */ auto GPGFRONTEND_CORE_EXPORT IsKeyGroupID(const KeyId& id) -> bool; + +/** + * @brief + * + * @return bool + */ +auto GPGFRONTEND_CORE_EXPORT GpgAgentVersionGreaterThan(int channel, + const QString&) -> bool; + +/** + * @brief + * + * @param channel + * @return true + * @return false + */ +auto GPGFRONTEND_CORE_EXPORT CheckGpgVersion(int channel, + const QString&) -> bool; + } // namespace GpgFrontend \ No newline at end of file diff --git a/src/init.cpp b/src/init.cpp index 71f24668..3d1f344b 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -184,9 +184,15 @@ void ShutdownGlobalBasicEnv(const GFCxtWPtr &p_ctx) { .toBool(); if (ctx->unit_test_mode || kill_all_gnupg_daemon_at_close) { - GpgAdvancedOperator::KillAllGpgComponents(nullptr); + const auto size = GpgContext::GetAllChannelId().size(); + for (auto i = 0; i < size; i++) { + assert(GpgAdvancedOperator::GetInstance().KillAllGpgComponents()); + } } else if (!ctx->unit_test_mode && clear_gpg_password_cache) { - GpgAdvancedOperator::ClearGpgPasswordCache(nullptr); + const auto size = GpgContext::GetAllChannelId().size(); + for (auto i = 0; i < size; i++) { + assert(GpgAdvancedOperator::GetInstance().ClearGpgPasswordCache()); + } } // first should shutdown the module system diff --git a/src/ui/UserInterfaceUtils.cpp b/src/ui/UserInterfaceUtils.cpp index 8d277ab4..ed76824a 100644 --- a/src/ui/UserInterfaceUtils.cpp +++ b/src/ui/UserInterfaceUtils.cpp @@ -167,16 +167,17 @@ void CommonUtils::RaiseMessageBox(QWidget *parent, GpgError err) { } } -void CommonUtils::RaiseFailureMessageBox(QWidget *parent, GpgError err) { +void CommonUtils::RaiseFailureMessageBox(QWidget *parent, GpgError err, + const QString &msg) { GpgErrorDesc desc = DescribeGpgErrCode(err); GpgErrorCode err_code = CheckGpgError2ErrCode(err); QMessageBox::critical(parent, tr("Failure"), - tr("Gpg Operation failed.\n\nError code: %1\nSource: " - " %2\nDescription: %3") - .arg(err_code) - .arg(desc.first) - .arg(desc.second)); + tr("Gpg Operation failed.") + "\n\n" + + tr("Error code: %1").arg(err_code) + "\n\n\n" + + tr("Source: %1").arg(desc.first) + "\n" + + tr("Description: %1").arg(desc.second) + "\n" + + tr("Error Message: %1").arg(msg)); } void CommonUtils::SlotImportKeys(QWidget *parent, int channel, diff --git a/src/ui/UserInterfaceUtils.h b/src/ui/UserInterfaceUtils.h index fe912fcf..b544ffc3 100644 --- a/src/ui/UserInterfaceUtils.h +++ b/src/ui/UserInterfaceUtils.h @@ -113,7 +113,8 @@ class CommonUtils : public QWidget { * * @param err */ - static void RaiseFailureMessageBox(QWidget* parent, GpgError err); + static void RaiseFailureMessageBox(QWidget* parent, GpgError err, + const QString& msg = {}); /** * @brief diff --git a/src/ui/dialog/ADSKsPicker.cpp b/src/ui/dialog/ADSKsPicker.cpp index 878c5e96..56039a15 100644 --- a/src/ui/dialog/ADSKsPicker.cpp +++ b/src/ui/dialog/ADSKsPicker.cpp @@ -115,8 +115,7 @@ void ADSKsPicker::slot_add_adsk(const QContainer& s_keys) { for (const auto& info : err_sub_key_infos) { failed_info.append(info); } - QString details = failed_info.join("\n\n"); - + auto details = failed_info.join("\n\n"); auto* msg_box = new QMessageBox(nullptr); msg_box->setIcon(QMessageBox::Warning); msg_box->setWindowTitle(err_sub_key_infos.size() == s_keys.size() diff --git a/src/ui/dialog/controller/SmartCardControllerDialog.cpp b/src/ui/dialog/controller/SmartCardControllerDialog.cpp index 73dd48b9..797fe052 100644 --- a/src/ui/dialog/controller/SmartCardControllerDialog.cpp +++ b/src/ui/dialog/controller/SmartCardControllerDialog.cpp @@ -33,6 +33,7 @@ #include "core/function/gpg/GpgSmartCardManager.h" #include "core/utils/GpgUtils.h" #include "ui/UISignalStation.h" +#include "ui/UserInterfaceUtils.h" #include "ui/dialog/key_generate/GenerateCardKeyDialog.h" // @@ -110,18 +111,22 @@ SmartCardControllerDialog::SmartCardControllerDialog(QWidget* parent) [=](bool) { modify_key_pin("OPENPGP.2"); }); connect(ui_->restartGpgAgentButton, &QPushButton::clicked, this, [=](bool) { - GpgFrontend::GpgAdvancedOperator::RestartGpgComponents( - [=](int err, DataObjectPtr) { - if (err >= 0) { - QMessageBox::information( - this, tr("Successful Operation"), - tr("Restart all the GnuPG's components successfully")); - } else { - QMessageBox::critical( - this, tr("Failed Operation"), - tr("Failed to restart all or one of the GnuPG's component(s)")); - } - }); + bool ret = true; + const auto size = GpgContext::GetAllChannelId().size(); + for (auto i = 0; i < size; i++) { + ret = GpgAdvancedOperator::GetInstance().RestartGpgComponents(); + if (!ret) break; + } + + if (ret) { + QMessageBox::information( + this, tr("Successful Operation"), + tr("Restart all the GnuPG's components successfully")); + } else { + QMessageBox::critical( + this, tr("Failed Operation"), + tr("Failed to restart all or one of the GnuPG's component(s)")); + } }); connect(ui_->generateKeysButton, &QPushButton::clicked, this, [=](bool) { @@ -163,11 +168,13 @@ void SmartCardControllerDialog::select_smart_card_by_serial_number( return; } - auto [ret, err] = + auto [err, status] = GpgSmartCardManager::GetInstance(channel_).SelectCardBySerialNumber( serial_number); - if (!ret) { - LOG_E() << "select card by serial number failed: " << err; + if (err != GPG_ERR_NO_ERROR) { + LOG_E() << "select card by serial number failed, err:" << CheckGpgError(err) + << "status:" << status; + CommonUtils::RaiseFailureMessageBox(this, err, status); reset_status(); return; } @@ -188,6 +195,7 @@ void SmartCardControllerDialog::fetch_smart_card_info( GpgSmartCardManager::GetInstance(channel_).FetchCardInfoBySerialNumber( serial_number); if (card_info == nullptr) { + LOG_E() << "card info is nullptr, serial number:" << serial_number; reset_status(); return; } @@ -446,9 +454,14 @@ void SmartCardControllerDialog::slot_disable_controllers(bool disable) { void SmartCardControllerDialog::slot_fetch_smart_card_keys() { ui_->fetchButton->setDisabled(true); - GpgSmartCardManager::GetInstance().Fetch( + auto err = GpgSmartCardManager::GetInstance().Fetch( ui_->currentCardComboBox->currentText()); + if (err != GPG_ERR_NO_ERROR) { + CommonUtils::RaiseFailureMessageBox(this, err); + return; + } + QTimer::singleShot(1000, [=]() { GpgCommandExecutor::GetInstance(channel_).GpgExecuteSync( {{}, @@ -524,14 +537,13 @@ void SmartCardControllerDialog::modify_key_attribute(const QString& attr) { } } - auto [r, err] = + auto [err, status] = GpgSmartCardManager::GetInstance(channel_).ModifyAttr(attr, value); - if (!r) { - LOG_D() << "SCD SETATTR command failed for attr" << attr; - QMessageBox::critical( - this, tr("Failed"), - tr("Failed to set attribute '%1'. Reason: %2. ").arg(attr).arg(err)); + if (err != GPG_ERR_NO_ERROR) { + LOG_D() << "SCD SETATTR command failed for attr:" << attr + << ", err:" << CheckGpgError(err); + CommonUtils::RaiseFailureMessageBox(this, err, status); return; } QMessageBox::information(this, tr("Success"), @@ -540,22 +552,11 @@ void SmartCardControllerDialog::modify_key_attribute(const QString& attr) { } void SmartCardControllerDialog::modify_key_pin(const QString& pinref) { - auto [success, err] = + auto [err, status] = GpgSmartCardManager::GetInstance(channel_).ModifyPin(pinref); - if (!success) { - QString message; - if (pinref == "OPENPGP.3") { - message = tr("Failed to change Admin PIN."); - } else if (pinref == "OPENPGP.2") { - message = tr("Failed to set the Reset Code."); - } else { - message = tr("Failed to change PIN."); - } - - message += tr("Reason: ") + err; - - QMessageBox::critical(this, tr("Error"), message); + if (err != GPG_ERR_NO_ERROR) { + CommonUtils::RaiseFailureMessageBox(this, err, status); return; } diff --git a/src/ui/function/GpgOperaHelper.cpp b/src/ui/function/GpgOperaHelper.cpp index 91bc6c38..82742b93 100644 --- a/src/ui/function/GpgOperaHelper.cpp +++ b/src/ui/function/GpgOperaHelper.cpp @@ -90,6 +90,12 @@ auto GpgOperaHelper::BuildSimpleGpgFileOperasHelper( // stop waiting op_hd(); + if (CheckGpgError(err) == GPG_ERR_NOT_SUPPORTED) { + opera_results.append({-1, "# " + tr("Operation Not Supported"), + QFileInfo(path).fileName()}); + return; + } + if (CheckGpgError(err) == GPG_ERR_USER_1 || data_obj == nullptr || !data_obj->Check()) { opera_results.append( @@ -126,6 +132,12 @@ auto GpgOperaHelper::BuildComplexGpgFileOperasHelper( // stop waiting op_hd(); + if (CheckGpgError(err) == GPG_ERR_NOT_SUPPORTED) { + opera_results.append({-1, "# " + tr("Operation Not Supported"), + QFileInfo(path).fileName()}); + return; + } + if (CheckGpgError(err) == GPG_ERR_USER_1 || data_obj == nullptr || !data_obj->Check()) { opera_results.append( @@ -169,6 +181,11 @@ auto GpgOperaHelper::BuildSimpleGpgOperasHelper( // stop waiting op_hd(); + if (CheckGpgError(err) == GPG_ERR_NOT_SUPPORTED) { + opera_results.append({-1, "# " + tr("Operation Not Supported"), {}}); + return; + } + if (CheckGpgError(err) == GPG_ERR_USER_1 || data_obj == nullptr || !data_obj->Check()) { opera_results.append({-1, "# " + tr("Critical Error"), {}}); @@ -207,6 +224,11 @@ auto GpgOperaHelper::BuildComplexGpgOperasHelper( // stop waiting op_hd(); + if (CheckGpgError(err) == GPG_ERR_NOT_SUPPORTED) { + opera_results.append({-1, "# " + tr("Operation Not Supported"), {}}); + return; + } + if (CheckGpgError(err) == GPG_ERR_USER_1 || data_obj == nullptr || !data_obj->Check()) { opera_results.append({-1, "# " + tr("Critical Error"), {}}); diff --git a/src/ui/main_window/MainWindow.h b/src/ui/main_window/MainWindow.h index 15fb9fb1..16092609 100644 --- a/src/ui/main_window/MainWindow.h +++ b/src/ui/main_window/MainWindow.h @@ -528,7 +528,7 @@ class MainWindow : public GeneralMainWindow { * * @param results */ - void slot_update_operations_menu_by_checked_keys(unsigned int type); + void slot_update_operations_menu_by_checked_keys(unsigned int mask); /** * @brief diff --git a/src/ui/main_window/MainWindowSlotUI.cpp b/src/ui/main_window/MainWindowSlotUI.cpp index e0a72ed1..6b945beb 100644 --- a/src/ui/main_window/MainWindowSlotUI.cpp +++ b/src/ui/main_window/MainWindowSlotUI.cpp @@ -311,46 +311,58 @@ void MainWindow::SlotGeneralDecryptVerify(bool) { } void MainWindow::slot_clean_gpg_password_cache(bool) { - GpgFrontend::GpgAdvancedOperator::ClearGpgPasswordCache( - [=](int err, DataObjectPtr) { - if (err >= 0) { - QMessageBox::information(this, tr("Successful Operation"), - tr("Clear password cache successfully")); - } else { - QMessageBox::critical(this, tr("Failed Operation"), - tr("Failed to clear password cache of GnuPG")); - } - }); + bool ret = true; + const auto size = GpgContext::GetAllChannelId().size(); + for (auto i = 0; i < size; i++) { + ret = GpgAdvancedOperator::GetInstance().ClearGpgPasswordCache(); + if (!ret) break; + } + + if (ret) { + QMessageBox::information(this, tr("Successful Operation"), + tr("Clear password cache successfully")); + } else { + QMessageBox::critical(this, tr("Failed Operation"), + tr("Failed to clear password cache of GnuPG")); + } } void MainWindow::slot_reload_gpg_components(bool) { - GpgFrontend::GpgAdvancedOperator::ReloadGpgComponents( - [=](int err, DataObjectPtr) { - if (err >= 0) { - QMessageBox::information( - this, tr("Successful Operation"), - tr("Reload all the GnuPG's components successfully")); - } else { - QMessageBox::critical( - this, tr("Failed Operation"), - tr("Failed to reload all or one of the GnuPG's component(s)")); - } - }); + bool ret = true; + const auto size = GpgContext::GetAllChannelId().size(); + for (auto i = 0; i < size; i++) { + ret = GpgAdvancedOperator::GetInstance().ReloadAllGpgComponents(); + if (!ret) break; + } + + if (ret) { + QMessageBox::information( + this, tr("Successful Operation"), + tr("Reload all the GnuPG's components successfully")); + } else { + QMessageBox::critical( + this, tr("Failed Operation"), + tr("Failed to reload all or one of the GnuPG's component(s)")); + } } void MainWindow::slot_restart_gpg_components(bool) { - GpgFrontend::GpgAdvancedOperator::RestartGpgComponents( - [=](int err, DataObjectPtr) { - if (err >= 0) { - QMessageBox::information( - this, tr("Successful Operation"), - tr("Restart all the GnuPG's components successfully")); - } else { - QMessageBox::critical( - this, tr("Failed Operation"), - tr("Failed to restart all or one of the GnuPG's component(s)")); - } - }); + bool ret = true; + const auto size = GpgContext::GetAllChannelId().size(); + for (auto i = 0; i < size; i++) { + ret = GpgAdvancedOperator::GetInstance().RestartGpgComponents(); + if (!ret) break; + } + + if (ret) { + QMessageBox::information( + this, tr("Successful Operation"), + tr("Restart all the GnuPG's components successfully")); + } else { + QMessageBox::critical( + this, tr("Failed Operation"), + tr("Failed to restart all or one of the GnuPG's component(s)")); + } } void MainWindow::slot_update_operations_menu_by_checked_keys( -- cgit v1.2.3 From 502a43488d51c88be33d95be11ba8f160c2a3fd4 Mon Sep 17 00:00:00 2001 From: saturneric Date: Fri, 18 Apr 2025 19:11:40 +0200 Subject: feat: add more basic env checks at init --- src/core/GpgCoreInit.cpp | 63 ++++++++++++++++++++++ src/core/function/gpg/GpgAutomatonHandler.h | 3 +- src/core/model/GpgKeyGenerateInfo.cpp | 26 ++++----- src/core/model/GpgKeyGenerateInfo.h | 6 +-- src/core/utils/GpgUtils.cpp | 19 +++++++ src/core/utils/GpgUtils.h | 6 +++ src/ui/UserInterfaceUtils.cpp | 8 +++ src/ui/UserInterfaceUtils.h | 7 +++ src/ui/dialog/key_generate/KeyGenerateDialog.cpp | 9 +++- .../dialog/key_generate/SubkeyGenerateDialog.cpp | 7 ++- src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp | 14 +++-- src/ui/main_window/KeyMgmt.cpp | 19 ++++--- 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( 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 { 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 -#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 KeyGenerateInfo::kSubKeyAlgos = { {"elg4096", "ELG-E", "ELG-E", 4096, kENCRYPT, "2.2.0"}, }; -auto KeyGenerateInfo::GetSupportedKeyAlgo() -> QContainer { - const auto gnupg_version = Module::RetrieveRTValueTypedOrDefault<>( - "core", "gpgme.ctx.gnupg_version", QString{"2.0.0"}); - +auto KeyGenerateInfo::GetSupportedKeyAlgo(int channel) -> QContainer { QContainer 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 { return algos; } -auto KeyGenerateInfo::GetSupportedSubkeyAlgo() -> QContainer { - const auto gnupg_version = Module::RetrieveRTValueTypedOrDefault<>( - "core", "gpgme.ctx.gnupg_version", QString{"2.0.0"}); - +auto KeyGenerateInfo::GetSupportedSubkeyAlgo(int channel) + -> QContainer { QContainer 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& */ - static auto GetSupportedKeyAlgo() -> QContainer; + static auto GetSupportedKeyAlgo(int channel) -> QContainer; /** * @brief Get the Supported Subkey Algo object * * @return const QContainer& */ - static auto GetSupportedSubkeyAlgo() -> QContainer; + static auto GetSupportedSubkeyAlgo(int channel) -> QContainer; /** * @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 @@ -108,6 +108,13 @@ class CommonUtils : public QWidget { */ static void RaiseMessageBox(QWidget* parent, GpgError err); + /** + * @brief + * + * @param err + */ + static void RaiseMessageBoxNotSupported(QWidget* parent); + /** * @brief * 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::create()), gen_key_info_(QSharedPointer::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::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(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( -- cgit v1.2.3 From d115562e6cb231356ef87a2ab86f4da1159a9e41 Mon Sep 17 00:00:00 2001 From: saturneric Date: Fri, 18 Apr 2025 19:35:45 +0200 Subject: fix: issues found on macos --- resource/lfs/locale/ts/GpgFrontend.de_DE.ts | 905 +++++++++++---------- resource/lfs/locale/ts/GpgFrontend.en_US.ts | 881 ++++++++++---------- resource/lfs/locale/ts/GpgFrontend.fr_FR.ts | 895 ++++++++++---------- resource/lfs/locale/ts/GpgFrontend.it_IT.ts | 899 ++++++++++---------- resource/lfs/locale/ts/GpgFrontend.zh_CN.ts | 905 +++++++++++---------- resource/lfs/locale/ts/GpgFrontend.zh_TW.ts | 891 ++++++++++---------- src/core/GpgCoreInit.cpp | 11 +- src/core/function/gpg/GpgContext.cpp | 4 +- src/core/utils/GpgUtils.cpp | 2 + src/ui/UserInterfaceUtils.cpp | 7 +- src/ui/dialog/controller/GnuPGControllerDialog.cpp | 3 +- src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp | 1 - src/ui/dialog/keypair_details/KeyPairSubkeyTab.h | 100 +-- src/ui/main_window/MainWindow.cpp | 19 +- 14 files changed, 2818 insertions(+), 2705 deletions(-) diff --git a/resource/lfs/locale/ts/GpgFrontend.de_DE.ts b/resource/lfs/locale/ts/GpgFrontend.de_DE.ts index f478e08a..500a2af6 100644 --- a/resource/lfs/locale/ts/GpgFrontend.de_DE.ts +++ b/resource/lfs/locale/ts/GpgFrontend.de_DE.ts @@ -492,7 +492,7 @@ GpgFrontend::KeyGenerateInfo - + None Kein @@ -586,22 +586,22 @@ Schlüssel-ID: %1 Grund: %2 - + Failed Fehlgeschlagen - + Partially Failed Teilweise fehlgeschlagen - + Failed to add all selected subkeys. Alle ausgewählten Unterschlüssel konnten nicht hinzugefügt werden. - + Some subkeys failed to be added as ADSKs. Einige Unterschlüssel konnten nicht als ADSKs hinzugefügt werden. @@ -769,13 +769,13 @@ GpgFrontend::UI::CommonUtils - + Timeout Zeitablauf - + Success Erfolg @@ -795,126 +795,148 @@ Gpg-Verarbeitung erfolgreich. - - + + Failure Fehler - - Gpg Operation failed. - -Error code: %1 -Source: %2 -Description: %3 - GPG Vorgang fehlgeschlagen - -Fehlercode: %1 -Quelle: %2 -Beschrei: %3 - - - - - - + + + + Error Fehler - + Open Key Schlüssel öffnen - + + Operation Not Supported + Vorgang nicht unterstützt + + + + The current GnuPG version is too low and does not support this operation. Please upgrade your GnuPG version to continue. + Die aktuelle GnuPG-Version ist zu alt und unterstützt diesen Vorgang nicht. Bitte aktualisieren Sie GnuPG, um fortzufahren. + + + + Gpg Operation failed. + GPG-Vorgang fehlgeschlagen. + + + + Error code: %1 + Fehlercode: %1 + + + + Source: %1 + Quelle: %1 + + + + Description: %1 + Beschreibung: %1 + + + + Error Message: %1 + Fehlermeldung: %1 + + + Keyring files Schlüsselbunddateien - + Cannot open this file. Please make sure that this is a regular file and it's readable. Kann diese Datei nicht öffnen. Bitte stellen Sie sicher, dass es sich um eine reguläre, lesbare Datei handelt. - + The target file is too large for a keyring. Die Zieldatei ist zu groß für einen Schlüsselring. - + File Open Failed Datei konnte nicht geöffnet werden - + Failed to open file: Datei konnte nicht geöffnet werden: - + Processing In Bearbeitung - + Failed to execute command. Fehler beim Ausführen des Befehls. - + Succeed in executing command. Befehl erfolgreich ausgeführt. - + Warning Warnung - + Finished executing command. Ausführung des Befehls abgeschlossen. - + Default Keyserver Not Found Standard-Keyserver nicht gefunden - + Cannot read default keyserver from your settings, please set a default keyserver first Der Standard-Keyserver kann nicht aus Ihren Einstellungen gelesen werden, bitte legen Sie zuerst einen Standard-Keyserver fest - + Key Not Found Schlüssel nicht gefunden - + Key Server Not Found Schlüsselserver nicht gefunden - + Connection Error Verbindungsfehler - + Key Not Found. Schlüssel nicht gefunden. - - + + The key has been updated Der Schlüssel wurde aktualisiert - - + + No need to update the key Keine Notwendigkeit, den Schlüssel zu aktualisieren @@ -1460,70 +1482,70 @@ This will result in loss of all cached form positions, statuses, key servers, et Echter Pfad - + Maximum Key Database Limit Reached Maximum Key Database Limit erreicht - + Currently, GpgFrontend supports a maximum of 8 key databases. Please remove an existing database to add a new one. Derzeit unterstützt GpgFrontend maximal 8 Schlüsseldatenbanken. Bitte entfernen Sie eine bestehende Datenbank, um eine neue hinzuzufügen. - - + + Duplicate Key Database Paths Doppelte Datenbankpfade für Schlüssel - + The newly added key database path duplicates a previously existing one. Der neu hinzugefügte Schlüsseldatenbankpfad dupliziert einen bereits vorhandenen Pfad. - - + + Invalid Key Database Paths Ungültige Schlüsseldatenbankpfade - - + + The edited key database path is not a valid path that GpgFrontend can use Der editierte Pfad zur Schlüsseldatenbank ist kein gültiger Pfad, den GpgFrontend verwenden kann - + Active Aktiv - + Inactive Inaktiv - + Confirm Deletion Bestätigen Sie die Löschung - + Are you sure you want to delete the selected key database? Sind Sie sicher, dass Sie die ausgewählte Schlüsseldatenbank löschen wollen? - + No Key Database Selected Keine Schlüsseldatenbank ausgewählt - + Please select a key database to edit. Bitte wählen Sie eine Schlüsseldatenbank zur Bearbeitung aus. - + The edited key database path duplicates a previously existing one. Der bearbeitete Schlüsseldatenbankpfad dupliziert einen bereits vorhandenen Pfad. @@ -1560,7 +1582,7 @@ This will result in loss of all cached form positions, statuses, key servers, et - + Illegal GnuPG Path Unzulässiger GnuPG-Pfad @@ -1575,7 +1597,7 @@ This will result in loss of all cached form positions, statuses, key servers, et Der Ziel-GnuPG-Pfad ist kein absoluter Pfad. - + Target GnuPG Path contains no "gpgconf" executable. Der Ziel-GnuPG-Pfad enthält keine ausführbare Datei „gpgconf“. @@ -1606,10 +1628,18 @@ This will result in loss of all cached form positions, statuses, key servers, et GpgFrontend::UI::GpgOperaHelper - - - - + + + + + Operation Not Supported + Operation nicht unterstützt + + + + + + Critical Error Kritischer Fehler @@ -1827,218 +1857,218 @@ This will result in loss of all cached form positions, statuses, key servers, et GpgFrontend::UI::KeyGenerateDialog - - - - + + + + Custom Benutzerdefiniert - - + + 3 Months 3 Monate - - + + 6 Months 6 Monate - - + + 1 Year 1 Jahr - - - - + + + + 2 Years 2 Jahre - - + + 5 Years 5 Jahre - - + + 10 Years 10 Jahre - - - - + + + + Non Expired Nicht abgelaufen - - - + + + Primary Key Only Nur Primärschlüssel - - + + Primary Key With Subkey Primärschlüssel mit Unterschlüssel - + Name Name - + Email E-Mail - + Comment Kommentar - + Key Database Schlüsseldatenbank - - - + + + Algorithm Algorithmus - - + + Validity Period Gültigkeitsdauer - - + + Key Length Länge des Schlüssels - - + + Usage Verwendungszweck - - + + Encrypt Verschlüsseln - - + + Sign Unterschreiben - - + + Authentication Authentifizierung - + No Passphrase Keine Passphrase - + Expire Date Ablaufdatum - + Easy Mode Einfacher Modus - + Primary Key Primärschlüssel - + Subkey Unterschlüssel - + Generate Erstellen - - + + None Kein - + Generate Key Schlüssel erstellen - + Name must contain at least five characters. Der Name muss mindestens fünf Zeichen enthalten. - + Please give a valid email address. Bitte geben Sie eine gültige E-Mail Adresse an. - + Please give a valid primary key algorithm. Bitte geben Sie einen gültigen Primärschlüssel-Algorithmus an. - + Time to primary key expiration must not be less than 120 seconds. Die Zeit bis zum Ablauf des Primärschlüssels darf nicht weniger als 120 Sekunden betragen. - + Please give a valid subkey algorithm. Bitte geben Sie einen gültigen Unterschlüssel-Algorithmus an. - + Time to subkey expiration must not be less than 120 seconds. Die Zeit bis zum Ablauf des Unterschlüssels darf nicht weniger als 120 Sekunden betragen. - + Error Fehler - + Unknown error occurred Unbekannter Fehler ist aufgetreten - + Generating Erstellen @@ -2492,7 +2522,7 @@ Diese Schlüssel sind nicht mehr verfügbar. Möchten Sie sie aus der Gruppe ent - + Key Package Schlüsselpaket @@ -2614,22 +2644,22 @@ Diese Schlüssel sind nicht mehr verfügbar. Möchten Sie sie aus der Gruppe ent - - - - - - - - + + + + + + + + Error Fehler - - + + Forbidden Verboten @@ -2641,102 +2671,102 @@ Diese Schlüssel sind nicht mehr verfügbar. Möchten Sie sie aus der Gruppe ent - + key(s) exported Schlüssel exportiert - + Exporting Exportiere - - + + Unknown error occurred Unbekannter Fehler ist aufgetreten - + Invalid Operation Ungültige Operation - + If a key pair does not have a private key then it will not be able to generate sub-keys. Wenn ein Schlüsselpaar keinen privaten Schlüssel hat, kann es keine Unterschlüssel generieren. - + Please check a key before performing this operation. Bitte wählen Sie einen Schlüssel aus, bevor Sie diesen Vorgang starten. - + This operation accepts just a single key. Dieser Vorgang kann nur für einen einzelnen Schlüssel ausgeführt werden. - + This key may not be able to export as OpenSSH format. Please check the key-size of the subkey(s) used to sign. Dieser Schlüssel kann möglicherweise nicht im OpenSSH-Format exportiert werden. Bitte überprüfen Sie die Schlüsselgröße der zum Signieren verwendeten Unterschlüssel. - + Export OpenSSH Key To File OpenSSH-Schlüssel in eine Datei exportieren - + OpenSSH Public Key Files OpenSSH-Dateien mit öffentlichem Schlüssel - + Import Key Package Schlüsselpaket importieren - - + + Cannot open this file. Please make sure that this is a regular file and it's readable. Kann diese Datei nicht öffnen. Bitte stellen Sie sicher, dass es sich um eine reguläre, lesbare Datei handelt. - + The target file is too large for a key package. Die Zieldatei ist zu groß für ein Schlüsselpaket. - + Import Key Package Passphrase File Schlüsselpaket-Passphrasendatei importieren - + Key Package Passphrase File Schlüsselpaket-Passphrasendatei - + The target file is too large for a key package passphrase. Die Zieldatei ist zu groß für eine Schlüsselpaket-Passphrase. - + Importing Importieren - + key(s) imported Schlüssel importiert - + An error occur in importing key package. Beim Importieren des Schlüsselpakets ist ein Fehler aufgetreten. @@ -3329,313 +3359,313 @@ Hinweis: Weitere Informationen zur Verifizierung finden Sie hier: https://keys.o GpgFrontend::UI::KeyPairSubkeyTab - - + + Key ID Schlüssel-ID - - + + Algorithm Algorithmus - - + + Algorithm Detail Algorithmusdetails - - + + Key Size Schlüsselgröße - + Usage Verwendungszweck - + Expires On (Local Time) Läuft ab am (Ortszeit) - + Create Date (Local Time) Erstellungsdatum (Ortszeit) - + Existence Existenz - + Key in Smart Card Smartcard eintippen - + Fingerprint Fingerabdruck - + List of the primary key and subkey(s) Liste des Primärschlüssels und des/der Unterschlüssel(s) - + Detail of Selected Primary Key/Subkey Detail des ausgewählten Primärschlüssels/Unterschlüssels - + New Subkey Neuer Unterschlüssel - + Add ADSK(s) ADSK(s) hinzufügen - - + + Key Type Schlüsselart - + Revoked Widerrufen - - + + Export Subkey Unterschlüssel exportieren - + Create Date Erstellung - + Expire Date Ablaufdatum - - + + Primary Key Primärschlüssel - - + + Subkey Unterschlüssel - + ADSK ADSK - + Never Expire Nie ablaufen - + Never Expires Läuft nie ab - + Exists Existiert - + Not Exists Existiert nicht - - + + Yes Ja - - + + No Nein - + Export Primary Key Primärschlüssel exportieren - + Edit Expire Date Ablaufdatum bearbeiten - + Export Exportieren - + Delete Löschen - + Revoke Widerrufen - + Exporting Subkey Unterschlüssel exportieren - + You are about to export a private subkey. Sie sind dabei, einen privaten Unterschlüssel zu exportieren. - + While subkeys are less critical than the primary key, they should still be handled with care. Unterschlüssel sind zwar weniger kritisch als der Primärschlüssel, sollten aber dennoch mit Vorsicht behandelt werden. - + Do you want to proceed with exporting this subkey? Möchten Sie mit dem Exportieren dieses Unterschlüssels fortfahren? - + Export Key To File Schlüssel in Datei exportieren - + Key Files Schlüsseldateien - + Export Error Exportfehler - + Couldn't open %1 for writing %1 konnte nicht zum Schreiben geöffnet werden - + <h3>You are about to delete the subkey:</h3><br /><b>KeyID:</b> %1<br /><br />This action is irreversible. Please confirm. <h3>Sie sind dabei, den Unterschlüssel zu löschen:</h3><br /><b>KeyID:</b> %1<br /><br />Diese Aktion ist irreversibel. Bitte bestätigen Sie. - + Delete Subkey Confirmation Unterschlüssel löschen Bestätigung - - + + Illegal Operation Illegale Operation - + Cannot delete the primary key or an invalid subkey. Der Primärschlüssel oder ein ungültiger Unterschlüssel kann nicht gelöscht werden. - + Operation Failed Vorgang fehlgeschlagen - + The selected subkey could not be deleted. Please check your permissions or try again. Der ausgewählte Unterschlüssel konnte nicht gelöscht werden. Bitte überprüfen Sie Ihre Berechtigungen oder versuchen Sie es erneut. - + Operation Successful Operation erfolgreich - + The subkey with KeyID %1 has been successfully deleted. Der Unterschlüssel mit KeyID %1 wurde erfolgreich gelöscht. - + <h3>Revoke Subkey Confirmation</h3><br /><b>KeyID:</b> %1<br /><br />Revoking a subkey will make it permanently unusable. This action is <b>irreversible</b>.<br />Are you sure you want to revoke this subkey? <h3>Unterschlüssel widerrufen Bestätigung</h3><br /><b>KeyID:</b> %1<br /><br /><br />Das Widerrufen eines Unterschlüssels macht ihn dauerhaft unbrauchbar. Diese Aktion ist <b>irreversibel</b>.<br />Sind Sie sicher, dass Sie diesen Unterschlüssel widerrufen wollen? - + Revoke Subkey Unterschlüssel widerrufen - + Cannot revoke the primary key or an invalid subkey. Der Primärschlüssel oder ein ungültiger Unterschlüssel kann nicht widerrufen werden. - + 0 -> No Reason. 0 -> Kein Grund. - + 1 -> This key is no more safe. 1 -> Dieser Schlüssel ist nicht mehr sicher. - + 2 -> Key is outdated. 2 -> Der Schlüssel ist veraltet. - + 3 -> Key is no longer used 3 -> Der Schlüssel wird nicht mehr verwendet. - + Revocation Failed Widerruf fehlgeschlagen - + Failed to revoke the subkey. Please try again. Der Unterschlüssel konnte nicht widerrufen werden. Bitte versuchen Sie es erneut. - + Revocation Successful Widerruf erfolgreich - + The subkey has been successfully revoked. Der Unterschlüssel wurde erfolgreich widerrufen. @@ -3871,139 +3901,139 @@ Hinweis: Weitere Informationen zur Verifizierung finden Sie hier: https://keys.o GpgFrontend::UI::KeyServerImportDialog - + Close Schließen - + Import ALL ALLE importieren - + Search Suchen - + Search String Suchbegriff - - + + : : - + Key Server Schlüsselserver - + Import Keys from key server Importieren von Schlüsseln vom Schlüsselserver - + UID UID - + Creation date Erstellungsdatum - + KeyID SchlüsselID - + Tag Kennzeichen - + Text is empty. Text ist leer. - + Not Key Found Schlüssel nicht gefunden - + Timeout Zeitablauf - + Key Server Not Found Schlüsselserver nicht gefunden - + Connection Error Verbindungsfehler - + Too many responses from keyserver! Zu viele Antworten vom Schlüsselserver! - + No keys found, input may be kexId, retrying search with 0x. Keine Schlüssel gefunden, Eingabe kann kexId sein, versuche es mit 0x erneut. - + No keys found containing the search string! Keine Schlüssel gefunden, die den Suchbegriff enthalten! - + Insufficiently specific search string! Unzureichend spezifischer Suchbegriff! - + revoked widerrufen - + disabled deaktiviert - + %1 keys found. Double click a key to import it. %1 Schlüssel gefunden. Doppelklicken Sie auf einen Schlüssel, um ihn zu importieren. - + Warning Warnung - + Please select one KeyPair before doing this operation. Bitte wählen Sie ein Schlüsselpaar aus, bevor Sie diesen Vorgang ausführen. - + Key Imported Schlüssel importiert - + Processing ... Verarbeite ... @@ -4297,13 +4327,35 @@ Hinweis: Weitere Informationen zur Verifizierung finden Sie hier: https://keys.o GpgFrontend::UI::MainWindow - - + + GUI Pinentry Not Found + Grafisches Pinentry-Programm nicht gefunden + + + + No suitable *graphical* Pinentry program was found on your system. + +Please install a GUI-based Pinentry (e.g., 'pinentry-qt', 'pinentry-gnome3', or 'pinentry-mac' on macOS). + +Without a GUI Pinentry, GnuPG cannot prompt you for passwords or passphrases. + +After installing it, please restart GpgFrontend. The configuration file will be updated automatically. + Es wurde kein geeignetes *grafisches* Pinentry-Programm auf Ihrem System gefunden. + +Bitte installieren Sie ein GUI-basiertes Pinentry (z. B. "pinentry-qt", "pinentry-gnome3" oder "pinentry-mac" unter macOS). + +Ohne ein grafisches Pinentry kann GnuPG Sie nicht nach Passwörtern oder Passphrasen fragen. + +Bitte starten Sie GpgFrontend nach der Installation neu. Die Konfigurationsdatei wird automatisch aktualisiert. + + + + Critical error occur while loading GpgFrontend. Beim Laden von GpgFrontend ist ein kritischer Fehler aufgetreten. - + Loading Failed Laden fehlgeschlagen @@ -5133,26 +5185,26 @@ Wenn das Problem weiterhin besteht, wenden Sie sich an den technischen Support o Status-Panel - - - + + + Successful Operation Erfolgreiche Durchführung - + Clear password cache successfully Kennwort-Cache erfolgreich gelöscht - - - + + + Failed Operation Fehlgeschlagener Vorgang - + Failed to clear password cache of GnuPG Passwort-Cache von GnuPG konnte nicht geleert werden @@ -5167,12 +5219,12 @@ Wenn das Problem weiterhin besteht, wenden Sie sich an den technischen Support o Alle Komponenten von GnuPG neu laden - + Reload all the GnuPG's components successfully Alle GnuPG-Komponenten erfolgreich neu geladen - + Failed to reload all or one of the GnuPG's component(s) Fehler beim Neuladen aller oder einer Komponente(n) von GnuPG @@ -5187,12 +5239,12 @@ Wenn das Problem weiterhin besteht, wenden Sie sich an den technischen Support o Alle Komponenten von GnuPG neu starten - + Restart all the GnuPG's components successfully Alle Komponenten von GnuPG erfolgreich neu gestartet - + Failed to restart all or one of the GnuPG's component(s) Neustart aller oder einer GnuPG-Komponente(n) fehlgeschlagen @@ -5939,495 +5991,464 @@ Wenn das Problem weiterhin besteht, wenden Sie sich an den technischen Support o GpgFrontend::UI::SmartCardControllerDialog - + Smart Card(s): Chipkarte(n): - + Key Stub(s) in Key Database(s): Schlüssel-Stub(s) in Schlüssel-Datenbank(en): - + Change Name Name ändern - + Change Language Sprache ändern - + Change Gender Geschlecht ändern - + Change Login Data Anmeldedaten ändern - + Change Public Key URL URL des öffentlichen Schlüssels ändern - + Change PIN PIN ändern - + Change Admin PIN Admin-PIN ändern - + Change Reset Code Rückstellcode ändern - + Fetch Abrufen - + Restart All Gpg-Agents Alle Gpg-Agenten neu starten - + Generate Card Keys Erzeugen von Kartenschlüsseln - + Refresh Aktualisierung - + Operations Aktivieren - + Successful Operation Erfolgreiche Durchführung - + Restart all the GnuPG's components successfully Alle Komponenten von GnuPG erfolgreich neu gestartet - + Failed Operation Fehlgeschlagener Vorgang - + Failed to restart all or one of the GnuPG's component(s) Neustart aller oder einer GnuPG-Komponente(n) fehlgeschlagen - - + Error Fehler - + Generate card key failed. Kartenschlüssel generieren fehlgeschlagen. - + Smart Card Controller Chipkarten-Controller - + OpenPGP Card Information OpenPGP-Karteninformationen - + Basic Information Grundsätzliche Informationen - + Reader Kartenleser - + Serial Number Seriennummer - + Card Type Karten-Typ - + Card Version Kartenversion - + App Type App-Typ - + App Version App-Version - + Manufacturer ID Hersteller-ID - + Manufacturer Hersteller - + Card Holder Besitzer der Karte - + Language Sprache - + Sex Geschlecht - + Status Status - + Signature Counter Unterschriftenzähler - + CHV1 Cached CHV1 Zwischengespeichert - + CHV Max Length CHV Maximale Länge - + CHV Retry Left Verbleibende CHV-Versuche - + KDF Status KDF-Status - + Unknown Unbekannt - + UIF UIF - + Sign Unterschreiben - - - + + + Enabled Aktiviert - - - + + + Disabled Deaktiviert - + Encrypt Verschlüsseln - + Authenticate Authentifizieren - + Fingerprint Fingerabdruck - + Status Indicator Statusanzeige - + Cardholder's Surname Nachname des Karteninhabers - + Please enter your surname (e.g., Lee): Bitte geben Sie Ihren Nachnamen ein (z. B. Lee): - + Cardholder's Given Name Vorname des Karteninhabers - + Please enter your given name (e.g., Chris): Bitte geben Sie Ihren Vornamen ein (z. B. Chris): - + Too Long Zu lang - + Combined name too long (max 39 characters). Kombinierter Name zu lang (max. 39 Zeichen). - + Male Männlich - + Female Weiblich - + Select sex to store in '%1' Geschlecht zur Speicherung in '%1' auswählen - + Enter new value for attribute '%1' Neuen Wert für Attribut '%1' eingeben - + Not enabled Nicht aktiviert - + Enabled (no protection) Aktiviert (kein Schutz) - + Enabled with salt protection Aktiviert mit Salt-Schutz - + Key Information Schlüsselinformationen - + No key information available. Keine Schlüsselinformationen verfügbar. - + No. Nr. - + Created Erstellt - + Grip Grip - + Type Typ - + Algorithm Algorithmus - + Usage Verwendungszweck - + Curve Kurve - + Extended Capabilities Erweiterte Funktionen - + Key Info (ki): %1 Schlüsselinformationen (ki): %1 - - - + + + Yes Ja - - - + + + No Nein - + Additional Auth (aac): %1 Zusätzliche Authentifizierung (aac): %1 - + Biometric Terminal (bt): %1 Biometrisches Terminal (bt): %1 - + KDF Supported: %1 KDF-Unterstützung: %1 - + Additional Info Zusätzliche Informationen - + No OpenPGP Smart Card Found Keine OpenPGP-Smartcard gefunden - + No OpenPGP-compatible smart card has been detected. Es wurde keine OpenPGP-kompatible Smartcard erkannt. - + An OpenPGP Smart Card is a physical device that securely stores your private cryptographic keys and can be used for digital signing, encryption, and authentication. Popular examples include YubiKey, Nitrokey, and other GnuPG-compatible tokens. Eine OpenPGP-Smartcard ist ein physisches Gerät, das Ihre privaten kryptografischen Schlüssel sicher speichert und für digitale Signaturen, Verschlüsselung und Authentifizierung verwendet werden kann. Bekannte Beispiele sind YubiKey, Nitrokey und andere GnuPG-kompatible Token. - + Make sure your card is inserted and properly recognized by the system. You can also try reconnecting the card or restarting the application. Stellen Sie sicher, dass Ihre Karte eingesteckt und vom System korrekt erkannt wurde. Sie können auch versuchen, die Karte neu zu verbinden oder die Anwendung neu zu starten. - + Note: Smart card support of GpgFrontend requires GnuPG version 2.3.0 or later. Hinweis: Die Smartcard-Unterstützung von GpgFrontend erfordert GnuPG in Version 2.3.0 oder höher. - + Read the GnuPG Smart Card HOWTO: Lesen Sie das GnuPG Smartcard HOWTO: - - + + Modify Card Attribute Kartenattribut ändern - - Failed - Fehlgeschlagen - - - - Failed to set attribute '%1'. Reason: %2. - Attribut „%1“ konnte nicht gesetzt werden. Grund: %2. - - - - + + Success Erfolgreich - + Attribute operation completed successfully. Attributänderung erfolgreich abgeschlossen. - - Failed to change Admin PIN. - Ändern der Admin-PIN fehlgeschlagen. - - - - Failed to set the Reset Code. - Setzen des Rücksetz-Codes fehlgeschlagen. - - - - Failed to change PIN. - Ändern der PIN fehlgeschlagen. - - - - Reason: - Grund: - - - + PIN operation completed successfully. PIN-Änderung erfolgreich abgeschlossen. @@ -6435,82 +6456,82 @@ Wenn das Problem weiterhin besteht, wenden Sie sich an den technischen Support o GpgFrontend::UI::SubkeyGenerateDialog - + Tipps: if the key pair has a passphrase, the subkey's passphrase must be equal to it. Tipps: Wenn das Schlüsselpaar eine Passphrase hat, muss die Passphrase des Unterschlüssels die gleiche sein. - + Generate New Subkey Neuen Unterschlüssel erstellen - + Authentication Authentifizierung - + Algorithm Algorithmus - + Key Length Länge des Schlüssels - + Expire Date Ablaufdatum - + Usage Verwendungszweck - + Encrypt Verschlüsseln - + Sign Unterschreiben - + Non Expired Nicht abgelaufen - + No Passphrase Keine Passphrase - + Please give a valid subkey algorithm. Bitte geben Sie einen gültigen Unterschlüssel-Algorithmus an. - + Time to subkey expiration must not be less than 120 seconds. Die Zeit bis zum Ablauf des Unterschlüssels darf nicht weniger als 120 Sekunden betragen. - + Generating Erstellen - + Error Fehler - + Unknown error occurred Unbekannter Fehler ist aufgetreten @@ -6987,13 +7008,13 @@ Wenn das Problem weiterhin besteht, wenden Sie sich an den technischen Support o - + Usage Verwendungszweck - + Trust Vertrauen @@ -7019,32 +7040,32 @@ Wenn das Problem weiterhin besteht, wenden Sie sich an den technischen Support o - + Comment Kommentar - + ID ID - + Algo Algorithmus - + No Comment Kein Kommentar - + SubKeys (up to 8): Unterschlüssel (bis zu 8): - + ID: %1 | Algo: %2 | Usage: %3 ID: %1 | Algorithmus: %2 | Verwendung: %3 @@ -7173,42 +7194,42 @@ Wenn das Problem weiterhin besteht, wenden Sie sich an den technischen Support o Sie haben keine öffentlichen Schlüssel angekreuzt, die Sie synchronisieren möchten. Möchten Sie alle lokalen öffentlichen Schlüssel mit dem Schlüsselserver synchronisieren? - + Cannot Find GpgConf GpgConf kann nicht gefunden werden - + Cannot Find GnuPG GnuPG kann nicht gefunden werden - + Cannot get Infos from GpgConf Kann keine Infos von GpgConf erhalten - + Cannot Find Default Home Path Standard-GnuPG-Startpfad kann nicht gefunden werden - + GpgME Initiation Failed GpgME-Initiation fehlgeschlagen - + No valid Key Database Keine gültige Schlüsseldatenbank - + GpgME Default Context Initiation Failed GpgME-Standardkontext-Initiation fehlgeschlagen - + Gpg Default Key Database Initiation Failed Gpg-Standard-Schlüsseldatenbank-Initiation fehlgeschlagen diff --git a/resource/lfs/locale/ts/GpgFrontend.en_US.ts b/resource/lfs/locale/ts/GpgFrontend.en_US.ts index a6475318..88611c20 100644 --- a/resource/lfs/locale/ts/GpgFrontend.en_US.ts +++ b/resource/lfs/locale/ts/GpgFrontend.en_US.ts @@ -492,7 +492,7 @@ GpgFrontend::KeyGenerateInfo - + None @@ -586,22 +586,22 @@ - + Failed - + Partially Failed - + Failed to add all selected subkeys. - + Some subkeys failed to be added as ADSKs. @@ -770,7 +770,7 @@ GpgFrontend::UI::CommonUtils - + Success @@ -780,121 +780,122 @@ - - - Failure + + Operation Not Supported - - Gpg Operation failed. - -Error code: %1 -Source: %2 -Description: %3 + + The current GnuPG version is too low and does not support this operation. Please upgrade your GnuPG version to continue. + + + + + + Failure - + Open Key - + Keyring files - - - - + + + + Error - + Cannot open this file. Please make sure that this is a regular file and it's readable. - + The target file is too large for a keyring. - + File Open Failed - + Failed to open file: - + Processing - + Failed to execute command. - + Succeed in executing command. - + Warning - + Finished executing command. - + Default Keyserver Not Found - + Cannot read default keyserver from your settings, please set a default keyserver first - + Key Not Found - + Timeout - + Key Server Not Found - + Connection Error - + Key Not Found. - - + + The key has been updated @@ -909,8 +910,33 @@ Description: %3 - - + + Gpg Operation failed. + + + + + Error code: %1 + + + + + Source: %1 + + + + + Description: %1 + + + + + Error Message: %1 + + + + + No need to update the key @@ -1488,7 +1514,7 @@ This will result in loss of all cached form positions, statuses, key servers, et - + Illegal GnuPG Path @@ -1503,75 +1529,75 @@ This will result in loss of all cached form positions, statuses, key servers, et - + Target GnuPG Path contains no "gpgconf" executable. - + Maximum Key Database Limit Reached - + Currently, GpgFrontend supports a maximum of 8 key databases. Please remove an existing database to add a new one. - - + + Duplicate Key Database Paths - + The newly added key database path duplicates a previously existing one. - - + + Invalid Key Database Paths - - + + The edited key database path is not a valid path that GpgFrontend can use - + Active - + Inactive - + Confirm Deletion - + Are you sure you want to delete the selected key database? - + No Key Database Selected - + Please select a key database to edit. - + The edited key database path duplicates a previously existing one. @@ -1602,10 +1628,18 @@ This will result in loss of all cached form positions, statuses, key servers, et GpgFrontend::UI::GpgOperaHelper - - - - + + + + + Operation Not Supported + + + + + + + Critical Error @@ -1823,218 +1857,218 @@ This will result in loss of all cached form positions, statuses, key servers, et GpgFrontend::UI::KeyGenerateDialog - - - - - Custom - - - + - - 3 Months + + + Custom - 6 Months + 3 Months - 1 Year + 6 Months - - - 2 Years + 1 Year + + - 5 Years + 2 Years - 10 Years + 5 Years - - - - Non Expired + + 10 Years - - - - Primary Key Only + + + + + Non Expired - - Primary Key With Subkey + + + Primary Key Only - - Name + + + Primary Key With Subkey - Email + Name - Comment + Email - Key Database + Comment - - - Algorithm + Key Database - Validity Period + + Algorithm + - - Key Length + Validity Period - Usage + Key Length - Encrypt + Usage - Sign + Encrypt - Authentication + Sign + + Authentication + + + + No Passphrase - + Expire Date - + Easy Mode - + Primary Key - + Subkey - + Generate - - + + None - + Generate Key - + Name must contain at least five characters. - + Please give a valid email address. - + Please give a valid primary key algorithm. - + Time to primary key expiration must not be less than 120 seconds. - + Please give a valid subkey algorithm. - + Time to subkey expiration must not be less than 120 seconds. - + Error - + Unknown error occurred - + Generating @@ -2483,7 +2517,7 @@ These keys are no longer available. Do you want to remove them from the group? - + Key Package @@ -2605,22 +2639,22 @@ These keys are no longer available. Do you want to remove them from the group? - - - - - - - - + + + + + + + + Error - - + + Forbidden @@ -2632,102 +2666,102 @@ These keys are no longer available. Do you want to remove them from the group? - + key(s) exported - + Exporting - - + + Unknown error occurred - + Invalid Operation - + If a key pair does not have a private key then it will not be able to generate sub-keys. - + Please check a key before performing this operation. - + This operation accepts just a single key. - + This key may not be able to export as OpenSSH format. Please check the key-size of the subkey(s) used to sign. - + Export OpenSSH Key To File - + OpenSSH Public Key Files - + Import Key Package - - + + Cannot open this file. Please make sure that this is a regular file and it's readable. - + The target file is too large for a key package. - + Import Key Package Passphrase File - + Key Package Passphrase File - + The target file is too large for a key package passphrase. - + Importing - + An error occur in importing key package. - + key(s) imported @@ -3312,313 +3346,313 @@ Note: For verification, you can find more information here: https://keys.openpgp GpgFrontend::UI::KeyPairSubkeyTab - - + + Key ID - - + + Algorithm - - + + Algorithm Detail - - + + Key Size - + Usage - + Expires On (Local Time) - + Create Date (Local Time) - + Existence - + Key in Smart Card - + Fingerprint - + List of the primary key and subkey(s) - + Detail of Selected Primary Key/Subkey - + New Subkey - + Add ADSK(s) - - + + Key Type - + Revoked - - + + Export Subkey - + Create Date - + Expire Date - - + + Primary Key - - + + Subkey - + ADSK - + Never Expire - + Never Expires - + Exists - + Not Exists - - + + Yes - - + + No - + Export Primary Key - + Edit Expire Date - + Export - + Delete - + Revoke - + Exporting Subkey - + You are about to export a private subkey. - + While subkeys are less critical than the primary key, they should still be handled with care. - + Do you want to proceed with exporting this subkey? - + Export Key To File - + Key Files - + Export Error - + Couldn't open %1 for writing - + <h3>You are about to delete the subkey:</h3><br /><b>KeyID:</b> %1<br /><br />This action is irreversible. Please confirm. - + Delete Subkey Confirmation - - + + Illegal Operation - + Cannot delete the primary key or an invalid subkey. - + Operation Failed - + The selected subkey could not be deleted. Please check your permissions or try again. - + Operation Successful - + The subkey with KeyID %1 has been successfully deleted. - + <h3>Revoke Subkey Confirmation</h3><br /><b>KeyID:</b> %1<br /><br />Revoking a subkey will make it permanently unusable. This action is <b>irreversible</b>.<br />Are you sure you want to revoke this subkey? - + Revoke Subkey - + Cannot revoke the primary key or an invalid subkey. - + 0 -> No Reason. - + 1 -> This key is no more safe. - + 2 -> Key is outdated. - + 3 -> Key is no longer used - + Revocation Failed - + Failed to revoke the subkey. Please try again. - + Revocation Successful - + The subkey has been successfully revoked. @@ -3854,139 +3888,139 @@ Note: For verification, you can find more information here: https://keys.openpgp GpgFrontend::UI::KeyServerImportDialog - + Close - + Import ALL - + Search - + Search String - - + + : - + Key Server - + Import Keys from key server - + UID - + Creation date - + KeyID - + Tag - + Text is empty. - + Not Key Found - + Timeout - + Key Server Not Found - + Connection Error - + Too many responses from keyserver! - + No keys found, input may be kexId, retrying search with 0x. - + No keys found containing the search string! - + Insufficiently specific search string! - + revoked - + disabled - + %1 keys found. Double click a key to import it. - + Warning - + Please select one KeyPair before doing this operation. - + Key Imported - + Processing ... @@ -4280,13 +4314,29 @@ Note: For verification, you can find more information here: https://keys.openpgp GpgFrontend::UI::MainWindow - - + + GUI Pinentry Not Found + + + + + No suitable *graphical* Pinentry program was found on your system. + +Please install a GUI-based Pinentry (e.g., 'pinentry-qt', 'pinentry-gnome3', or 'pinentry-mac' on macOS). + +Without a GUI Pinentry, GnuPG cannot prompt you for passwords or passphrases. + +After installing it, please restart GpgFrontend. The configuration file will be updated automatically. + + + + + Critical error occur while loading GpgFrontend. - + Loading Failed @@ -5068,26 +5118,26 @@ If the issue persists, consider seeking technical support or consulting the docu - - - + + + Successful Operation - + Clear password cache successfully - - - + + + Failed Operation - + Failed to clear password cache of GnuPG @@ -5102,12 +5152,12 @@ If the issue persists, consider seeking technical support or consulting the docu - + Reload all the GnuPG's components successfully - + Failed to reload all or one of the GnuPG's component(s) @@ -5122,12 +5172,12 @@ If the issue persists, consider seeking technical support or consulting the docu - + Restart all the GnuPG's components successfully - + Failed to restart all or one of the GnuPG's component(s) @@ -5874,495 +5924,464 @@ If the issue persists, consider seeking technical support or consulting the docu GpgFrontend::UI::SmartCardControllerDialog - + Smart Card(s): - + Key Stub(s) in Key Database(s): - + Change Name - + Change Language - + Change Gender - + Change Login Data - + Change Public Key URL - + Change PIN - + Change Admin PIN - + Change Reset Code - + Fetch - + Restart All Gpg-Agents - + Generate Card Keys - + Refresh - + Operations - + Successful Operation - + Restart all the GnuPG's components successfully - + Failed Operation - + Failed to restart all or one of the GnuPG's component(s) - + Generate card key failed. - + Smart Card Controller - + OpenPGP Card Information - + Basic Information - + Reader - + Serial Number - + Card Type - + Card Version - + App Type - + App Version - + Manufacturer ID - + Manufacturer - + Card Holder - + Language - + Sex - + Signature Counter - + CHV1 Cached - + CHV Max Length - + CHV Retry Left - + KDF Status - + UIF - + Sign - - - + + + Enabled - - - + + + Disabled - + Encrypt - + Authenticate - + Status Indicator - + Cardholder's Surname - + Please enter your surname (e.g., Lee): - + Cardholder's Given Name - + Please enter your given name (e.g., Chris): - + Too Long - + Combined name too long (max 39 characters). - + Male - + Female - + Select sex to store in '%1' - + Enter new value for attribute '%1' - + Status - + Not enabled - + Enabled (no protection) - + Enabled with salt protection - + Unknown - + Key Information - + No key information available. - + No. - + Fingerprint - + Created - + Grip - + Type - + Algorithm - + Usage - + Curve - + Extended Capabilities - + Key Info (ki): %1 - - - + + + Yes - - - + + + No - + Additional Auth (aac): %1 - + Biometric Terminal (bt): %1 - + KDF Supported: %1 - + Additional Info - + No OpenPGP Smart Card Found - + No OpenPGP-compatible smart card has been detected. - + An OpenPGP Smart Card is a physical device that securely stores your private cryptographic keys and can be used for digital signing, encryption, and authentication. Popular examples include YubiKey, Nitrokey, and other GnuPG-compatible tokens. - + Make sure your card is inserted and properly recognized by the system. You can also try reconnecting the card or restarting the application. - + Note: Smart card support of GpgFrontend requires GnuPG version 2.3.0 or later. - + Read the GnuPG Smart Card HOWTO: - - + + Modify Card Attribute - - Failed - - - - - Failed to set attribute '%1'. Reason: %2. - - - - - + + Success - + Attribute operation completed successfully. - - Failed to change Admin PIN. - - - - - Failed to set the Reset Code. - - - - - Failed to change PIN. - - - - - Reason: - - - - - + Error - + PIN operation completed successfully. @@ -6370,82 +6389,82 @@ If the issue persists, consider seeking technical support or consulting the docu GpgFrontend::UI::SubkeyGenerateDialog - + Tipps: if the key pair has a passphrase, the subkey's passphrase must be equal to it. - + Generate New Subkey - + Authentication - + Algorithm - + Key Length - + Expire Date - + Usage - + Encrypt - + Sign - + Non Expired - + No Passphrase - + Please give a valid subkey algorithm. - + Time to subkey expiration must not be less than 120 seconds. - + Generating - + Error - + Unknown error occurred @@ -6920,13 +6939,13 @@ If the issue persists, consider seeking technical support or consulting the docu - + Usage - + Trust @@ -6952,32 +6971,32 @@ If the issue persists, consider seeking technical support or consulting the docu - + Comment - + ID - + Algo - + No Comment - + SubKeys (up to 8): - + ID: %1 | Algo: %2 | Usage: %3 @@ -7106,42 +7125,42 @@ If the issue persists, consider seeking technical support or consulting the docu - + Cannot Find GpgConf - + Cannot Find GnuPG - + Cannot get Infos from GpgConf - + Cannot Find Default Home Path - + GpgME Initiation Failed - + No valid Key Database - + GpgME Default Context Initiation Failed - + Gpg Default Key Database Initiation Failed diff --git a/resource/lfs/locale/ts/GpgFrontend.fr_FR.ts b/resource/lfs/locale/ts/GpgFrontend.fr_FR.ts index 384d18d2..2cd98555 100644 --- a/resource/lfs/locale/ts/GpgFrontend.fr_FR.ts +++ b/resource/lfs/locale/ts/GpgFrontend.fr_FR.ts @@ -492,7 +492,7 @@ GpgFrontend::KeyGenerateInfo - + None @@ -586,22 +586,22 @@ - + Failed Échoué - + Partially Failed - + Failed to add all selected subkeys. - + Some subkeys failed to be added as ADSKs. @@ -769,13 +769,13 @@ GpgFrontend::UI::CommonUtils - + Timeout Temps libre - + Success Succès @@ -795,126 +795,148 @@ Opération Gpg réussie. - - + + Failure Échec - - Gpg Operation failed. - -Error code: %1 -Source: %2 -Description: %3 - L'opération Gpg a échoué. - -Code d'erreur : %1 -Source : %2 -Description : %3 - - - - - - + + + + Error Erreur - + Open Key Ouvrir la clé - + + Operation Not Supported + + + + + The current GnuPG version is too low and does not support this operation. Please upgrade your GnuPG version to continue. + + + + + Gpg Operation failed. + + + + + Error code: %1 + + + + + Source: %1 + + + + + Description: %1 + + + + + Error Message: %1 + + + + Keyring files Fichiers de porte-clés - + Cannot open this file. Please make sure that this is a regular file and it's readable. - + The target file is too large for a keyring. - + File Open Failed L'ouverture du fichier a échoué - + Failed to open file: Échec de l'ouverture du fichier: - + Processing Traitement - + Failed to execute command. Échec de l'exécution de la commande. - + Succeed in executing command. Réussir l'exécution de la commande. - + Warning Avertissement - + Finished executing command. Exécution de la commande terminée. - + Default Keyserver Not Found Serveur de clés par défaut introuvable - + Cannot read default keyserver from your settings, please set a default keyserver first Impossible de lire le serveur de clés par défaut à partir de vos paramètres, veuillez d'abord définir un serveur de clés par défaut - + Key Not Found Clé introuvable - + Key Server Not Found Serveur de clé introuvable - + Connection Error Erreur de connexion - + Key Not Found. Clé introuvable. - - + + The key has been updated La clé a été mise à jour - - + + No need to update the key Pas besoin de mettre à jour la clé @@ -1460,70 +1482,70 @@ This will result in loss of all cached form positions, statuses, key servers, et - + Maximum Key Database Limit Reached - + Currently, GpgFrontend supports a maximum of 8 key databases. Please remove an existing database to add a new one. - - + + Duplicate Key Database Paths - + The newly added key database path duplicates a previously existing one. - - + + Invalid Key Database Paths - - + + The edited key database path is not a valid path that GpgFrontend can use - + Active - + Inactive - + Confirm Deletion - + Are you sure you want to delete the selected key database? - + No Key Database Selected - + Please select a key database to edit. - + The edited key database path duplicates a previously existing one. @@ -1560,7 +1582,7 @@ This will result in loss of all cached form positions, statuses, key servers, et - + Illegal GnuPG Path Chemin GnuPG illégal @@ -1575,7 +1597,7 @@ This will result in loss of all cached form positions, statuses, key servers, et Le chemin GnuPG cible n&#39;est pas un chemin absolu. - + Target GnuPG Path contains no "gpgconf" executable. Le chemin GnuPG cible ne contient pas d&#39;exécutable &quot;gpgconf&quot;. @@ -1606,10 +1628,18 @@ This will result in loss of all cached form positions, statuses, key servers, et GpgFrontend::UI::GpgOperaHelper - - - - + + + + + Operation Not Supported + + + + + + + Critical Error @@ -1827,218 +1857,218 @@ This will result in loss of all cached form positions, statuses, key servers, et GpgFrontend::UI::KeyGenerateDialog - - - - - Custom - - - + - - 3 Months + + + Custom - 6 Months + 3 Months - 1 Year + 6 Months - - - 2 Years + 1 Year + + - 5 Years + 2 Years - 10 Years + 5 Years - - - + + 10 Years + + + + + + + Non Expired - - - + + + Primary Key Only - - + + Primary Key With Subkey - + Name Nom - + Email E-mail - + Comment Commentaire - + Key Database Base de données de clés - - - + + + Algorithm Algorithme - - + + Validity Period - - + + Key Length - - + + Usage Usage - - + + Encrypt Chiffrer - - + + Sign Signer - - + + Authentication Authentification - + No Passphrase - + Expire Date Date d'expiration - + Easy Mode - + Primary Key Clé primaire - + Subkey Sous-clé - + Generate - - + + None - + Generate Key Générer la clé - + Name must contain at least five characters. Le nom doit contenir au moins cinq caractères. - + Please give a valid email address. - + Please give a valid primary key algorithm. - + Time to primary key expiration must not be less than 120 seconds. - + Please give a valid subkey algorithm. - + Time to subkey expiration must not be less than 120 seconds. - + Error Erreur - + Unknown error occurred Une erreur inconnue s'est produite - + Generating Générateur @@ -2487,7 +2517,7 @@ These keys are no longer available. Do you want to remove them from the group? - + Key Package Paquet de clés @@ -2609,22 +2639,22 @@ These keys are no longer available. Do you want to remove them from the group? - - - - - - - - + + + + + + + + Error Erreur - - + + Forbidden Interdit @@ -2636,102 +2666,102 @@ These keys are no longer available. Do you want to remove them from the group? - + key(s) exported clé(s) exportée(s) - + Exporting Exportation - - + + Unknown error occurred Une erreur inconnue s'est produite - + Invalid Operation Opération invalide - + If a key pair does not have a private key then it will not be able to generate sub-keys. Si une paire de clés n'a pas de clé privée, elle ne pourra pas générer de sous-clés. - + Please check a key before performing this operation. - + This operation accepts just a single key. - + This key may not be able to export as OpenSSH format. Please check the key-size of the subkey(s) used to sign. Cette clé peut ne pas être en mesure d'exporter au format OpenSSH. Veuillez vérifier la taille de la ou des sous-clés utilisées pour signer. - + Export OpenSSH Key To File Exporter la clé OpenSSH vers un fichier - + OpenSSH Public Key Files Fichiers de clé publique OpenSSH - + Import Key Package Importer le paquet de clés - - + + Cannot open this file. Please make sure that this is a regular file and it's readable. - + The target file is too large for a key package. - + Import Key Package Passphrase File Importer le fichier de mot de passe du package de clés - + Key Package Passphrase File Fichier de mot de passe du package de clé - + The target file is too large for a key package passphrase. - + Importing - + key(s) imported clé(s) importée(s) - + An error occur in importing key package. Une erreur s'est produite lors de l'importation du package de clés. @@ -3316,313 +3346,313 @@ Note: For verification, you can find more information here: https://keys.openpgp GpgFrontend::UI::KeyPairSubkeyTab - - + + Key ID Identifiant de clé - - + + Algorithm Algorithme - - + + Algorithm Detail - - + + Key Size Taille de la clé - + Usage Usage - + Expires On (Local Time) Expire le (heure locale) - + Create Date (Local Time) Date de création (heure locale) - + Existence Existence - + Key in Smart Card Entrez la carte à puce - + Fingerprint Empreinte digitale - + List of the primary key and subkey(s) - + Detail of Selected Primary Key/Subkey - + New Subkey Nouvelle sous-clé - + Add ADSK(s) - - + + Key Type Type de clé - + Revoked Révoqué - - + + Export Subkey - + Create Date - + Expire Date Date d'expiration - - + + Primary Key Clé primaire - - + + Subkey Sous-clé - + ADSK - + Never Expire N'expire jamais - + Never Expires N'expire jamais - + Exists Existe - + Not Exists N'existe pas - - + + Yes Oui - - + + No Non - + Export Primary Key - + Edit Expire Date Modifier la date d'expiration - + Export - + Delete Effacer - + Revoke - + Exporting Subkey - + You are about to export a private subkey. - + While subkeys are less critical than the primary key, they should still be handled with care. - + Do you want to proceed with exporting this subkey? - + Export Key To File Exporter la clé vers un fichier - + Key Files Fichiers clés - + Export Error Erreur d'exportation - + Couldn't open %1 for writing Impossible d'ouvrir %1 pour l'écriture - + <h3>You are about to delete the subkey:</h3><br /><b>KeyID:</b> %1<br /><br />This action is irreversible. Please confirm. - + Delete Subkey Confirmation - - + + Illegal Operation - + Cannot delete the primary key or an invalid subkey. - + Operation Failed L'opération a échoué - + The selected subkey could not be deleted. Please check your permissions or try again. - + Operation Successful - + The subkey with KeyID %1 has been successfully deleted. - + <h3>Revoke Subkey Confirmation</h3><br /><b>KeyID:</b> %1<br /><br />Revoking a subkey will make it permanently unusable. This action is <b>irreversible</b>.<br />Are you sure you want to revoke this subkey? - + Revoke Subkey - + Cannot revoke the primary key or an invalid subkey. - + 0 -> No Reason. - + 1 -> This key is no more safe. - + 2 -> Key is outdated. - + 3 -> Key is no longer used - + Revocation Failed - + Failed to revoke the subkey. Please try again. - + Revocation Successful - + The subkey has been successfully revoked. @@ -3858,139 +3888,139 @@ Note: For verification, you can find more information here: https://keys.openpgp GpgFrontend::UI::KeyServerImportDialog - + Close proche - + Import ALL Importer TOUT - + Search Chercher - + Search String Chaîne de recherche - - + + : : - + Key Server Serveur de clés - + Import Keys from key server - + UID UID - + Creation date Date de création - + KeyID ID clé - + Tag Étiqueter - + Text is empty. Le texte est vide. - + Not Key Found Pas de clé trouvée - + Timeout Temps libre - + Key Server Not Found Serveur de clé introuvable - + Connection Error Erreur de connexion - + Too many responses from keyserver! Trop de réponses du serveur de clés ! - + No keys found, input may be kexId, retrying search with 0x. Aucune clé trouvée, l'entrée peut être kexId, réessayer la recherche avec 0x. - + No keys found containing the search string! Aucune clé trouvée contenant la chaîne de recherche ! - + Insufficiently specific search string! Chaîne de recherche insuffisamment spécifique ! - + revoked révoqué - + disabled désactivée - + %1 keys found. Double click a key to import it. %1 clés trouvées. Double-cliquez sur une clé pour l'importer. - + Warning Avertissement - + Please select one KeyPair before doing this operation. Veuillez sélectionner une KeyPair avant de faire cette opération. - + Key Imported Clé importée - + Processing ... @@ -4284,13 +4314,29 @@ Note: For verification, you can find more information here: https://keys.openpgp GpgFrontend::UI::MainWindow - - + + GUI Pinentry Not Found + + + + + No suitable *graphical* Pinentry program was found on your system. + +Please install a GUI-based Pinentry (e.g., 'pinentry-qt', 'pinentry-gnome3', or 'pinentry-mac' on macOS). + +Without a GUI Pinentry, GnuPG cannot prompt you for passwords or passphrases. + +After installing it, please restart GpgFrontend. The configuration file will be updated automatically. + + + + + Critical error occur while loading GpgFrontend. Une erreur critique s'est produite lors du chargement de GpgFrontend. - + Loading Failed Échec du chargement @@ -5072,26 +5118,26 @@ If the issue persists, consider seeking technical support or consulting the docu - - - + + + Successful Operation Opération réussie - + Clear password cache successfully Effacer le cache du mot de passe avec succès - - - + + + Failed Operation Échec de l'opération - + Failed to clear password cache of GnuPG Impossible d'effacer le cache du mot de passe de GnuPG @@ -5106,12 +5152,12 @@ If the issue persists, consider seeking technical support or consulting the docu Recharger tous les composants de GnuPG - + Reload all the GnuPG's components successfully Rechargez tous les composants de GnuPG avec succès - + Failed to reload all or one of the GnuPG's component(s) Échec du rechargement de tout ou partie des composants de GnuPG @@ -5126,12 +5172,12 @@ If the issue persists, consider seeking technical support or consulting the docu Redémarrez tous les composants de GnuPG - + Restart all the GnuPG's components successfully Redémarrez tous les composants de GnuPG avec succès - + Failed to restart all or one of the GnuPG's component(s) Échec du redémarrage de tout ou partie des composants de GnuPG @@ -5878,495 +5924,464 @@ If the issue persists, consider seeking technical support or consulting the docu GpgFrontend::UI::SmartCardControllerDialog - + Smart Card(s): - + Key Stub(s) in Key Database(s): - + Change Name - + Change Language - + Change Gender - + Change Login Data - + Change Public Key URL - + Change PIN - + Change Admin PIN - + Change Reset Code - + Fetch - + Restart All Gpg-Agents - + Generate Card Keys - + Refresh Rafraîchir - + Operations Opérations - + Successful Operation Opération réussie - + Restart all the GnuPG's components successfully Redémarrez tous les composants de GnuPG avec succès - + Failed Operation Échec de l'opération - + Failed to restart all or one of the GnuPG's component(s) Échec du redémarrage de tout ou partie des composants de GnuPG - + Generate card key failed. - + Smart Card Controller - + OpenPGP Card Information - + Basic Information - + Reader - + Serial Number - + Card Type - + Card Version - + App Type - + App Version - + Manufacturer ID - + Manufacturer - + Card Holder - + Language Langue - + Sex - + Signature Counter - + CHV1 Cached - + CHV Max Length - + CHV Retry Left - + KDF Status - + UIF - + Sign Signer - - - + + + Enabled - - - + + + Disabled - + Encrypt Chiffrer - + Authenticate - + Status Indicator - + Cardholder's Surname - + Please enter your surname (e.g., Lee): - + Cardholder's Given Name - + Please enter your given name (e.g., Chris): - + Too Long - + Combined name too long (max 39 characters). - + Male - + Female - + Select sex to store in '%1' - + Enter new value for attribute '%1' - + Status Statut - + Not enabled - + Enabled (no protection) - + Enabled with salt protection - + Unknown Inconnu - + Key Information - + No key information available. - + No. - + Fingerprint Empreinte digitale - + Created - + Grip - + Type Taper - + Algorithm Algorithme - + Usage Usage - + Curve - + Extended Capabilities - + Key Info (ki): %1 - - - + + + Yes Oui - - - + + + No Non - + Additional Auth (aac): %1 - + Biometric Terminal (bt): %1 - + KDF Supported: %1 - + Additional Info - + No OpenPGP Smart Card Found - + No OpenPGP-compatible smart card has been detected. - + An OpenPGP Smart Card is a physical device that securely stores your private cryptographic keys and can be used for digital signing, encryption, and authentication. Popular examples include YubiKey, Nitrokey, and other GnuPG-compatible tokens. - + Make sure your card is inserted and properly recognized by the system. You can also try reconnecting the card or restarting the application. - + Note: Smart card support of GpgFrontend requires GnuPG version 2.3.0 or later. - + Read the GnuPG Smart Card HOWTO: - - + + Modify Card Attribute - - Failed - Échoué - - - - Failed to set attribute '%1'. Reason: %2. - - - - - + + Success Succès - + Attribute operation completed successfully. - - Failed to change Admin PIN. - - - - - Failed to set the Reset Code. - - - - - Failed to change PIN. - - - - - Reason: - - - - - + Error Erreur - + PIN operation completed successfully. @@ -6374,82 +6389,82 @@ If the issue persists, consider seeking technical support or consulting the docu GpgFrontend::UI::SubkeyGenerateDialog - + Tipps: if the key pair has a passphrase, the subkey's passphrase must be equal to it. Conseil : si la paire de clés a une phrase secrète, la phrase secrète de la sous-clé doit lui être égale. - + Generate New Subkey Générer une nouvelle sous-clé - + Authentication Authentification - + Algorithm Algorithme - + Key Length - + Expire Date Date d'expiration - + Usage Usage - + Encrypt Chiffrer - + Sign Signer - + Non Expired - + No Passphrase - + Please give a valid subkey algorithm. - + Time to subkey expiration must not be less than 120 seconds. - + Generating Générateur - + Error Erreur - + Unknown error occurred Une erreur inconnue s'est produite @@ -6926,13 +6941,13 @@ If the issue persists, consider seeking technical support or consulting the docu - + Usage Usage - + Trust Confiance @@ -6958,32 +6973,32 @@ If the issue persists, consider seeking technical support or consulting the docu - + Comment Commentaire - + ID - + Algo - + No Comment - + SubKeys (up to 8): - + ID: %1 | Algo: %2 | Usage: %3 @@ -7112,42 +7127,42 @@ If the issue persists, consider seeking technical support or consulting the docu - + Cannot Find GpgConf - + Cannot Find GnuPG - + Cannot get Infos from GpgConf - + Cannot Find Default Home Path - + GpgME Initiation Failed - + No valid Key Database - + GpgME Default Context Initiation Failed - + Gpg Default Key Database Initiation Failed diff --git a/resource/lfs/locale/ts/GpgFrontend.it_IT.ts b/resource/lfs/locale/ts/GpgFrontend.it_IT.ts index 18bdf8d3..c62337d5 100644 --- a/resource/lfs/locale/ts/GpgFrontend.it_IT.ts +++ b/resource/lfs/locale/ts/GpgFrontend.it_IT.ts @@ -492,7 +492,7 @@ GpgFrontend::KeyGenerateInfo - + None Nessuno @@ -586,22 +586,22 @@ - + Failed Fallito - + Partially Failed - + Failed to add all selected subkeys. - + Some subkeys failed to be added as ADSKs. @@ -769,13 +769,13 @@ GpgFrontend::UI::CommonUtils - + Timeout Tempo scaduto - + Success Successo @@ -795,126 +795,148 @@ Operazione Gpg riuscita. - - + + Failure Fallimento - - Gpg Operation failed. - -Error code: %1 -Source: %2 -Description: %3 - Operazione Gpg non riuscita. - -Codice errore: %1 -Origine: %2 -Descrizione: %3 - - - - - - + + + + Error Errore - + Open Key Chiave aperta - + + Operation Not Supported + + + + + The current GnuPG version is too low and does not support this operation. Please upgrade your GnuPG version to continue. + + + + + Gpg Operation failed. + + + + + Error code: %1 + + + + + Source: %1 + + + + + Description: %1 + + + + + Error Message: %1 + + + + Keyring files File portachiavi - + Cannot open this file. Please make sure that this is a regular file and it's readable. Impossibile aprire questo file. Assicurati che questo sia un file regolare e che sia leggibile. - + The target file is too large for a keyring. Il file di destinazione è troppo grande per un portachiavi. - + File Open Failed Apertura file non riuscita - + Failed to open file: Impossibile aprire il file: - + Processing In lavorazione - + Failed to execute command. Impossibile eseguire il comando. - + Succeed in executing command. Riuscire a eseguire il comando. - + Warning Avvertimento - + Finished executing command. Terminata l'esecuzione del comando. - + Default Keyserver Not Found Keyserver predefinito non trovato - + Cannot read default keyserver from your settings, please set a default keyserver first Impossibile leggere il server delle chiavi predefinito dalle impostazioni, impostare prima un server delle chiavi predefinito - + Key Not Found Chiave non trovata - + Key Server Not Found Server chiave non trovato - + Connection Error Errore di connessione - + Key Not Found. Chiave non trovata. - - + + The key has been updated La chiave è stata aggiornata - - + + No need to update the key Non è necessario aggiornare la chiave @@ -1464,73 +1486,73 @@ This will result in loss of all cached form positions, statuses, key servers, et - + Maximum Key Database Limit Reached È stato raggiunto il limite massimo del database delle chiavi - + Currently, GpgFrontend supports a maximum of 8 key databases. Please remove an existing database to add a new one. Attualmente, GpgFrontend supporta un massimo di 8 database di chiavi. Rimuovi un database esistente per aggiungerne uno nuovo. - - + + Duplicate Key Database Paths Percorsi del database delle chiavi duplicati - + The newly added key database path duplicates a previously existing one. Il percorso del database delle chiavi appena aggiunto duplica quello già esistente. - - + + Invalid Key Database Paths Percorsi del database delle chiavi non validi - - + + The edited key database path is not a valid path that GpgFrontend can use Il percorso modificato del database delle chiavi non è un percorso valido che GpgFrontend può utilizzare - + Active Attivo - + Inactive Inattivo/a - + Confirm Deletion Conferma la cancellazione - + Are you sure you want to delete the selected key database? Vuoi davvero eliminare il database delle chiavi selezionato? - + No Key Database Selected Nessun database di chiavi selezionato - + Please select a key database to edit. Selezionare un database chiave da modificare. - + The edited key database path duplicates a previously existing one. Il percorso del database delle chiavi modificato duplica un percorso già esistente. @@ -1567,7 +1589,7 @@ This will result in loss of all cached form positions, statuses, key servers, et - + Illegal GnuPG Path Percorso GnuPG illegale @@ -1582,7 +1604,7 @@ This will result in loss of all cached form positions, statuses, key servers, et Target GnuPG Path non è un percorso assoluto. - + Target GnuPG Path contains no "gpgconf" executable. Il percorso GnuPG di destinazione non contiene l'eseguibile "gpgconf". @@ -1613,10 +1635,18 @@ This will result in loss of all cached form positions, statuses, key servers, et GpgFrontend::UI::GpgOperaHelper - - - - + + + + + Operation Not Supported + + + + + + + Critical Error Errore critico @@ -1836,218 +1866,218 @@ This will result in loss of all cached form positions, statuses, key servers, et GpgFrontend::UI::KeyGenerateDialog - - - - + + + + Custom Impiego - - + + 3 Months 3 Mesi - - + + 6 Months 6 Mesi - - + + 1 Year 1 Anno - - - - + + + + 2 Years 2 Anni - - + + 5 Years 5 Anni - - + + 10 Years 10 Anni - - - - + + + + Non Expired Non Scaduto - - - + + + Primary Key Only Solo Chiave Primaria - - + + Primary Key With Subkey Chiave Primaria con Sottochiave - + Name Nome - + Email Email - + Comment Commento - + Key Database Database delle chiavi - - - + + + Algorithm Algoritmo - - + + Validity Period Periodo di validità - - + + Key Length Lunghezza Chiave - - + + Usage Utilizzo - - + + Encrypt Cifra - - + + Sign Firma - - + + Authentication Autenticazione - + No Passphrase Nessuna frase segreta - + Expire Date Data di scadenza - + Easy Mode Modalità facile - + Primary Key Chiave primaria - + Subkey Sottochiave - + Generate Generare - - + + None Nessuno - + Generate Key Genera chiave - + Name must contain at least five characters. Il nome deve contenere almeno cinque caratteri. - + Please give a valid email address. Inserisci un indirizzo email valido. - + Please give a valid primary key algorithm. Fornisci un algoritmo di chiave primaria valido. - + Time to primary key expiration must not be less than 120 seconds. Il tempo di scadenza della chiave primaria non deve essere inferiore a 120 secondi. - + Please give a valid subkey algorithm. Si prega di fornire un algoritmo di sottochiave valido. - + Time to subkey expiration must not be less than 120 seconds. Il tempo di scadenza della sottochiave non deve essere inferiore a 120 secondi. - + Error Errore - + Unknown error occurred Si è verificato un errore sconosciuto - + Generating Generazione @@ -2496,7 +2526,7 @@ These keys are no longer available. Do you want to remove them from the group? - + Key Package Pacchetto chiave @@ -2618,22 +2648,22 @@ These keys are no longer available. Do you want to remove them from the group? - - - - - - - - + + + + + + + + Error Errore - - + + Forbidden Vietato @@ -2645,102 +2675,102 @@ These keys are no longer available. Do you want to remove them from the group? - + key(s) exported chiavi esportate - + Exporting Sto spotando - - + + Unknown error occurred Si è verificato un errore sconosciuto - + Invalid Operation Operazione non valida - + If a key pair does not have a private key then it will not be able to generate sub-keys. Se una coppia di chiavi non dispone di una chiave privata, non sarà in grado di generare sottochiavi. - + Please check a key before performing this operation. Si prega di controllare una chiave prima di eseguire questa operazione. - + This operation accepts just a single key. Questa operazione accetta una sola chiave. - + This key may not be able to export as OpenSSH format. Please check the key-size of the subkey(s) used to sign. Questa chiave potrebbe non essere in grado di esportare come formato OpenSSH. Controlla la dimensione della chiave della/e sottochiave/i utilizzata/e per firmare. - + Export OpenSSH Key To File Esporta chiave OpenSSH in file - + OpenSSH Public Key Files File di chiavi pubbliche OpenSSH - + Import Key Package Importa pacchetto chiave - - + + Cannot open this file. Please make sure that this is a regular file and it's readable. Impossibile aprire questo file. Assicurati che questo sia un file regolare e che sia leggibile. - + The target file is too large for a key package. Il file di destinazione è troppo grande per un pacchetto chiave. - + Import Key Package Passphrase File Importa file passphrase pacchetto chiave - + Key Package Passphrase File File di passphrase del pacchetto chiave - + The target file is too large for a key package passphrase. Il file di destinazione è troppo grande per un pacchetto chiave. - + Importing Sto importando - + key(s) imported chiavi importate - + An error occur in importing key package. Si è verificato un errore durante l'importazione del pacchetto di chiavi. @@ -3334,313 +3364,313 @@ Nota: per la verifica, puoi trovare maggiori informazioni qui: https://keys.open GpgFrontend::UI::KeyPairSubkeyTab - - + + Key ID ID chiave - - + + Algorithm Algoritmo - - + + Algorithm Detail Dettaglio dell'Algoritmo - - + + Key Size Dimensione chiave - + Usage Utilizzo - + Expires On (Local Time) Scade il (ora locale) - + Create Date (Local Time) Data di creazione (ora locale) - + Existence Esistenza - + Key in Smart Card Inserisci la Smart Card - + Fingerprint Impronta digitale - + List of the primary key and subkey(s) Elenco della chiave primaria e della(e) sottochiave(i) - + Detail of Selected Primary Key/Subkey Dettaglio della chiave primaria/sottochiave selezionata - + New Subkey Nuova sottochiave - + Add ADSK(s) - - + + Key Type Tipo di chiave - + Revoked Revocata - - + + Export Subkey Esporta Sottochiave - + Create Date Crea Data - + Expire Date Data di scadenza - - + + Primary Key Chiave primaria - - + + Subkey Sottochiave - + ADSK - + Never Expire Non scade mai - + Never Expires Non scade mai - + Exists Esiste - + Not Exists Non esiste - - + + Yes - - + + No No - + Export Primary Key Esporta Chiave Primaria - + Edit Expire Date Modifica data di scadenza - + Export Esporta - + Delete Elimina - + Revoke Revoca - + Exporting Subkey Esporto la sottochiave - + You are about to export a private subkey. Stai per esportare una sottochiave privata. - + While subkeys are less critical than the primary key, they should still be handled with care. Sebbene le sottochiavi siano meno critiche della chiave primaria, è comunque opportuno gestirle con cura. - + Do you want to proceed with exporting this subkey? Vuoi procedere con l'esportazione di questa sottochiave? - + Export Key To File Esporta chiave in file - + Key Files File chiave - + Export Error Errore di esportazione - + Couldn't open %1 for writing Impossibile aprire %1 per scrittura - + <h3>You are about to delete the subkey:</h3><br /><b>KeyID:</b> %1<br /><br />This action is irreversible. Please confirm. <h3>Stai per eliminare la sottochiave:</h3><br /><b>KeyID:</b> %1<br /><br />Questa azione è irreversibile. Conferma. - + Delete Subkey Confirmation Conferma eliminazione sottochiave - - + + Illegal Operation Operazione illegale - + Cannot delete the primary key or an invalid subkey. Impossibile eliminare la chiave primaria o una sottochiave non valida. - + Operation Failed Operazione fallita - + The selected subkey could not be deleted. Please check your permissions or try again. La sottochiave selezionata non può essere eliminata. Controlla i tuoi permessi o riprova. - + Operation Successful Operazione riuscita - + The subkey with KeyID %1 has been successfully deleted. La sottochiave con KeyID %1 è stata eliminata correttamente. - + <h3>Revoke Subkey Confirmation</h3><br /><b>KeyID:</b> %1<br /><br />Revoking a subkey will make it permanently unusable. This action is <b>irreversible</b>.<br />Are you sure you want to revoke this subkey? <h3>Conferma revoca sottochiave</h3><br /><b>KeyID:</b> %1<br /><br />La revoca di una sottochiave la renderà definitivamente inutilizzabile. Questa azione è <b>irreversibile</b>.<br />Sei ​​sicuro di voler revocare questa sottochiave? - + Revoke Subkey Revoca sottochiave - + Cannot revoke the primary key or an invalid subkey. Impossibile revocare la chiave primaria o una sottochiave non valida. - + 0 -> No Reason. 0 -> Nessun motivo. - + 1 -> This key is no more safe. 1 -> Questa chiave non è più sicura. - + 2 -> Key is outdated. 2 -> La chiave è obsoleta. - + 3 -> Key is no longer used 3 -> La chiave non è più utilizzata - + Revocation Failed Revoca non riuscita - + Failed to revoke the subkey. Please try again. Impossibile revocare la sottochiave. Riprova. - + Revocation Successful Revoca riuscita - + The subkey has been successfully revoked. La sottochiave è stata revocata correttamente. @@ -3876,139 +3906,139 @@ Nota: per la verifica, puoi trovare maggiori informazioni qui: https://keys.open GpgFrontend::UI::KeyServerImportDialog - + Close Chiudi - + Import ALL Importa TUTTO - + Search Ricerca - + Search String Stringa di ricerca - - + + : : - + Key Server Server chiave - + Import Keys from key server Importa chiavi dal server delle chiavi - + UID UID - + Creation date Data di creazione - + KeyID ID chiave - + Tag Etichetta - + Text is empty. Il testo è vuoto. - + Not Key Found Chiave non trovata - + Timeout Tempo scaduto - + Key Server Not Found Server chiave non trovato - + Connection Error Errore di connessione - + Too many responses from keyserver! Troppe risposte dal server delle chiavi! - + No keys found, input may be kexId, retrying search with 0x. Nessuna chiave trovata, l'input potrebbe essere kexId, riprovando la ricerca con 0x. - + No keys found containing the search string! Nessuna chiave trovata contenente la stringa di ricerca! - + Insufficiently specific search string! Stringa di ricerca non sufficientemente specifica! - + revoked revocato - + disabled disabilitato - + %1 keys found. Double click a key to import it. %1 chiavi trovate. Fare doppio clic su una chiave per importarla. - + Warning Avvertimento - + Please select one KeyPair before doing this operation. Si prega di selezionare un KeyPair prima di eseguire questa operazione. - + Key Imported Chiave importata - + Processing ... Elaborazione in corso... @@ -4302,13 +4332,29 @@ Nota: per la verifica, puoi trovare maggiori informazioni qui: https://keys.open GpgFrontend::UI::MainWindow - - + + GUI Pinentry Not Found + + + + + No suitable *graphical* Pinentry program was found on your system. + +Please install a GUI-based Pinentry (e.g., 'pinentry-qt', 'pinentry-gnome3', or 'pinentry-mac' on macOS). + +Without a GUI Pinentry, GnuPG cannot prompt you for passwords or passphrases. + +After installing it, please restart GpgFrontend. The configuration file will be updated automatically. + + + + + Critical error occur while loading GpgFrontend. Si è verificato un errore critico durante il caricamento di GpgFrontend. - + Loading Failed Caricamento non riuscito @@ -5136,26 +5182,26 @@ Se il problema persiste, prendere in considerazione la possibilità di richieder Pannello di stato - - - + + + Successful Operation Operazione riuscita - + Clear password cache successfully Cancella la cache delle password con successo - - - + + + Failed Operation Operazione fallita - + Failed to clear password cache of GnuPG Impossibile cancellare la cache delle password di GnuPG @@ -5170,12 +5216,12 @@ Se il problema persiste, prendere in considerazione la possibilità di richieder Ricarica tutti i componenti di GnuPG - + Reload all the GnuPG's components successfully Ricarica correttamente tutti i componenti di GnuPG - + Failed to reload all or one of the GnuPG's component(s) Impossibile ricaricare tutti o uno dei componenti di GnuPG @@ -5190,12 +5236,12 @@ Se il problema persiste, prendere in considerazione la possibilità di richieder Riavvia tutti i componenti di GnuPG - + Restart all the GnuPG's components successfully Riavvia correttamente tutti i componenti di GnuPG - + Failed to restart all or one of the GnuPG's component(s) Impossibile riavviare tutti o uno dei componenti di GnuPG @@ -5942,495 +5988,464 @@ Se il problema persiste, prendere in considerazione la possibilità di richieder GpgFrontend::UI::SmartCardControllerDialog - + Smart Card(s): - + Key Stub(s) in Key Database(s): - + Change Name - + Change Language - + Change Gender - + Change Login Data - + Change Public Key URL - + Change PIN - + Change Admin PIN - + Change Reset Code - + Fetch - + Restart All Gpg-Agents - + Generate Card Keys - + Refresh Ricaricare - + Operations Operazioni - + Successful Operation Operazione riuscita - + Restart all the GnuPG's components successfully Riavvia correttamente tutti i componenti di GnuPG - + Failed Operation Operazione fallita - + Failed to restart all or one of the GnuPG's component(s) Impossibile riavviare tutti o uno dei componenti di GnuPG - + Generate card key failed. - + Smart Card Controller - + OpenPGP Card Information - + Basic Information - + Reader - + Serial Number - + Card Type - + Card Version - + App Type - + App Version - + Manufacturer ID - + Manufacturer - + Card Holder - + Language Lingua - + Sex - + Signature Counter - + CHV1 Cached - + CHV Max Length - + CHV Retry Left - + KDF Status - + UIF - + Sign Firma - - - + + + Enabled - - - + + + Disabled - + Encrypt Cifra - + Authenticate - + Status Indicator - + Cardholder's Surname - + Please enter your surname (e.g., Lee): - + Cardholder's Given Name - + Please enter your given name (e.g., Chris): - + Too Long - + Combined name too long (max 39 characters). - + Male - + Female - + Select sex to store in '%1' - + Enter new value for attribute '%1' - + Status Stato - + Not enabled - + Enabled (no protection) - + Enabled with salt protection - + Unknown Sconosciuto - + Key Information - + No key information available. - + No. - + Fingerprint Impronta digitale - + Created - + Grip - + Type Tipo - + Algorithm Algoritmo - + Usage Utilizzo - + Curve - + Extended Capabilities - + Key Info (ki): %1 - - - + + + Yes - - - + + + No No - + Additional Auth (aac): %1 - + Biometric Terminal (bt): %1 - + KDF Supported: %1 - + Additional Info - + No OpenPGP Smart Card Found - + No OpenPGP-compatible smart card has been detected. - + An OpenPGP Smart Card is a physical device that securely stores your private cryptographic keys and can be used for digital signing, encryption, and authentication. Popular examples include YubiKey, Nitrokey, and other GnuPG-compatible tokens. - + Make sure your card is inserted and properly recognized by the system. You can also try reconnecting the card or restarting the application. - + Note: Smart card support of GpgFrontend requires GnuPG version 2.3.0 or later. - + Read the GnuPG Smart Card HOWTO: - - + + Modify Card Attribute - - Failed - Fallito - - - - Failed to set attribute '%1'. Reason: %2. - - - - - + + Success Successo - + Attribute operation completed successfully. - - Failed to change Admin PIN. - - - - - Failed to set the Reset Code. - - - - - Failed to change PIN. - - - - - Reason: - - - - - + Error Errore - + PIN operation completed successfully. @@ -6438,82 +6453,82 @@ Se il problema persiste, prendere in considerazione la possibilità di richieder GpgFrontend::UI::SubkeyGenerateDialog - + Tipps: if the key pair has a passphrase, the subkey's passphrase must be equal to it. Suggerimenti: se la coppia di chiavi ha una passphrase, la passphrase della sottochiave deve essere uguale ad essa. - + Generate New Subkey Genera nuova sottochiave - + Authentication Autenticazione - + Algorithm Algoritmo - + Key Length Lunghezza Chiave - + Expire Date Data di scadenza - + Usage Utilizzo - + Encrypt Cifra - + Sign Firma - + Non Expired Non Scaduta - + No Passphrase Nessuna frase segreta - + Please give a valid subkey algorithm. Si prega di fornire un algoritmo di sottochiave valido. - + Time to subkey expiration must not be less than 120 seconds. Il tempo di scadenza della sottochiave non deve essere inferiore a 120 secondi. - + Generating Generazione - + Error Errore - + Unknown error occurred Si è verificato un errore sconosciuto @@ -6990,13 +7005,13 @@ Se il problema persiste, prendere in considerazione la possibilità di richieder - + Usage Utilizzo - + Trust Fiducia @@ -7022,32 +7037,32 @@ Se il problema persiste, prendere in considerazione la possibilità di richieder - + Comment Commento - + ID ID - + Algo - + No Comment - + SubKeys (up to 8): - + ID: %1 | Algo: %2 | Usage: %3 @@ -7176,42 +7191,42 @@ Se il problema persiste, prendere in considerazione la possibilità di richieder Non hai selezionato nessuna chiave pubblica che desideri sincronizzare. Vuoi sincronizzare tutte le chiavi pubbliche locali dal server delle chiavi? - + Cannot Find GpgConf Impossibile trovare GpgConf - + Cannot Find GnuPG Impossibile trovare GnuPG - + Cannot get Infos from GpgConf Impossibile ottenere informazioni da GpgConf - + Cannot Find Default Home Path Impossibile trovare il percorso predefinito di Home - + GpgME Initiation Failed Avvio GpgME non riuscito - + No valid Key Database - + GpgME Default Context Initiation Failed Errore nell'avvio del contesto predefinito di GpgME - + Gpg Default Key Database Initiation Failed Errore nell'avvio del database delle chiavi predefinite Gpg diff --git a/resource/lfs/locale/ts/GpgFrontend.zh_CN.ts b/resource/lfs/locale/ts/GpgFrontend.zh_CN.ts index 986c9e81..6798ffd7 100644 --- a/resource/lfs/locale/ts/GpgFrontend.zh_CN.ts +++ b/resource/lfs/locale/ts/GpgFrontend.zh_CN.ts @@ -492,7 +492,7 @@ GpgFrontend::KeyGenerateInfo - + None @@ -586,22 +586,22 @@ 密钥ID: %1 原因: %2 - + Failed 失败 - + Partially Failed 部分失败 - + Failed to add all selected subkeys. 无法添加任何选中的子密钥。 - + Some subkeys failed to be added as ADSKs. 无法添加选中的部分子密钥。 @@ -769,13 +769,13 @@ GpgFrontend::UI::CommonUtils - + Timeout 超时 - + Success 成功 @@ -795,126 +795,148 @@ Gpg 操作成功。 - - + + Failure 失败 - - Gpg Operation failed. - -Error code: %1 -Source: %2 -Description: %3 - Gpg 操作失败。 - -错误代码: %1 -来源: %2 -说明: %3 - - - - - - + + + + Error 错误 - + Open Key 打开密钥 - + + Operation Not Supported + 不支持的操作 + + + + The current GnuPG version is too low and does not support this operation. Please upgrade your GnuPG version to continue. + 当前 GnuPG 版本过低,不支持此操作。请升级 GnuPG 后重试。 + + + + Gpg Operation failed. + GPG 操作失败。 + + + + Error code: %1 + 错误代码:%1 + + + + Source: %1 + 来源:%1 + + + + Description: %1 + 描述:%1 + + + + Error Message: %1 + 错误信息:%1 + + + Keyring files 密钥圈文件 - + Cannot open this file. Please make sure that this is a regular file and it's readable. 无法打开此文件。请确保这是一个普通文件,并且有读取权限。 - + The target file is too large for a keyring. 目标文件对于一个密钥来说太大。 - + File Open Failed 文件打开失败 - + Failed to open file: 打开文件失败: - + Processing 处理中 - + Failed to execute command. 执行命令失败。 - + Succeed in executing command. 成功执行命令。 - + Warning 警告 - + Finished executing command. 命令执行完毕。 - + Default Keyserver Not Found 未找到默认密钥服务器 - + Cannot read default keyserver from your settings, please set a default keyserver first 无法从您的设置中读取默认密钥服务器,请先设置默认密钥服务器 - + Key Not Found 未找到密钥 - + Key Server Not Found 未找到密钥服务器 - + Connection Error 连接错误 - + Key Not Found. 未找到密钥。 - - + + The key has been updated 密钥已更新 - - + + No need to update the key 无需更新密钥 @@ -1460,70 +1482,70 @@ This will result in loss of all cached form positions, statuses, key servers, et 实际路径 - + Maximum Key Database Limit Reached 已达到密钥数据库上限 - + Currently, GpgFrontend supports a maximum of 8 key databases. Please remove an existing database to add a new one. 目前,GpgFrontend 最多支持 8 个密钥数据库。要添加新数据库,请移除现有数据库。 - - + + Duplicate Key Database Paths 重复的密钥数据库路径 - + The newly added key database path duplicates a previously existing one. 新添加的密钥数据库路径与先前存在的路径重复。 - - + + Invalid Key Database Paths 无效的密钥数据库地址 - - + + The edited key database path is not a valid path that GpgFrontend can use 编辑的密钥数据库路径不是 GpgFrontend 可以使用的有效路径 - + Active 启用 - + Inactive 未启用 - + Confirm Deletion 确认删除 - + Are you sure you want to delete the selected key database? 您确定要删除选定的密钥数据库吗? - + No Key Database Selected 未选择任何密钥数据库 - + Please select a key database to edit. 请选择要编辑的密钥数据库。 - + The edited key database path duplicates a previously existing one. 编辑后的密钥数据库路径与先前存在的路径重复。 @@ -1560,7 +1582,7 @@ This will result in loss of all cached form positions, statuses, key servers, et - + Illegal GnuPG Path 非法 GnuPG 路径 @@ -1575,7 +1597,7 @@ This will result in loss of all cached form positions, statuses, key servers, et 目标 GnuPG 路径不是绝对路径。 - + Target GnuPG Path contains no "gpgconf" executable. 目标 GnuPG 路径不包含“gpgconf”可执行文件。 @@ -1606,10 +1628,18 @@ This will result in loss of all cached form positions, statuses, key servers, et GpgFrontend::UI::GpgOperaHelper - - - - + + + + + Operation Not Supported + 操作不被支持 + + + + + + Critical Error 关键错误 @@ -1827,218 +1857,218 @@ This will result in loss of all cached form positions, statuses, key servers, et GpgFrontend::UI::KeyGenerateDialog - - - - + + + + Custom 自定义 - - + + 3 Months 3个月 - - + + 6 Months 6个月 - - + + 1 Year 1年 - - - - + + + + 2 Years 2年 - - + + 5 Years 5年 - - + + 10 Years 10年 - - - - + + + + Non Expired 不过期 - - - + + + Primary Key Only 仅主密钥 - - + + Primary Key With Subkey 主密钥附带子密钥 - + Name 名称 - + Email 电子邮件 - + Comment 注释 - + Key Database 密钥数据库 - - - + + + Algorithm 算法 - - + + Validity Period 有效时长 - - + + Key Length 密钥长度 - - + + Usage 用法 - - + + Encrypt 加密 - - + + Sign 签名 - - + + Authentication 验证 - + No Passphrase 无密码 - + Expire Date 到期日期 - + Easy Mode 简单模式 - + Primary Key 主密钥 - + Subkey 子密钥 - + Generate 生成 - - + + None - + Generate Key 生成密钥 - + Name must contain at least five characters. 名称必须至少包含五个字符。 - + Please give a valid email address. 请使用一个有效的电子邮件地址。 - + Please give a valid primary key algorithm. 请选择一个有效的主密钥算法。 - + Time to primary key expiration must not be less than 120 seconds. 距离主密钥过期时间不得少于 120 秒。 - + Please give a valid subkey algorithm. 请选择一个有效的子密钥算法。 - + Time to subkey expiration must not be less than 120 seconds. 距离子密钥过期时间不得少于 120 秒。 - + Error 错误 - + Unknown error occurred 发生未知错误 - + Generating 生成中 @@ -2492,7 +2522,7 @@ These keys are no longer available. Do you want to remove them from the group? - + Key Package 密钥包 @@ -2614,22 +2644,22 @@ These keys are no longer available. Do you want to remove them from the group? - - - - - - - - + + + + + + + + Error 错误 - - + + Forbidden 操作被禁止 @@ -2641,102 +2671,102 @@ These keys are no longer available. Do you want to remove them from the group? - + key(s) exported 导出的密钥 - + Exporting 导出中 - - + + Unknown error occurred 发生了未知错误 - + Invalid Operation 无效操作 - + If a key pair does not have a private key then it will not be able to generate sub-keys. 如果密钥对没有私钥,那么它将无法生成子密钥。 - + Please check a key before performing this operation. 请在执行此操作前勾选一个密钥。 - + This operation accepts just a single key. 此操作只接受单个密钥。 - + This key may not be able to export as OpenSSH format. Please check the key-size of the subkey(s) used to sign. 此密钥可能无法导出为 OpenSSH 格式。请检查用于签名的子密钥的密钥大小。 - + Export OpenSSH Key To File 将 OpenSSH 密钥导出到文件 - + OpenSSH Public Key Files OpenSSH 公钥文件 - + Import Key Package 导入密钥包 - - + + Cannot open this file. Please make sure that this is a regular file and it's readable. 无法打开此文件。请确保这是一个普通文件,并且有读取权限。 - + The target file is too large for a key package. 目标文件对于密钥包来说太大。 - + Import Key Package Passphrase File 导入密钥包口令文件 - + Key Package Passphrase File 密钥包口令文件 - + The target file is too large for a key package passphrase. 目标文件对于密钥包口令来说太大。 - + Importing 导入中 - + key(s) imported 导入的密钥 - + An error occur in importing key package. 导入密钥包出错。 @@ -3329,313 +3359,313 @@ Note: For verification, you can find more information here: https://keys.openpgp GpgFrontend::UI::KeyPairSubkeyTab - - + + Key ID 密钥编号 - - + + Algorithm 算法 - - + + Algorithm Detail 算法细节 - - + + Key Size 密钥大小 - + Usage 用法 - + Expires On (Local Time) 到期时间(本地时间) - + Create Date (Local Time) 创建日期(本地时间) - + Existence 存在 - + Key in Smart Card 在智能卡中 - + Fingerprint 指纹 - + List of the primary key and subkey(s) 主密钥和子密钥列表 - + Detail of Selected Primary Key/Subkey 选中的主密钥/子密钥详情 - + New Subkey 新子密钥 - + Add ADSK(s) 添加ADSK - - + + Key Type 密钥类型 - + Revoked 已吊销 - - + + Export Subkey 导出子密钥 - + Create Date 创建时间 - + Expire Date 到期日期 - - + + Primary Key 主密钥 - - + + Subkey 子密钥 - + ADSK ADSK - + Never Expire 永不过期 - + Never Expires 永不过期 - + Exists 存在 - + Not Exists 不存在 - - + + Yes - - + + No - + Export Primary Key 导出主密钥 - + Edit Expire Date 编辑到期日期 - + Export 导出 - + Delete 删除 - + Revoke 吊销 - + Exporting Subkey 正在导出子密钥 - + You are about to export a private subkey. 您即将导出一个子密钥的私有部分。 - + While subkeys are less critical than the primary key, they should still be handled with care. 虽然子密钥没有主密钥那么重要,但仍应小心处理。 - + Do you want to proceed with exporting this subkey? 是否要继续导出该子密钥? - + Export Key To File 将密钥导出到文件 - + Key Files 密钥文件 - + Export Error 导出错误 - + Couldn't open %1 for writing 无法打开 %1 进行写入 - + <h3>You are about to delete the subkey:</h3><br /><b>KeyID:</b> %1<br /><br />This action is irreversible. Please confirm. <h3>您即将删除子密钥:</h3><br /><b>KeyID:</b> %1<br /><br />此操作不可逆。请确认。 - + Delete Subkey Confirmation 确认删除子密钥 - - + + Illegal Operation 非法的操作 - + Cannot delete the primary key or an invalid subkey. 无法删除主密钥或者不可用的子密钥。 - + Operation Failed 操作失败 - + The selected subkey could not be deleted. Please check your permissions or try again. 所选子密钥无法删除。请检查权限或重试。 - + Operation Successful 操作成功 - + The subkey with KeyID %1 has been successfully deleted. 密钥ID为 %1 的子密钥已成功删除。 - + <h3>Revoke Subkey Confirmation</h3><br /><b>KeyID:</b> %1<br /><br />Revoking a subkey will make it permanently unusable. This action is <b>irreversible</b>.<br />Are you sure you want to revoke this subkey? <h3>子密钥吊销确认</h3><br /><b>KeyID:</b>%1<br /><br />吊销子密钥将使其永久不可用。此操作是 <b>不可逆的</b>。<br />您确定要撤销此子密钥吗? - + Revoke Subkey 吊销子密钥 - + Cannot revoke the primary key or an invalid subkey. 无法吊销主密钥或者无效的子密钥。 - + 0 -> No Reason. 0 -> 无理由。 - + 1 -> This key is no more safe. 1 -> 密钥不再安全。 - + 2 -> Key is outdated. 2 -> 密钥已经过时。 - + 3 -> Key is no longer used 3 -> 密钥不再被使用。 - + Revocation Failed 吊销失败 - + Failed to revoke the subkey. Please try again. 吊销子密钥失败。请重试。 - + Revocation Successful 吊销成功 - + The subkey has been successfully revoked. 子密钥成功吊销 @@ -3871,139 +3901,139 @@ Note: For verification, you can find more information here: https://keys.openpgp GpgFrontend::UI::KeyServerImportDialog - + Close 关闭 - + Import ALL 全部导入 - + Search 搜索 - + Search String 搜索字符串 - - + + : - + Key Server 密钥服务器 - + Import Keys from key server 从密钥服务器导入密钥 - + UID UID - + Creation date 创建日期 - + KeyID 密钥 ID - + Tag 标签 - + Text is empty. 文字为空。 - + Not Key Found 未找到密钥 - + Timeout 超时 - + Key Server Not Found 未找到密钥服务器 - + Connection Error 连接错误 - + Too many responses from keyserver! 来自密钥服务器的响应太多! - + No keys found, input may be kexId, retrying search with 0x. 未找到密钥,输入可能是 kexId,正在使用 0x 重试。 - + No keys found containing the search string! 未找到包含搜索字符串的密钥! - + Insufficiently specific search string! 不够具体的搜索字符串! - + revoked 撤销 - + disabled 被禁用 - + %1 keys found. Double click a key to import it. 找到 %1 个密钥。双击一个密钥来导入它。 - + Warning 警告 - + Please select one KeyPair before doing this operation. 请在执行此操作前选择一个钥对。 - + Key Imported 密钥导入成功 - + Processing ... 处理中 ...... @@ -4297,13 +4327,35 @@ Note: For verification, you can find more information here: https://keys.openpgp GpgFrontend::UI::MainWindow - - + + GUI Pinentry Not Found + 未找到可用的图形化 Pinentry 程序 + + + + No suitable *graphical* Pinentry program was found on your system. + +Please install a GUI-based Pinentry (e.g., 'pinentry-qt', 'pinentry-gnome3', or 'pinentry-mac' on macOS). + +Without a GUI Pinentry, GnuPG cannot prompt you for passwords or passphrases. + +After installing it, please restart GpgFrontend. The configuration file will be updated automatically. + 系统中未找到可用的图形化 Pinentry 程序。 + +请安装一个基于图形界面的 Pinentry(例如:pinentry-qt、pinentry-gnome3,或在 macOS 上的 pinentry-mac)。 + +没有图形化 Pinentry,GnuPG 无法提示您输入密码或口令。 + +安装完成后,请重新启动 GpgFrontend,配置文件将自动更新。 + + + + Critical error occur while loading GpgFrontend. 加载 GpgFrontend 时发生严重错误。 - + Loading Failed 加载失败 @@ -5133,26 +5185,26 @@ If the issue persists, consider seeking technical support or consulting the docu 状态面板 - - - + + + Successful Operation 操作成功 - + Clear password cache successfully 清除密码缓存成功 - - - + + + Failed Operation 操作失败 - + Failed to clear password cache of GnuPG 无法清除 GnuPG 的密码缓存 @@ -5167,12 +5219,12 @@ If the issue persists, consider seeking technical support or consulting the docu 重新加载所有 GnuPG 的组件 - + Reload all the GnuPG's components successfully 成功重新加载所有 GnuPG 组件 - + Failed to reload all or one of the GnuPG's component(s) 未能重新加载所有或其中一个 GnuPG 组件 @@ -5187,12 +5239,12 @@ If the issue persists, consider seeking technical support or consulting the docu 重新启动所有 GnuPG 的组件 - + Restart all the GnuPG's components successfully 成功重启所有 GnuPG 组件 - + Failed to restart all or one of the GnuPG's component(s) 无法重新启动所有或其中一个 GnuPG 组件 @@ -5939,495 +5991,464 @@ If the issue persists, consider seeking technical support or consulting the docu GpgFrontend::UI::SmartCardControllerDialog - + Smart Card(s): 智能卡: - + Key Stub(s) in Key Database(s): 在密钥数据库中的密钥桩: - + Change Name 修改姓名 - + Change Language 修改语言 - + Change Gender 修改性别 - + Change Login Data 修改登录信息 - + Change Public Key URL 修改公钥链接 - + Change PIN 修改PIN - + Change Admin PIN 修改管理员PIN - + Change Reset Code 修改重置代码 - + Fetch 同步密钥信息 - + Restart All Gpg-Agents 重启所有Gpg-Agents - + Generate Card Keys 生成智能卡密钥 - + Refresh 刷新 - + Operations 操作 - + Successful Operation 操作成功 - + Restart all the GnuPG's components successfully 成功重启所有 GnuPG 组件 - + Failed Operation 操作失败 - + Failed to restart all or one of the GnuPG's component(s) 无法重新启动所有或其中一个 GnuPG 组件 - + Generate card key failed. 生成智能卡密钥失败。 - + Smart Card Controller 智能卡控制器 - + OpenPGP Card Information OpenPGP智能卡信息 - + Basic Information 基本信息 - + Reader 读卡器 - + Serial Number 序列号 - + Card Type 卡片类型 - + Card Version 卡片版本 - + App Type 应用类型 - + App Version 应用版本 - + Manufacturer ID 制造商ID - + Manufacturer 制造商 - + Card Holder 持卡人 - + Language 语言 - + Sex 性别 - + Signature Counter 签名计数器 - + CHV1 Cached 已缓存普通PIN - + CHV Max Length PIN最大长度 - + CHV Retry Left PIN剩余重试次数 - + KDF Status 密钥派生函数状态 - + UIF 用户交互标志 - + Sign 签名 - - - + + + Enabled 已启用 - - - + + + Disabled 已禁用 - + Encrypt 加密 - + Authenticate 验证 - + Status Indicator 状态指示器 - + Cardholder's Surname 持卡人的姓氏 - + Please enter your surname (e.g., Lee): 请输入您的姓氏 (如: 李): - + Cardholder's Given Name 持卡人的名字 - + Please enter your given name (e.g., Chris): 请输入您的名字 (如: 四): - + Too Long 太长 - + Combined name too long (max 39 characters). 姓名合并后太长 (最长39个字符)。 - + Male - + Female - + Select sex to store in '%1' 选择存储在 '%1' 中的性别 - + Enter new value for attribute '%1' 请输入 '%1' 的新值 - + Status 状态 - + Not enabled 未启用 - + Enabled (no protection) 启用 (无保护) - + Enabled with salt protection 启用并开启加盐保护 - + Unknown 未知 - + Key Information 密钥信息 - + No key information available. 未发现可用密钥信息 - + No. 序号 - + Fingerprint 指纹 - + Created 已生成 - + Grip 内部密钥标识符 - + Type 类型 - + Algorithm 算法 - + Usage 用法 - + Curve 密钥曲线 - + Extended Capabilities 扩展能力 - + Key Info (ki): %1 密钥信息 (ki): %1 - - - + + + Yes - - - + + + No - + Additional Auth (aac): %1 额外验证 (aac): %1 - + Biometric Terminal (bt): %1 生物终端: %1 - + KDF Supported: %1 密钥派生函数支持: %1 - + Additional Info 额外信息 - + No OpenPGP Smart Card Found 未发现OpenPGP智能卡 - + No OpenPGP-compatible smart card has been detected. 未检测到兼容 OpenPGP 的智能卡。 - + An OpenPGP Smart Card is a physical device that securely stores your private cryptographic keys and can be used for digital signing, encryption, and authentication. Popular examples include YubiKey, Nitrokey, and other GnuPG-compatible tokens. OpenPGP 智能卡是一种物理设备,可以安全地存储你的私人加密密钥,并可用于数字签名、加密和身份验证。流行的例子包括 YubiKey、Nitrokey 和其他 GnuPG 兼容令牌。 - + Make sure your card is inserted and properly recognized by the system. You can also try reconnecting the card or restarting the application. 确保您的卡已插入并被系统正确识别。您也可以尝试重新连接卡或重启应用程序。 - + Note: Smart card support of GpgFrontend requires GnuPG version 2.3.0 or later. 注意:GpgFrontend 的智能卡支持需要 GnuPG 2.3.0 或更高版本。 - + Read the GnuPG Smart Card HOWTO: 阅读 GnuPG 智能卡帮助文档 - - + + Modify Card Attribute 修改智能卡属性 - - Failed - 失败 - - - - Failed to set attribute '%1'. Reason: %2. - 修改属性 '%1' 失败。 原因: %2。 - - - - + + Success 成功 - + Attribute operation completed successfully. 属性操作成功完成。 - - Failed to change Admin PIN. - 修改管理员PIN失败。 - - - - Failed to set the Reset Code. - 修改重置代码失败。 - - - - Failed to change PIN. - 修改PIN失败。 - - - - Reason: - 原因: - - - - + Error 错误 - + PIN operation completed successfully. PIN操作成功完成。 @@ -6435,82 +6456,82 @@ If the issue persists, consider seeking technical support or consulting the docu GpgFrontend::UI::SubkeyGenerateDialog - + Tipps: if the key pair has a passphrase, the subkey's passphrase must be equal to it. 提示:如果主密钥和子密钥都有密码,则子密钥的密码必须与主密钥相同。 - + Generate New Subkey 生成新子密钥 - + Authentication 验证 - + Algorithm 算法 - + Key Length 密钥长度 - + Expire Date 到期日期 - + Usage 用法 - + Encrypt 加密 - + Sign 签名 - + Non Expired 不过期 - + No Passphrase 无密码 - + Please give a valid subkey algorithm. 请选择一个有效的子密钥算法。 - + Time to subkey expiration must not be less than 120 seconds. 距离主密钥过期时间不得少于120秒。 - + Generating 生成中 - + Error 错误 - + Unknown error occurred 发生未知错误 @@ -6987,13 +7008,13 @@ If the issue persists, consider seeking technical support or consulting the docu - + Usage 用法 - + Trust 信任 @@ -7019,32 +7040,32 @@ If the issue persists, consider seeking technical support or consulting the docu - + Comment 注释 - + ID ID - + Algo 算法 - + No Comment 无备注 - + SubKeys (up to 8): 子密钥 (前8个): - + ID: %1 | Algo: %2 | Usage: %3 ID: %1 | 算法: %2 | 用法: %3 @@ -7173,42 +7194,42 @@ If the issue persists, consider seeking technical support or consulting the docu 您没有选中任何要同步的公钥,是否要从密钥服务器同步所有本地公钥? - + Cannot Find GpgConf 无法找到 GpgConf - + Cannot Find GnuPG 无法找到 GnuPG - + Cannot get Infos from GpgConf 无法从GpgConf获取信息 - + Cannot Find Default Home Path 无法找到默认的GnuPG家目录 - + GpgME Initiation Failed GpgME 初始化失败 - + No valid Key Database 没有有效的密钥数据库 - + GpgME Default Context Initiation Failed GpgME 默认上下文初始化失败 - + Gpg Default Key Database Initiation Failed Gpg 默认密钥数据库初始化失败 diff --git a/resource/lfs/locale/ts/GpgFrontend.zh_TW.ts b/resource/lfs/locale/ts/GpgFrontend.zh_TW.ts index 7d3e3412..9270bdcc 100644 --- a/resource/lfs/locale/ts/GpgFrontend.zh_TW.ts +++ b/resource/lfs/locale/ts/GpgFrontend.zh_TW.ts @@ -492,7 +492,7 @@ GpgFrontend::KeyGenerateInfo - + None @@ -586,22 +586,22 @@ - + Failed 失敗 - + Partially Failed - + Failed to add all selected subkeys. - + Some subkeys failed to be added as ADSKs. @@ -769,13 +769,13 @@ GpgFrontend::UI::CommonUtils - + Timeout 暫停 - + Success 成功 @@ -795,122 +795,148 @@ - - + + Failure 失敗 - - Gpg Operation failed. - -Error code: %1 -Source: %2 -Description: %3 - - - - - - - + + + + Error 錯誤 - + Open Key 開關鍵 - + + Operation Not Supported + + + + + The current GnuPG version is too low and does not support this operation. Please upgrade your GnuPG version to continue. + + + + + Gpg Operation failed. + + + + + Error code: %1 + + + + + Source: %1 + + + + + Description: %1 + + + + + Error Message: %1 + + + + Keyring files 鑰匙圈文件 - + Cannot open this file. Please make sure that this is a regular file and it's readable. - + The target file is too large for a keyring. - + File Open Failed 文件打開失敗 - + Failed to open file: 開啟檔案失敗原因 : - + Processing 加工 - + Failed to execute command. 無法執行命令。 - + Succeed in executing command. 成功執行命令。 - + Warning 警告 - + Finished executing command. 命令執行完畢。 - + Default Keyserver Not Found 未找到預設金鑰伺服器 - + Cannot read default keyserver from your settings, please set a default keyserver first 無法從您的設定值中讀取預設金鑰伺服器,請先設定值預設金鑰伺服器 - + Key Not Found 未找到金鑰 - + Key Server Not Found 未找到金鑰伺服器 - + Connection Error 連線錯誤 - + Key Not Found. 未找到金鑰。 - - + + The key has been updated 金鑰已更新 - - + + No need to update the key 無需更新金鑰 @@ -1456,70 +1482,70 @@ This will result in loss of all cached form positions, statuses, key servers, et - + Maximum Key Database Limit Reached - + Currently, GpgFrontend supports a maximum of 8 key databases. Please remove an existing database to add a new one. - - + + Duplicate Key Database Paths - + The newly added key database path duplicates a previously existing one. - - + + Invalid Key Database Paths - - + + The edited key database path is not a valid path that GpgFrontend can use - + Active - + Inactive - + Confirm Deletion - + Are you sure you want to delete the selected key database? - + No Key Database Selected - + Please select a key database to edit. - + The edited key database path duplicates a previously existing one. @@ -1556,7 +1582,7 @@ This will result in loss of all cached form positions, statuses, key servers, et - + Illegal GnuPG Path 非法 GnuPG 路徑 @@ -1571,7 +1597,7 @@ This will result in loss of all cached form positions, statuses, key servers, et 目標 GnuPG 路徑不是絕對路徑。 - + Target GnuPG Path contains no "gpgconf" executable. 目標 GnuPG 路徑不包含“gpgconf”可執行文件。 @@ -1602,10 +1628,18 @@ This will result in loss of all cached form positions, statuses, key servers, et GpgFrontend::UI::GpgOperaHelper - - - - + + + + + Operation Not Supported + + + + + + + Critical Error @@ -1823,218 +1857,218 @@ This will result in loss of all cached form positions, statuses, key servers, et GpgFrontend::UI::KeyGenerateDialog - - - - - Custom - - - + - - 3 Months + + + Custom - 6 Months + 3 Months - 1 Year + 6 Months - - - 2 Years + 1 Year + + - 5 Years + 2 Years - 10 Years + 5 Years - - - + + 10 Years + + + + + + + Non Expired - - - + + + Primary Key Only - - + + Primary Key With Subkey - + Name 姓名 - + Email 電子郵件 - + Comment 評論 - + Key Database 金鑰數據庫 - - - + + + Algorithm 算法 - - + + Validity Period - - + + Key Length - - + + Usage 用法 - - + + Encrypt 加密 - - + + Sign 標誌 - - + + Authentication 驗證 - + No Passphrase - + Expire Date 到期日期 - + Easy Mode - + Primary Key 首要的關鍵 - + Subkey - + Generate - - + + None - + Generate Key 生成金鑰 - + Name must contain at least five characters. 名稱必須至少包含五個字符。 - + Please give a valid email address. - + Please give a valid primary key algorithm. - + Time to primary key expiration must not be less than 120 seconds. - + Please give a valid subkey algorithm. - + Time to subkey expiration must not be less than 120 seconds. - + Error 錯誤 - + Unknown error occurred - + Generating 生成 @@ -2483,7 +2517,7 @@ These keys are no longer available. Do you want to remove them from the group? - + Key Package 鑰匙包 @@ -2605,22 +2639,22 @@ These keys are no longer available. Do you want to remove them from the group? - - - - - - - - + + + + + + + + Error 錯誤 - - + + Forbidden 禁止的 @@ -2632,102 +2666,102 @@ These keys are no longer available. Do you want to remove them from the group? - + key(s) exported 導出的金鑰 - + Exporting - - + + Unknown error occurred - + Invalid Operation 無效操作 - + If a key pair does not have a private key then it will not be able to generate sub-keys. 如果金鑰對沒有私鑰,那麼它將無法生成子金鑰。 - + Please check a key before performing this operation. - + This operation accepts just a single key. - + This key may not be able to export as OpenSSH format. Please check the key-size of the subkey(s) used to sign. 此金鑰可能無法導出為 OpenSSH 格式。請檢查用於簽名的子金鑰的金鑰大小。 - + Export OpenSSH Key To File 將 OpenSSH 金鑰導出到文件 - + OpenSSH Public Key Files OpenSSH 公鑰文件 - + Import Key Package 導入金鑰包 - - + + Cannot open this file. Please make sure that this is a regular file and it's readable. - + The target file is too large for a key package. - + Import Key Package Passphrase File 導入金鑰包密碼文件 - + Key Package Passphrase File 金鑰包密碼文件 - + The target file is too large for a key package passphrase. - + Importing - + key(s) imported 導入的金鑰 - + An error occur in importing key package. 導入金鑰包出錯。 @@ -3312,313 +3346,313 @@ Note: For verification, you can find more information here: https://keys.openpgp GpgFrontend::UI::KeyPairSubkeyTab - - + + Key ID 鑰匙編號 - - + + Algorithm 算法 - - + + Algorithm Detail 算法細節 - - + + Key Size 金鑰大小 - + Usage 用法 - + Expires On (Local Time) 到期時間(當地時間) - + Create Date (Local Time) 創建日期(當地時間) - + Existence 存在 - + Key in Smart Card 輸入智能卡 - + Fingerprint 指紋 - + List of the primary key and subkey(s) - + Detail of Selected Primary Key/Subkey - + New Subkey 新增子系金鑰 - + Add ADSK(s) - - + + Key Type 鑰匙類型 - + Revoked 撤銷 - - + + Export Subkey - + Create Date - + Expire Date 到期日期 - - + + Primary Key 首要的關鍵 - - + + Subkey - + ADSK - + Never Expire 永不過期 - + Never Expires 永不過期 - + Exists 存在 - + Not Exists 不存在 - - + + Yes 是的 - - + + No - + Export Primary Key - + Edit Expire Date 編輯到期日 - + Export - + Delete 刪除 - + Revoke - + Exporting Subkey - + You are about to export a private subkey. - + While subkeys are less critical than the primary key, they should still be handled with care. - + Do you want to proceed with exporting this subkey? - + Export Key To File 將金鑰導出到文件 - + Key Files 關鍵文件 - + Export Error 導出錯誤 - + Couldn't open %1 for writing 無法打開 %1 進行寫入 - + <h3>You are about to delete the subkey:</h3><br /><b>KeyID:</b> %1<br /><br />This action is irreversible. Please confirm. - + Delete Subkey Confirmation - - + + Illegal Operation - + Cannot delete the primary key or an invalid subkey. - + Operation Failed 手術失敗 - + The selected subkey could not be deleted. Please check your permissions or try again. - + Operation Successful - + The subkey with KeyID %1 has been successfully deleted. - + <h3>Revoke Subkey Confirmation</h3><br /><b>KeyID:</b> %1<br /><br />Revoking a subkey will make it permanently unusable. This action is <b>irreversible</b>.<br />Are you sure you want to revoke this subkey? - + Revoke Subkey - + Cannot revoke the primary key or an invalid subkey. - + 0 -> No Reason. - + 1 -> This key is no more safe. - + 2 -> Key is outdated. - + 3 -> Key is no longer used - + Revocation Failed - + Failed to revoke the subkey. Please try again. - + Revocation Successful - + The subkey has been successfully revoked. @@ -3854,139 +3888,139 @@ Note: For verification, you can find more information here: https://keys.openpgp GpgFrontend::UI::KeyServerImportDialog - + Close 關閉 - + Import ALL 全部導入 - + Search 搜索 - + Search String 搜索字符串 - - + + : : - + Key Server 金鑰伺服器 - + Import Keys from key server - + UID 用戶識別碼 - + Creation date 創立日期 - + KeyID 金鑰 ID - + Tag 標籤 - + Text is empty. 文字為空。 - + Not Key Found 未找到金鑰 - + Timeout 暫停 - + Key Server Not Found 未找到金鑰伺服器 - + Connection Error 連線錯誤 - + Too many responses from keyserver! 來自金鑰伺服器的響應太多! - + No keys found, input may be kexId, retrying search with 0x. 未找到鍵,輸入可能是 kexId,使用 0x 重試搜索。 - + No keys found containing the search string! 未找到包含搜索字符串的鍵! - + Insufficiently specific search string! 不夠具體的搜索字符串! - + revoked 撤銷 - + disabled 殘疾 - + %1 keys found. Double click a key to import it. 找到 %1 個金鑰。雙擊一個鍵來導入它。 - + Warning 警告 - + Please select one KeyPair before doing this operation. 請在執行此操作前選擇一個 KeyPair。 - + Key Imported 鑰匙進口 - + Processing ... @@ -4280,13 +4314,29 @@ Note: For verification, you can find more information here: https://keys.openpgp GpgFrontend::UI::MainWindow - - + + GUI Pinentry Not Found + + + + + No suitable *graphical* Pinentry program was found on your system. + +Please install a GUI-based Pinentry (e.g., 'pinentry-qt', 'pinentry-gnome3', or 'pinentry-mac' on macOS). + +Without a GUI Pinentry, GnuPG cannot prompt you for passwords or passphrases. + +After installing it, please restart GpgFrontend. The configuration file will be updated automatically. + + + + + Critical error occur while loading GpgFrontend. 加載 GpgFrontend 時發生嚴重錯誤。 - + Loading Failed 加載失敗 @@ -5068,26 +5118,26 @@ If the issue persists, consider seeking technical support or consulting the docu - - - + + + Successful Operation 成功運作 - + Clear password cache successfully 清除密碼緩存成功 - - - + + + Failed Operation 操作失敗 - + Failed to clear password cache of GnuPG 無法清除 GnuPG 的密碼緩存 @@ -5102,12 +5152,12 @@ If the issue persists, consider seeking technical support or consulting the docu 重新加載所有 GnuPG 的組件 - + Reload all the GnuPG's components successfully 成功重新加載所有 GnuPG 組件 - + Failed to reload all or one of the GnuPG's component(s) 未能重新加載所有或其中一個 GnuPG 組件 @@ -5122,12 +5172,12 @@ If the issue persists, consider seeking technical support or consulting the docu 重新啟動所有 GnuPG 的組件 - + Restart all the GnuPG's components successfully 成功重啟所有 GnuPG 組件 - + Failed to restart all or one of the GnuPG's component(s) 無法重新啟動所有或其中一個 GnuPG 組件 @@ -5874,495 +5924,464 @@ If the issue persists, consider seeking technical support or consulting the docu GpgFrontend::UI::SmartCardControllerDialog - + Smart Card(s): - + Key Stub(s) in Key Database(s): - + Change Name - + Change Language - + Change Gender - + Change Login Data - + Change Public Key URL - + Change PIN - + Change Admin PIN - + Change Reset Code - + Fetch - + Restart All Gpg-Agents - + Generate Card Keys - + Refresh 刷新 - + Operations 運作中 - + Successful Operation 成功運作 - + Restart all the GnuPG's components successfully 成功重啟所有 GnuPG 組件 - + Failed Operation 操作失敗 - + Failed to restart all or one of the GnuPG's component(s) 無法重新啟動所有或其中一個 GnuPG 組件 - + Generate card key failed. - + Smart Card Controller - + OpenPGP Card Information - + Basic Information - + Reader - + Serial Number - + Card Type - + Card Version - + App Type - + App Version - + Manufacturer ID - + Manufacturer - + Card Holder - + Language - + Sex - + Signature Counter - + CHV1 Cached - + CHV Max Length - + CHV Retry Left - + KDF Status - + UIF - + Sign 標誌 - - - + + + Enabled - - - + + + Disabled - + Encrypt 加密 - + Authenticate - + Status Indicator - + Cardholder's Surname - + Please enter your surname (e.g., Lee): - + Cardholder's Given Name - + Please enter your given name (e.g., Chris): - + Too Long - + Combined name too long (max 39 characters). - + Male - + Female - + Select sex to store in '%1' - + Enter new value for attribute '%1' - + Status 狀態 - + Not enabled - + Enabled (no protection) - + Enabled with salt protection - + Unknown 未知 - + Key Information - + No key information available. - + No. - + Fingerprint 指紋 - + Created - + Grip - + Type 類型 - + Algorithm 算法 - + Usage 用法 - + Curve - + Extended Capabilities - + Key Info (ki): %1 - - - + + + Yes 是的 - - - + + + No - + Additional Auth (aac): %1 - + Biometric Terminal (bt): %1 - + KDF Supported: %1 - + Additional Info - + No OpenPGP Smart Card Found - + No OpenPGP-compatible smart card has been detected. - + An OpenPGP Smart Card is a physical device that securely stores your private cryptographic keys and can be used for digital signing, encryption, and authentication. Popular examples include YubiKey, Nitrokey, and other GnuPG-compatible tokens. - + Make sure your card is inserted and properly recognized by the system. You can also try reconnecting the card or restarting the application. - + Note: Smart card support of GpgFrontend requires GnuPG version 2.3.0 or later. - + Read the GnuPG Smart Card HOWTO: - - + + Modify Card Attribute - - Failed - 失敗 - - - - Failed to set attribute '%1'. Reason: %2. - - - - - + + Success 成功 - + Attribute operation completed successfully. - - Failed to change Admin PIN. - - - - - Failed to set the Reset Code. - - - - - Failed to change PIN. - - - - - Reason: - - - - - + Error 錯誤 - + PIN operation completed successfully. @@ -6370,82 +6389,82 @@ If the issue persists, consider seeking technical support or consulting the docu GpgFrontend::UI::SubkeyGenerateDialog - + Tipps: if the key pair has a passphrase, the subkey's passphrase must be equal to it. 提示:如果金鑰對有密碼,則子金鑰的密碼必須與其相等。 - + Generate New Subkey 生成新子金鑰 - + Authentication 驗證 - + Algorithm 算法 - + Key Length - + Expire Date 到期日期 - + Usage 用法 - + Encrypt 加密 - + Sign 標誌 - + Non Expired - + No Passphrase - + Please give a valid subkey algorithm. - + Time to subkey expiration must not be less than 120 seconds. - + Generating 生成 - + Error 錯誤 - + Unknown error occurred @@ -6922,13 +6941,13 @@ If the issue persists, consider seeking technical support or consulting the docu - + Usage 用法 - + Trust 相信 @@ -6954,32 +6973,32 @@ If the issue persists, consider seeking technical support or consulting the docu - + Comment 評論 - + ID - + Algo - + No Comment - + SubKeys (up to 8): - + ID: %1 | Algo: %2 | Usage: %3 @@ -7108,42 +7127,42 @@ If the issue persists, consider seeking technical support or consulting the docu - + Cannot Find GpgConf - + Cannot Find GnuPG - + Cannot get Infos from GpgConf - + Cannot Find Default Home Path - + GpgME Initiation Failed - + No valid Key Database - + GpgME Default Context Initiation Failed - + Gpg Default Key Database Initiation Failed diff --git a/src/core/GpgCoreInit.cpp b/src/core/GpgCoreInit.cpp index 1735c316..561c3e24 100644 --- a/src/core/GpgCoreInit.cpp +++ b/src/core/GpgCoreInit.cpp @@ -429,10 +429,6 @@ void EnsureGpgAgentConfHasPinentry(GpgContext& ctx) { } 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"; } @@ -612,7 +608,8 @@ auto InitGpgFrontendCore(CoreInitArgs args) -> int { return -1; } -#if defined(__linux__) +#if !(defined(_WIN32) || defined(WIN32)) + // auto config pinentry-program EnsureGpgAgentConfHasPinentry(default_ctx); #endif @@ -669,6 +666,10 @@ auto InitGpgFrontendCore(CoreInitArgs args) -> int { EnsureGpgAgentConfHasPinentry(ctx); #endif +#if defined(__APPLE__) && defined(__MACH__) + 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/GpgContext.cpp b/src/core/function/gpg/GpgContext.cpp index de450356..ca00c452 100644 --- a/src/core/function/gpg/GpgContext.cpp +++ b/src/core/function/gpg/GpgContext.cpp @@ -43,7 +43,7 @@ #include "core/utils/GpgUtils.h" #include "core/utils/MemoryUtils.h" -#ifdef _WIN32 +#if defined(_WIN32) || defined(WIN32) #include #endif @@ -408,7 +408,7 @@ class GpgContext::Impl { auto configuration_name = info_split_list[0].trimmed(); auto configuration_value = info_split_list[1].trimmed(); -#ifdef __MINGW32__ +#if defined(_WIN32) || defined(WIN32) // replace some special substrings on windows // platform configuration_value.replace("%3a", ":"); diff --git a/src/core/utils/GpgUtils.cpp b/src/core/utils/GpgUtils.cpp index 8b2abeb7..d8f147bb 100644 --- a/src/core/utils/GpgUtils.cpp +++ b/src/core/utils/GpgUtils.cpp @@ -462,6 +462,8 @@ auto GPGFRONTEND_CORE_EXPORT DecidePinentry() -> QString { QStringList preferred_list = {"pinentry-gnome3", "pinentry-qt" "pinentry-gtk2"}; +#elif defined(__APPLE__) && defined(__MACH__) + QStringList preferred_list = {"pinentry-mac", "pinentry-qt"}; #else QStringList preferred_list = {"pinentry-qt"}; #endif diff --git a/src/ui/UserInterfaceUtils.cpp b/src/ui/UserInterfaceUtils.cpp index b5747b9f..dbc3f7e3 100644 --- a/src/ui/UserInterfaceUtils.cpp +++ b/src/ui/UserInterfaceUtils.cpp @@ -169,10 +169,9 @@ 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.")); + parent, tr("Operation Not Supported"), + 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, diff --git a/src/ui/dialog/controller/GnuPGControllerDialog.cpp b/src/ui/dialog/controller/GnuPGControllerDialog.cpp index 5dacae65..3f21b57b 100644 --- a/src/ui/dialog/controller/GnuPGControllerDialog.cpp +++ b/src/ui/dialog/controller/GnuPGControllerDialog.cpp @@ -333,7 +333,8 @@ auto GnuPGControllerDialog::check_custom_gnupg_path(QString path) -> bool { QMessageBox::critical(this, tr("Illegal GnuPG Path"), tr("Target GnuPG Path is not an absolute path.")); } -#ifdef __MINGW32__ + +#if defined(_WIN32) || defined(WIN32) QFileInfo const gpgconf_info(path + "/gpgconf.exe"); #else QFileInfo const gpgconf_info(path + "/gpgconf"); diff --git a/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp b/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp index b8942b94..64e4d029 100644 --- a/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp +++ b/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp @@ -31,7 +31,6 @@ #include "core/function/gpg/GpgKeyGetter.h" #include "core/function/gpg/GpgKeyImportExporter.h" #include "core/function/gpg/GpgKeyManager.h" -#include "core/function/gpg/GpgKeyOpera.h" #include "core/utils/CommonUtils.h" #include "core/utils/GpgUtils.h" #include "core/utils/IOUtils.h" diff --git a/src/ui/dialog/keypair_details/KeyPairSubkeyTab.h b/src/ui/dialog/keypair_details/KeyPairSubkeyTab.h index 3d9eeb50..c7d7a08a 100644 --- a/src/ui/dialog/keypair_details/KeyPairSubkeyTab.h +++ b/src/ui/dialog/keypair_details/KeyPairSubkeyTab.h @@ -47,55 +47,13 @@ class KeyPairSubkeyTab : public QWidget { */ KeyPairSubkeyTab(int channel, GpgKeyPtr key, QWidget* parent); - private: - /** - * @brief Create a subkey list object - * - */ - void create_subkey_list(); - - /** - * @brief Create a subkey opera menu object - * - */ - void create_subkey_opera_menu(); - + protected: /** - * @brief Get the selected subkey object + * @brief * - * @return const GpgSubKey& + * @param event */ - auto get_selected_subkey() -> const GpgSubKey&; - - int current_gpg_context_channel_; - GpgKeyPtr key_; ///< - QTableWidget* subkey_list_{}; ///< - QContainer buffered_subkeys_; ///< - - QGroupBox* list_box_; ///< - QGroupBox* detail_box_; ///< - - QMenu* subkey_opera_menu_{}; ///< - - QLabel* key_type_var_label_; - QLabel* key_size_var_label_; ///< Label containing the keys key size - QLabel* expire_var_label_; ///< Label containing the keys expiration date - QLabel* revoke_var_label_; - QLabel* created_var_label_; ///< Label containing the keys creation date - QLabel* algorithm_var_label_; ///< Label containing the keys algorithm - QLabel* algorithm_detail_var_label_; ///< - QLabel* key_id_var_label_; ///< Label containing the keys keyid - QLabel* fingerprint_var_label_; ///< Label containing the keys fingerprint - QLabel* usage_var_label_; ///< - QLabel* master_key_exist_var_label_; ///< - QLabel* card_key_label_; ///< - - QPushButton* export_subkey_button_; - QAction* export_subkey_act_; - - QAction* edit_subkey_act_; - QAction* delete_subkey_act_; - QAction* revoke_subkey_act_; + void contextMenuEvent(QContextMenuEvent* event) override; private slots: @@ -161,13 +119,55 @@ class KeyPairSubkeyTab : public QWidget { */ void SignalKeyDatabaseRefresh(); - protected: + private: + int current_gpg_context_channel_; + GpgKeyPtr key_; ///< + QTableWidget* subkey_list_{}; ///< + QContainer buffered_subkeys_; ///< + + QGroupBox* list_box_; ///< + QGroupBox* detail_box_; ///< + + QMenu* subkey_opera_menu_{}; ///< + + QLabel* key_type_var_label_; + QLabel* key_size_var_label_; ///< Label containing the keys key size + QLabel* expire_var_label_; ///< Label containing the keys expiration date + QLabel* revoke_var_label_; + QLabel* created_var_label_; ///< Label containing the keys creation date + QLabel* algorithm_var_label_; ///< Label containing the keys algorithm + QLabel* algorithm_detail_var_label_; ///< + QLabel* key_id_var_label_; ///< Label containing the keys keyid + QLabel* fingerprint_var_label_; ///< Label containing the keys fingerprint + QLabel* usage_var_label_; ///< + QLabel* master_key_exist_var_label_; ///< + QLabel* card_key_label_; ///< + + QPushButton* export_subkey_button_; + QAction* export_subkey_act_; + + QAction* edit_subkey_act_; + QAction* delete_subkey_act_; + QAction* revoke_subkey_act_; + /** - * @brief + * @brief Create a subkey list object * - * @param event */ - void contextMenuEvent(QContextMenuEvent* event) override; + void create_subkey_list(); + + /** + * @brief Create a subkey opera menu object + * + */ + void create_subkey_opera_menu(); + + /** + * @brief Get the selected subkey object + * + * @return const GpgSubKey& + */ + auto get_selected_subkey() -> const GpgSubKey&; }; } // namespace GpgFrontend::UI diff --git a/src/ui/main_window/MainWindow.cpp b/src/ui/main_window/MainWindow.cpp index 4b5c71f5..8c8fd55e 100644 --- a/src/ui/main_window/MainWindow.cpp +++ b/src/ui/main_window/MainWindow.cpp @@ -117,19 +117,20 @@ void MainWindow::Init() noexcept { &UISignalStation::SignalMainWindowOpenFile, this, &MainWindow::SlotOpenFile); -#if defined(__linux__) +#if !(defined(_WIN32) || defined(WIN32)) connect(this, &MainWindow::SignalLoaded, this, [=]() { QTimer::singleShot(3000, [self = QPointer(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.")); + self, tr("GUI Pinentry Not Found"), + tr("No suitable *graphical* Pinentry program was found on your " + "system.\n\n" + "Please install a GUI-based Pinentry (e.g., 'pinentry-qt', " + "'pinentry-gnome3', or 'pinentry-mac' on macOS).\n\n" + "Without a GUI Pinentry, GnuPG cannot prompt you for " + "passwords or passphrases.\n\n" + "After installing it, please restart GpgFrontend. The " + "configuration file will be updated automatically.")); } }); }); -- cgit v1.2.3 From 28f82dd7557a2d57d9e5a403ac6b3502ec6af209 Mon Sep 17 00:00:00 2001 From: saturneric Date: Fri, 18 Apr 2025 19:47:58 +0200 Subject: fix: ts file parse error --- resource/lfs/locale/ts/GpgFrontend.de_DE.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resource/lfs/locale/ts/GpgFrontend.de_DE.ts b/resource/lfs/locale/ts/GpgFrontend.de_DE.ts index 500a2af6..a2da439d 100644 --- a/resource/lfs/locale/ts/GpgFrontend.de_DE.ts +++ b/resource/lfs/locale/ts/GpgFrontend.de_DE.ts @@ -4342,7 +4342,7 @@ Without a GUI Pinentry, GnuPG cannot prompt you for passwords or passphrases. After installing it, please restart GpgFrontend. The configuration file will be updated automatically. Es wurde kein geeignetes *grafisches* Pinentry-Programm auf Ihrem System gefunden. -Bitte installieren Sie ein GUI-basiertes Pinentry (z. B. "pinentry-qt", "pinentry-gnome3" oder "pinentry-mac" unter macOS). +Bitte installieren Sie ein GUI-basiertes Pinentry (z.B. "pinentry-qt", "pinentry-gnome3" oder "pinentry-mac" unter macOS). Ohne ein grafisches Pinentry kann GnuPG Sie nicht nach Passwörtern oder Passphrasen fragen. -- cgit v1.2.3 From 2686fade3407d4163caf4234eefb872670a78ab4 Mon Sep 17 00:00:00 2001 From: saturneric Date: Fri, 18 Apr 2025 19:53:20 +0200 Subject: fix: spelling mistake on project config by nightly build --- .github/workflows/testing-nightly.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/testing-nightly.yml b/.github/workflows/testing-nightly.yml index 48345824..d8975bf4 100644 --- a/.github/workflows/testing-nightly.yml +++ b/.github/workflows/testing-nightly.yml @@ -276,7 +276,7 @@ jobs: - name: Build GpgFrontend (Linux) # Build your GpgFrontend with the given configuration run: | - cmake -B ${{github.workspace}}/build -G Ninja -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DDGPGFRONTEND_BUILD_TYPE_ONLY_APPLICATION=ON + cmake -B ${{github.workspace}}/build -G Ninja -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DGPGFRONTEND_BUILD_TYPE_ONLY_APPLICATION=ON cmake --build ${{github.workspace}}/build --config {{$env.BUILD_TYPE}} -- -v if: runner.os == 'Linux' -- cgit v1.2.3