diff options
Diffstat (limited to 'src/core/function')
-rw-r--r-- | src/core/function/gpg/GpgAdvancedOperator.cpp | 7 | ||||
-rw-r--r-- | src/core/function/gpg/GpgAssuanHelper.cpp | 24 | ||||
-rw-r--r-- | src/core/function/gpg/GpgAssuanHelper.h | 75 | ||||
-rw-r--r-- | src/core/function/gpg/GpgAutomatonHandler.cpp | 25 | ||||
-rw-r--r-- | src/core/function/gpg/GpgAutomatonHandler.h | 38 | ||||
-rw-r--r-- | src/core/function/gpg/GpgCommandExecutor.cpp | 32 | ||||
-rw-r--r-- | src/core/function/gpg/GpgCommandExecutor.h | 13 | ||||
-rw-r--r-- | src/core/function/gpg/GpgContext.cpp | 4 | ||||
-rw-r--r-- | src/core/function/gpg/GpgSmartCardManager.cpp | 87 | ||||
-rw-r--r-- | src/core/function/gpg/GpgSmartCardManager.h | 74 |
10 files changed, 355 insertions, 24 deletions
diff --git a/src/core/function/gpg/GpgAdvancedOperator.cpp b/src/core/function/gpg/GpgAdvancedOperator.cpp index 0b103c9b..492297c6 100644 --- a/src/core/function/gpg/GpgAdvancedOperator.cpp +++ b/src/core/function/gpg/GpgAdvancedOperator.cpp @@ -54,13 +54,18 @@ void ExecuteGpgCommand(const QString &operation, const QStringList &extra_args, std::atomic<int> completed_tasks{0}; std::vector<int> 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 = QStringList{"--homedir", target_home_dir}; + QStringList arguments = !target_home_dir.isEmpty() + ? QStringList{"--homedir", target_home_dir} + : QStringList{}; arguments.append(extra_args); GpgCommandExecutor::ExecuteSync( diff --git a/src/core/function/gpg/GpgAssuanHelper.cpp b/src/core/function/gpg/GpgAssuanHelper.cpp index 2351b9a2..8fa311dc 100644 --- a/src/core/function/gpg/GpgAssuanHelper.cpp +++ b/src/core/function/gpg/GpgAssuanHelper.cpp @@ -51,7 +51,7 @@ auto GpgAssuanHelper::ConnectToSocket(GpgComponentType type) -> bool { auto socket_path = ctx_.ComponentDirectory(type); if (socket_path.isEmpty()) { - LOG_F() << "socket path of component: " << component_type_to_q_string(type) + LOG_W() << "socket path of component: " << component_type_to_q_string(type) << " is empty"; return false; } @@ -65,7 +65,7 @@ auto GpgAssuanHelper::ConnectToSocket(GpgComponentType type) -> bool { launch_component(type); if (!info.exists()) { - LOG_F() << "socket path is still not exists: " << socket_path + LOG_W() << "socket path is still not exists: " << socket_path << "abort..."; return false; } @@ -77,17 +77,17 @@ auto GpgAssuanHelper::ConnectToSocket(GpgComponentType type) -> bool { auto err = assuan_socket_connect(a_ctx, info.absoluteFilePath().toUtf8(), ASSUAN_INVALID_PID, 0); if (err != GPG_ERR_NO_ERROR) { - LOG_F() << "failed to connect to socket:" << CheckGpgError(err); + LOG_W() << "failed to connect to socket:" << CheckGpgError(err); return false; } LOG_D() << "connected to socket by assuan protocol: " - << info.absoluteFilePath(); + << info.absoluteFilePath() << "channel:" << GetChannel(); err = assuan_transact(a_ctx, "GETINFO pid", simple_data_callback, nullptr, nullptr, nullptr, nullptr, nullptr); if (err != GPG_ERR_NO_ERROR) { - LOG_F() << "failed to test assuan connection:" << CheckGpgError(err); + LOG_W() << "failed to test assuan connection:" << CheckGpgError(err); return false; } @@ -111,12 +111,19 @@ auto GpgAssuanHelper::SendCommand(GpgComponentType type, const QString& command, context->status_cb = std::move(status_cb); context->inquery_cb = std::move(inquery_cb); + LOG_D() << "sending assuan command: " << command; + auto err = assuan_transact( assuan_ctx_[type], command.toUtf8(), default_data_callback, &context, default_inquery_callback, &context, default_status_callback, &context); if (err != GPG_ERR_NO_ERROR) { - LOG_F() << "failed to send assuan command :" << CheckGpgError(err); + LOG_W() << "failed to send assuan command:" << CheckGpgError(err); + + // broken pipe error, try reconnect next time + if (CheckGpgError(err) == 32877) { + assuan_ctx_.remove(type); + } return false; } @@ -153,7 +160,6 @@ auto GpgAssuanHelper::SendStatusCommand(GpgComponentType type, }; auto ret = SendCommand(type, command, d_cb, i_cb, s_cb); - return {ret, status_lines}; } @@ -185,7 +191,7 @@ auto GpgAssuanHelper::default_inquery_callback( void GpgAssuanHelper::launch_component(GpgComponentType type) { if (gpgconf_path_.isEmpty()) { - LOG_F() << "gpgconf_path is not collected by initializing"; + LOG_W() << "gpgconf_path is not collected by initializing"; return; } @@ -199,7 +205,7 @@ void GpgAssuanHelper::launch_component(GpgComponentType type) { process.start(); if (!process.waitForFinished()) { - LOG_F() << "failed to execute gpgconf" << process.arguments(); + LOG_E() << "failed to execute gpgconf" << process.arguments(); return; } } diff --git a/src/core/function/gpg/GpgAssuanHelper.h b/src/core/function/gpg/GpgAssuanHelper.h index 65ec325f..6e58e27c 100644 --- a/src/core/function/gpg/GpgAssuanHelper.h +++ b/src/core/function/gpg/GpgAssuanHelper.h @@ -62,15 +62,49 @@ class GPGFRONTEND_CORE_EXPORT GpgAssuanHelper [[nodiscard]] auto SendData(const QByteArray& b) const -> gpg_error_t; }; + /** + * @brief Construct a new Gpg Assuan Helper object + * + * @param channel + */ explicit GpgAssuanHelper(int channel); + + /** + * @brief Destroy the Gpg Assuan Helper object + * + */ ~GpgAssuanHelper(); + /** + * @brief + * + * @return true + * @return false + */ auto ConnectToSocket(GpgComponentType) -> bool; + /** + * @brief + * + * @param type + * @param command + * @param data_cb + * @param inquery_cb + * @param status_cb + * @return true + * @return false + */ auto SendCommand(GpgComponentType type, const QString& command, DataCallback data_cb, InqueryCallback inquery_cb, StatusCallback status_cb) -> bool; + /** + * @brief + * + * @param type + * @param command + * @return std::tuple<bool, QStringList> + */ auto SendStatusCommand(GpgComponentType type, const QString& command) -> std::tuple<bool, QStringList>; @@ -79,19 +113,60 @@ class GPGFRONTEND_CORE_EXPORT GpgAssuanHelper GpgContext::GetInstance(SingletonFunctionObject::GetChannel()); QMap<GpgComponentType, assuan_context_t> assuan_ctx_; + /** + * @brief + * + * @param type + */ void launch_component(GpgComponentType type); + /** + * @brief + * + * @param type + * @return QString + */ static auto component_type_to_q_string(GpgComponentType type) -> QString; + /** + * @brief + * + * @param opaque + * @param buffer + * @param length + * @return gpgme_error_t + */ static auto simple_data_callback(void* opaque, const void* buffer, size_t length) -> gpgme_error_t; + /** + * @brief + * + * @param opaque + * @param buffer + * @param length + * @return gpgme_error_t + */ static auto default_data_callback(void* opaque, const void* buffer, size_t length) -> gpgme_error_t; + /** + * @brief + * + * @param opaque + * @param status + * @return gpgme_error_t + */ static auto default_status_callback(void* opaque, const char* status) -> gpgme_error_t; + /** + * @brief + * + * @param opaque + * @param inquery + * @return gpgme_error_t + */ static auto default_inquery_callback(void* opaque, const char* inquery) -> gpgme_error_t; diff --git a/src/core/function/gpg/GpgAutomatonHandler.cpp b/src/core/function/gpg/GpgAutomatonHandler.cpp index 802279ed..af2f0cba 100644 --- a/src/core/function/gpg/GpgAutomatonHandler.cpp +++ b/src/core/function/gpg/GpgAutomatonHandler.cpp @@ -28,6 +28,8 @@ #include "GpgAutomatonHandler.h" +#include <utility> + #include "core/model/GpgData.h" #include "core/model/GpgKey.h" #include "core/utils/GpgUtils.h" @@ -96,21 +98,30 @@ auto GpgAutomatonHandler::interator_cb_func(void* handle, const char* status, auto GpgAutomatonHandler::DoInteract( const GpgKey& key, AutomatonNextStateHandler next_state_handler, - AutomatonActionHandler action_handler) -> bool { - auto key_fpr = key.Fingerprint(); - AutomatonHandelStruct handel_struct(key_fpr); + AutomatonActionHandler action_handler, int flags) -> bool { + gpgme_key_t p_key = + flags == GPGME_INTERACT_CARD ? nullptr : static_cast<gpgme_key_t>(key); + + AutomatonHandelStruct handel_struct( + flags == GPGME_INTERACT_CARD ? "" : key.Fingerprint()); handel_struct.SetHandler(std::move(next_state_handler), std::move(action_handler)); GpgData data_out; - auto err = - gpgme_op_interact(ctx_.DefaultContext(), static_cast<gpgme_key_t>(key), 0, - GpgAutomatonHandler::interator_cb_func, - static_cast<void*>(&handel_struct), data_out); + auto err = gpgme_op_interact(ctx_.DefaultContext(), p_key, flags, + GpgAutomatonHandler::interator_cb_func, + static_cast<void*>(&handel_struct), data_out); return CheckGpgError(err) == GPG_ERR_NO_ERROR && handel_struct.Success(); } +auto GpgAutomatonHandler::DoCardInteract( + AutomatonNextStateHandler next_state_handler, + AutomatonActionHandler action_handler) -> bool { + return DoInteract({}, std::move(next_state_handler), + std::move(action_handler), GPGME_INTERACT_CARD); +} + auto GpgAutomatonHandler::AutomatonHandelStruct::NextState( QString gpg_status, QString args) -> AutomatonState { return next_state_handler_(current_state_, std::move(gpg_status), diff --git a/src/core/function/gpg/GpgAutomatonHandler.h b/src/core/function/gpg/GpgAutomatonHandler.h index 78b20252..f86299e8 100644 --- a/src/core/function/gpg/GpgAutomatonHandler.h +++ b/src/core/function/gpg/GpgAutomatonHandler.h @@ -87,16 +87,46 @@ class GpgAutomatonHandler explicit GpgAutomatonHandler( int channel = SingletonFunctionObject::GetDefaultChannel()); + /** + * @brief + * + * @param key + * @param next_state_handler + * @param action_handler + * @param flags + * @return true + * @return false + */ auto DoInteract(const GpgKey& key, AutomatonNextStateHandler next_state_handler, - AutomatonActionHandler action_handler) -> bool; + AutomatonActionHandler action_handler, int flags = 0) -> bool; - private: - static auto interator_cb_func(void* handle, const char* status, - const char* args, int fd) -> gpgme_error_t; + /** + * @brief + * + * @param next_state_handler + * @param action_handler + * @return true + * @return false + */ + auto DoCardInteract(AutomatonNextStateHandler next_state_handler, + AutomatonActionHandler action_handler) -> bool; + private: GpgContext& ctx_ = GpgContext::GetInstance(SingletonFunctionObject::GetChannel()); ///< + + /** + * @brief + * + * @param handle + * @param status + * @param args + * @param fd + * @return gpgme_error_t + */ + static auto interator_cb_func(void* handle, const char* status, + const char* args, int fd) -> gpgme_error_t; }; using AutomatonNextStateHandler = diff --git a/src/core/function/gpg/GpgCommandExecutor.cpp b/src/core/function/gpg/GpgCommandExecutor.cpp index a4ab8990..191c1259 100644 --- a/src/core/function/gpg/GpgCommandExecutor.cpp +++ b/src/core/function/gpg/GpgCommandExecutor.cpp @@ -31,6 +31,7 @@ #include "core/model/DataObject.h" #include "core/module/Module.h" +#include "core/module/ModuleManager.h" #include "core/thread/Task.h" #include "core/thread/TaskRunnerGetter.h" @@ -234,4 +235,35 @@ GpgCommandExecutor::ExecuteContext::ExecuteContext( int_func(std::move(int_func)), task_runner(std::move(task_runner)) {} +GpgCommandExecutor::GpgCommandExecutor(int channel) + : GpgFrontend::SingletonFunctionObject<GpgCommandExecutor>(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()) { + LOG_E() << "failed to execute gpg command, gpg binary path is empty."; + return; + } + + LOG_D() << "got gpg binary path:" << gpg_path; + LOG_D() << "context channel:" << GetChannel() + << "home path: " << ctx_.HomeDirectory(); + + ExecuteContext ctx = { + context.cmd.isEmpty() ? gpg_path : context.cmd, + context.arguments, + context.cb_func, + context.task_runner, + context.int_func, + }; + + if (!ctx.arguments.contains("--homedir") && !ctx_.HomeDirectory().isEmpty()) { + ctx.arguments.append("--homedir"); + ctx.arguments.append(ctx_.HomeDirectory()); + } + + return ExecuteSync(ctx); +} } // 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 5a2f13db..fd2181d3 100644 --- a/src/core/function/gpg/GpgCommandExecutor.h +++ b/src/core/function/gpg/GpgCommandExecutor.h @@ -28,6 +28,8 @@ #pragma once +#include "core/function/basic/GpgFunctionObject.h" +#include "core/function/gpg/GpgContext.h" #include "core/module/Module.h" namespace GpgFrontend { @@ -39,7 +41,8 @@ using GpgCommandExecutorInterator = std::function<void(QProcess *)>; * @brief Extra commands related to GPG * */ -class GPGFRONTEND_CORE_EXPORT GpgCommandExecutor { +class GPGFRONTEND_CORE_EXPORT GpgCommandExecutor + : public SingletonFunctionObject<GpgCommandExecutor> { public: struct GPGFRONTEND_CORE_EXPORT ExecuteContext { QString cmd; @@ -58,6 +61,8 @@ class GPGFRONTEND_CORE_EXPORT GpgCommandExecutor { using ExecuteContexts = QContainer<ExecuteContext>; + explicit GpgCommandExecutor(int channel = kGpgFrontendDefaultChannel); + /** * @brief Excuting a command * @@ -69,6 +74,12 @@ class GPGFRONTEND_CORE_EXPORT GpgCommandExecutor { static void ExecuteConcurrentlyAsync(ExecuteContexts); static void ExecuteConcurrentlySync(ExecuteContexts); + + void GpgExecuteSync(const ExecuteContext &); + + private: + GpgContext &ctx_ = + GpgContext::GetInstance(SingletonFunctionObject::GetChannel()); }; } // namespace GpgFrontend diff --git a/src/core/function/gpg/GpgContext.cpp b/src/core/function/gpg/GpgContext.cpp index ce84ed2e..88eb3c1b 100644 --- a/src/core/function/gpg/GpgContext.cpp +++ b/src/core/function/gpg/GpgContext.cpp @@ -386,11 +386,11 @@ class GpgContext::Impl { QProcess process; process.setProgram(gpgconf_path); - process.setArguments({"--list-dirs"}); + process.setArguments({"--list-dirs", "--homedir", database_path_}); process.start(); if (!process.waitForFinished()) { - LOG_F() << "failed to execute gpgconf --list-dirs"; + LOG_W() << "failed to execute gpgconf --list-dirs"; return; } diff --git a/src/core/function/gpg/GpgSmartCardManager.cpp b/src/core/function/gpg/GpgSmartCardManager.cpp new file mode 100644 index 00000000..06010756 --- /dev/null +++ b/src/core/function/gpg/GpgSmartCardManager.cpp @@ -0,0 +1,87 @@ +/** + * Copyright (C) 2021-2024 Saturneric <[email protected]> + * + * 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 <https://www.gnu.org/licenses/>. + * + * 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 <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "GpgSmartCardManager.h" + +#include "core/function/gpg/GpgAutomatonHandler.h" + +namespace GpgFrontend { + +GpgSmartCardManager::GpgSmartCardManager(int channel) + : SingletonFunctionObject<GpgSmartCardManager>(channel) {} + +auto GpgSmartCardManager::Fetch(const QString& serial_number) -> bool { + GpgAutomatonHandler::AutomatonNextStateHandler next_state_handler = + [=](AutomatonState state, QString status, QString args) { + auto tokens = args.split(' '); + + switch (state) { + case GpgAutomatonHandler::AS_START: + if (status == "CARDCTRL" && args.contains(serial_number)) { + return GpgAutomatonHandler::AS_START; + } else if (status == "GET_LINE" && args == "cardedit.prompt") { + return GpgAutomatonHandler::AS_COMMAND; + } + return GpgAutomatonHandler::AS_ERROR; + case GpgAutomatonHandler::AS_COMMAND: + if (status == "GET_LINE" && args == "cardedit.prompt") { + return GpgAutomatonHandler::AS_QUIT; + } + return GpgAutomatonHandler::AS_ERROR; + case GpgAutomatonHandler::AS_QUIT: + case GpgAutomatonHandler::AS_ERROR: + if (status == "GET_LINE" && args == "keyedit.prompt") { + return GpgAutomatonHandler::AS_QUIT; + } + return GpgAutomatonHandler::AS_ERROR; + default: + return GpgAutomatonHandler::AS_ERROR; + }; + }; + + AutomatonActionHandler action_handler = [](AutomatonHandelStruct& handler, + AutomatonState state) { + switch (state) { + case GpgAutomatonHandler::AS_COMMAND: + return QString("fetch"); + case GpgAutomatonHandler::AS_QUIT: + return QString("quit"); + case GpgAutomatonHandler::AS_START: + case GpgAutomatonHandler::AS_ERROR: + return QString(""); + default: + return QString(""); + } + return QString(""); + }; + + return GpgAutomatonHandler::GetInstance(GetChannel()) + .DoCardInteract(next_state_handler, action_handler); +} + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/function/gpg/GpgSmartCardManager.h b/src/core/function/gpg/GpgSmartCardManager.h new file mode 100644 index 00000000..9c8cc8bb --- /dev/null +++ b/src/core/function/gpg/GpgSmartCardManager.h @@ -0,0 +1,74 @@ +/** + * Copyright (C) 2021-2024 Saturneric <[email protected]> + * + * 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 <https://www.gnu.org/licenses/>. + * + * 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 <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +#include "core/function/basic/GpgFunctionObject.h" +#include "core/function/gpg/GpgContext.h" +#include "core/typedef/GpgTypedef.h" + +namespace GpgFrontend { + +/** + * @brief + * + */ +class GPGFRONTEND_CORE_EXPORT GpgSmartCardManager + : public SingletonFunctionObject<GpgSmartCardManager> { + public: + /** + * @brief Construct a new Gpg Key Manager object + * + * @param channel + */ + explicit GpgSmartCardManager( + int channel = SingletonFunctionObject::GetDefaultChannel()); + + /** + * @brief + * + * @param key + * @param subkey_index + * @return true + * @return false + */ + auto Fetch(const QString& serial_number) -> bool; + + /** + * @brief + * + * @return std::tuple<bool, QString> + */ + auto ModifyAttr() -> std::tuple<bool, QString>; + + private: + GpgContext& ctx_ = + GpgContext::GetInstance(SingletonFunctionObject::GetChannel()); ///< +}; + +} // namespace GpgFrontend |