aboutsummaryrefslogtreecommitdiffstats
path: root/src/core/function
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/function')
-rw-r--r--src/core/function/gpg/GpgAdvancedOperator.cpp7
-rw-r--r--src/core/function/gpg/GpgAssuanHelper.cpp24
-rw-r--r--src/core/function/gpg/GpgAssuanHelper.h75
-rw-r--r--src/core/function/gpg/GpgAutomatonHandler.cpp25
-rw-r--r--src/core/function/gpg/GpgAutomatonHandler.h38
-rw-r--r--src/core/function/gpg/GpgCommandExecutor.cpp32
-rw-r--r--src/core/function/gpg/GpgCommandExecutor.h13
-rw-r--r--src/core/function/gpg/GpgContext.cpp4
-rw-r--r--src/core/function/gpg/GpgSmartCardManager.cpp87
-rw-r--r--src/core/function/gpg/GpgSmartCardManager.h74
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