diff options
Diffstat (limited to 'src/core/function/gpg')
20 files changed, 2182 insertions, 1681 deletions
diff --git a/src/core/function/gpg/GpgAdvancedOperator.cpp b/src/core/function/gpg/GpgAdvancedOperator.cpp index 2a3bba42..8b60003c 100644 --- a/src/core/function/gpg/GpgAdvancedOperator.cpp +++ b/src/core/function/gpg/GpgAdvancedOperator.cpp @@ -1,7 +1,7 @@ -/* - * Copyright (c) 2023. Saturneric +/** + * Copyright (C) 2021 Saturneric <[email protected]> * - * This file is part of GpgFrontend. + * 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 @@ -20,9 +20,10 @@ * 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. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later + * */ // @@ -32,152 +33,189 @@ #include "GpgAdvancedOperator.h" #include "core/function/gpg/GpgCommandExecutor.h" -#include "spdlog/spdlog.h" - -GpgFrontend::GpgAdvancedOperator::GpgAdvancedOperator(int channel) - : SingletonFunctionObject(channel) {} - -bool GpgFrontend::GpgAdvancedOperator::ClearGpgPasswordCache() { - bool success = false; - GpgFrontend::GpgCommandExecutor::GetInstance().Execute( - ctx_.GetInfo().GpgConfPath, {"--reload", "gpg-agent"}, - [&](int exit_code, const std::string &p_out, const std::string &p_err) { - if (exit_code == 0) { - SPDLOG_DEBUG("gpgconf reload exit code: {}", exit_code); - success = true; - } - }); - return success; +#include "core/module/ModuleManager.h" + +void GpgFrontend::GpgAdvancedOperator::ClearGpgPasswordCache( + OperationCallback cb) { + const auto gpgconf_path = Module::RetrieveRTValueTypedOrDefault<>( + "core", "gpgme.ctx.gpgconf_path", QString{}); + GF_CORE_LOG_DEBUG("got gpgconf path from rt: {}", gpgconf_path); + + if (gpgconf_path.isEmpty()) { + GF_CORE_LOG_ERROR("cannot get valid gpgconf path from rt, abort."); + cb(-1, TransferParams()); + return; + } + + GpgFrontend::GpgCommandExecutor::ExecuteSync( + {gpgconf_path, + {"--reload", "gpg-agent"}, + [=](int exit_code, const QString & /*p_out*/, + const QString & /*p_err*/) { + GF_CORE_LOG_DEBUG("gpgconf reload exit code: {}", exit_code); + cb(exit_code == 0 ? 0 : -1, TransferParams()); + }}); } -bool GpgFrontend::GpgAdvancedOperator::ReloadGpgComponents() { - bool success = false; - GpgFrontend::GpgCommandExecutor::GetInstance().Execute( - ctx_.GetInfo().GpgConfPath, {"--reload"}, - [&](int exit_code, const std::string &p_out, const std::string &p_err) { - if (exit_code == 0) { - success = true; - } else { - SPDLOG_ERROR( - "gpgconf execute error, process stderr: {}, process stdout: {}", - p_err, p_out); - return; - } - }); - return success; +void GpgFrontend::GpgAdvancedOperator::ReloadGpgComponents( + OperationCallback cb) { + const auto gpgconf_path = Module::RetrieveRTValueTypedOrDefault<>( + "core", "gpgme.ctx.gpgconf_path", QString{}); + GF_CORE_LOG_DEBUG("got gpgconf path from rt: {}", gpgconf_path); + + if (gpgconf_path.isEmpty()) { + GF_CORE_LOG_ERROR("cannot get valid gpgconf path from rt, abort."); + cb(-1, TransferParams()); + return; + } + + GpgFrontend::GpgCommandExecutor::ExecuteSync( + {gpgconf_path, + {"--reload"}, + [=](int exit_code, const QString &, const QString &) { + GF_CORE_LOG_DEBUG("gpgconf reload exit code: {}", exit_code); + cb(exit_code == 0 ? 0 : -1, TransferParams()); + }}); } -bool GpgFrontend::GpgAdvancedOperator::RestartGpgComponents() { - bool success = false; - - GpgFrontend::GpgCommandExecutor::GetInstance().Execute( - ctx_.GetInfo().GpgConfPath, {"--verbose", "--kill", "all"}, - [&](int exit_code, const std::string &p_out, const std::string &p_err) { - if (exit_code == 0) { - success = true; - return; - } else { - SPDLOG_ERROR( - "gpgconf execute error, process stderr: {}, process stdout: {}", - p_err, p_out); - return; - } - }); - - if (!success) return false; - - success &= StartGpgAgent(); - - success &= StartDirmngr(); - - success &= StartKeyBoxd(); - - return success; +void GpgFrontend::GpgAdvancedOperator::RestartGpgComponents() { + const auto gpgconf_path = Module::RetrieveRTValueTypedOrDefault<>( + "core", "gpgme.ctx.gpgconf_path", QString{}); + GF_CORE_LOG_DEBUG("got gpgconf path from rt: {}", gpgconf_path); + + if (gpgconf_path.isEmpty()) { + GF_CORE_LOG_ERROR("cannot get valid gpgconf path from rt, abort."); + return; + } + + GpgFrontend::GpgCommandExecutor::ExecuteSync( + {gpgconf_path, + {"--verbose", "--kill", "all"}, + [=](int exit_code, const QString &p_out, const QString &p_err) { + GF_CORE_LOG_DEBUG("gpgconf --kill all command got exit code: {}", + exit_code); + bool success = true; + if (exit_code != 0) { + success = false; + GF_CORE_LOG_ERROR( + "gpgconf execute error, process stderr: {}, process stdout: {}", + p_err, p_out); + return; + } + + GF_CORE_LOG_DEBUG("gpgconf --kill --all execute result: {}", success); + if (!success) { + GF_CORE_LOG_ERROR( + "restart all component after core initilized failed"); + Module::UpsertRTValue( + "core", "gpg_advanced_operator.restart_gpg_components", false); + return; + } + + StartGpgAgent([](int err, DataObjectPtr) { + if (err >= 0) { + Module::UpsertRTValue( + "core", "gpg_advanced_operator.restart_gpg_components", true); + return; + } + }); + }}); } -bool GpgFrontend::GpgAdvancedOperator::ResetConfigures() { - bool success = false; - GpgFrontend::GpgCommandExecutor::GetInstance().Execute( - ctx_.GetInfo().GpgConfPath, {"--apply-defaults"}, - [&](int exit_code, const std::string &p_out, const std::string &p_err) { - if (exit_code == 0) { - success = true; - } else { - SPDLOG_ERROR( - "gpgconf execute error, process stderr: {}, process stdout: {}", - p_err, p_out); - return; - } - }); - - return success; +void GpgFrontend::GpgAdvancedOperator::ResetConfigures(OperationCallback cb) { + const auto gpgconf_path = Module::RetrieveRTValueTypedOrDefault<>( + "core", "gpgme.ctx.gpgconf_path", QString{}); + GF_CORE_LOG_DEBUG("got gpgconf path from rt: {}", gpgconf_path); + + if (gpgconf_path.isEmpty()) { + GF_CORE_LOG_ERROR("cannot get valid gpgconf path from rt, abort."); + cb(-1, TransferParams()); + return; + } + + GpgFrontend::GpgCommandExecutor::ExecuteSync( + {gpgconf_path, + {"--apply-defaults"}, + [=](int exit_code, const QString &, const QString &) { + GF_CORE_LOG_DEBUG("gpgconf apply-defaults exit code: {}", exit_code); + cb(exit_code == 0 ? 0 : -1, TransferParams()); + }}); } -bool GpgFrontend::GpgAdvancedOperator::StartGpgAgent() { - bool success = false; - GpgFrontend::GpgCommandExecutor::GetInstance().Execute( - ctx_.GetInfo().GpgAgentPath, - {"--homedir", ctx_.GetInfo().GnuPGHomePath, "--daemon"}, - [&](int exit_code, const std::string &p_out, const std::string &p_err) { - if (exit_code == 0) { - success = true; - SPDLOG_INFO("start gpg-agent successfully"); - } else if (exit_code == 2) { - success = true; - SPDLOG_INFO("gpg-agent already started"); - } else { - SPDLOG_ERROR( - "gpg-agent execute error, process stderr: {}, process stdout: {}", - p_err, p_out); - return; - } - }); - - return success; +void GpgFrontend::GpgAdvancedOperator::StartGpgAgent(OperationCallback cb) { + const auto gpg_agent_path = Module::RetrieveRTValueTypedOrDefault<>( + "com.bktus.gpgfrontend.module.integrated.gnupg-info-gathering", + "gnupg.gpg_agent_path", QString{}); + GF_CORE_LOG_DEBUG("got gnupg agent path from rt: {}", gpg_agent_path); + + const auto home_path = Module::RetrieveRTValueTypedOrDefault<>( + "com.bktus.gpgfrontend.module.integrated.gnupg-info-gathering", + "gnupg.home_path", QString{}); + GF_CORE_LOG_DEBUG("got gnupg home path from rt: {}", home_path); + + if (gpg_agent_path.isEmpty()) { + GF_CORE_LOG_ERROR("cannot get valid gpg agent path from rt, abort."); + cb(-1, TransferParams()); + return; + } + + GpgFrontend::GpgCommandExecutor::ExecuteSync( + {gpg_agent_path, + {"--homedir", home_path, "--daemon"}, + [=](int exit_code, const QString &, const QString &) { + GF_CORE_LOG_DEBUG("gpgconf daemon exit code: {}", exit_code); + cb(exit_code >= 0 ? 0 : -1, TransferParams()); + }}); } -bool GpgFrontend::GpgAdvancedOperator::StartDirmngr() { - bool success = false; - GpgFrontend::GpgCommandExecutor::GetInstance().Execute( - ctx_.GetInfo().DirmngrPath, - {"--homedir", ctx_.GetInfo().GnuPGHomePath, "--daemon"}, - [&](int exit_code, const std::string &p_out, const std::string &p_err) { - if (exit_code == 0) { - success = true; - SPDLOG_INFO("start dirmngr successfully"); - } else if (exit_code == 2) { - success = true; - SPDLOG_INFO("dirmngr already started"); - } else { - SPDLOG_ERROR( - "dirmngr execute error, process stderr: {}, process stdout: {}", - p_err, p_out); - return; - } - }); - - return success; +void GpgFrontend::GpgAdvancedOperator::StartDirmngr(OperationCallback cb) { + const auto dirmngr_path = Module::RetrieveRTValueTypedOrDefault<>( + "com.bktus.gpgfrontend.module.integrated.gnupg-info-gathering", + "gnupg.dirmngr_path", QString{}); + GF_CORE_LOG_DEBUG("got gnupg dirmngr path from rt: {}", dirmngr_path); + + const auto home_path = Module::RetrieveRTValueTypedOrDefault<>( + "com.bktus.gpgfrontend.module.integrated.gnupg-info-gathering", + "gnupg.home_path", QString{}); + GF_CORE_LOG_DEBUG("got gnupg home path from rt: {}", home_path); + + if (dirmngr_path.isEmpty()) { + GF_CORE_LOG_ERROR("cannot get valid dirmngr path from rt, abort."); + cb(-1, TransferParams()); + return; + } + + GpgFrontend::GpgCommandExecutor::ExecuteSync( + {dirmngr_path, + {"--homedir", home_path, "--daemon"}, + [=](int exit_code, const QString &, const QString &) { + GF_CORE_LOG_DEBUG("gpgconf daemon exit code: {}", exit_code); + cb(exit_code >= 0 ? 0 : -1, TransferParams()); + }}); } -bool GpgFrontend::GpgAdvancedOperator::StartKeyBoxd() { - bool success = false; - GpgFrontend::GpgCommandExecutor::GetInstance().Execute( - ctx_.GetInfo().KeyboxdPath, - {"--homedir", ctx_.GetInfo().GnuPGHomePath, "--daemon"}, - [&](int exit_code, const std::string &p_out, const std::string &p_err) { - if (exit_code == 0) { - success = true; - SPDLOG_INFO("start keyboxd successfully"); - } else if (exit_code == 2) { - success = true; - SPDLOG_INFO("keyboxd already started"); - } else { - SPDLOG_ERROR( - "keyboxd execute error, process stderr: {}, process stdout: {}", - p_err, p_out); - return; - } - }); - - return success; +void GpgFrontend::GpgAdvancedOperator::StartKeyBoxd(OperationCallback cb) { + const auto keyboxd_path = Module::RetrieveRTValueTypedOrDefault<>( + "com.bktus.gpgfrontend.module.integrated.gnupg-info-gathering", + "gnupg.keyboxd_path", QString{}); + GF_CORE_LOG_DEBUG("got gnupg keyboxd path from rt: {}", keyboxd_path); + + const auto home_path = Module::RetrieveRTValueTypedOrDefault<>( + "com.bktus.gpgfrontend.module.integrated.gnupg-info-gathering", + "gnupg.home_path", QString{}); + GF_CORE_LOG_DEBUG("got gnupg home path from rt: {}", home_path); + + if (keyboxd_path.isEmpty()) { + GF_CORE_LOG_ERROR("cannot get valid keyboxd path from rt, abort."); + cb(-1, TransferParams()); + return; + } + + GpgFrontend::GpgCommandExecutor::ExecuteSync( + {keyboxd_path, + {"--homedir", home_path, "--daemon"}, + [=](int exit_code, const QString &, const QString &) { + GF_CORE_LOG_DEBUG("gpgconf daemon exit code: {}", exit_code); + cb(exit_code >= 0 ? 0 : -1, TransferParams()); + }}); } diff --git a/src/core/function/gpg/GpgAdvancedOperator.h b/src/core/function/gpg/GpgAdvancedOperator.h index 5325020a..d6b57095 100644 --- a/src/core/function/gpg/GpgAdvancedOperator.h +++ b/src/core/function/gpg/GpgAdvancedOperator.h @@ -1,7 +1,7 @@ -/* - * Copyright (c) 2023. Saturneric +/** + * Copyright (C) 2021 Saturneric <[email protected]> * - * This file is part of GpgFrontend. + * 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 @@ -20,42 +20,31 @@ * 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. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later + * */ // // Created by eric on 07.01.2023. // -#ifndef GPGFRONTEND_GPGADVANCEDOPERATOR_H -#define GPGFRONTEND_GPGADVANCEDOPERATOR_H +#pragma once -#include "core/GpgConstants.h" -#include "core/GpgContext.h" -#include "core/GpgFunctionObject.h" +#include "core/typedef/CoreTypedef.h" namespace GpgFrontend { -class GPGFRONTEND_CORE_EXPORT GpgAdvancedOperator - : public SingletonFunctionObject<GpgAdvancedOperator> { +class GPGFRONTEND_CORE_EXPORT GpgAdvancedOperator { public: /** - * @brief Construct a new Basic Operator object - * - * @param channel Channel corresponding to the context - */ - explicit GpgAdvancedOperator( - int channel = SingletonFunctionObject::GetDefaultChannel()); - - /** * @brief * * @return true * @return false */ - bool ClearGpgPasswordCache(); + static void ClearGpgPasswordCache(OperationCallback); /** * @brief @@ -63,7 +52,7 @@ class GPGFRONTEND_CORE_EXPORT GpgAdvancedOperator * @return true * @return false */ - bool ReloadGpgComponents(); + static void ReloadGpgComponents(OperationCallback); /** * @brief @@ -71,7 +60,7 @@ class GPGFRONTEND_CORE_EXPORT GpgAdvancedOperator * @return true * @return false */ - bool RestartGpgComponents(); + static void RestartGpgComponents(); /** * @brief @@ -79,7 +68,7 @@ class GPGFRONTEND_CORE_EXPORT GpgAdvancedOperator * @return true * @return false */ - bool ResetConfigures(); + static void ResetConfigures(OperationCallback); /** * @brief @@ -87,7 +76,7 @@ class GPGFRONTEND_CORE_EXPORT GpgAdvancedOperator * @return true * @return false */ - bool StartGpgAgent(); + static void StartGpgAgent(OperationCallback); /** * @brief @@ -95,7 +84,7 @@ class GPGFRONTEND_CORE_EXPORT GpgAdvancedOperator * @return true * @return false */ - bool StartDirmngr(); + static void StartDirmngr(OperationCallback); /** * @brief @@ -103,13 +92,7 @@ class GPGFRONTEND_CORE_EXPORT GpgAdvancedOperator * @return true * @return false */ - bool StartKeyBoxd(); - - private: - GpgContext& ctx_ = GpgContext::GetInstance( - SingletonFunctionObject::GetChannel()); ///< Corresponding context + static void StartKeyBoxd(OperationCallback); }; } // namespace GpgFrontend - -#endif // GPGFRONTEND_GPGADVANCEDOPERATOR_H diff --git a/src/core/function/gpg/GpgBasicOperator.cpp b/src/core/function/gpg/GpgBasicOperator.cpp index 71f84907..e5916c77 100644 --- a/src/core/function/gpg/GpgBasicOperator.cpp +++ b/src/core/function/gpg/GpgBasicOperator.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,7 +20,7 @@ * 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. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * @@ -28,195 +28,213 @@ #include "GpgBasicOperator.h" -#include <vector> +#include <gpg-error.h> -#include "GpgKeyGetter.h" +#include "core/GpgModel.h" +#include "core/model/GpgDecryptResult.h" +#include "core/model/GpgEncryptResult.h" +#include "core/model/GpgSignResult.h" +#include "core/model/GpgVerifyResult.h" +#include "core/utils/AsyncUtils.h" +#include "core/utils/GpgUtils.h" -GpgFrontend::GpgBasicOperator::GpgBasicOperator(int channel) - : SingletonFunctionObject<GpgBasicOperator>(channel) {} - -GpgFrontend::GpgError GpgFrontend::GpgBasicOperator::Encrypt( - KeyListPtr keys, GpgFrontend::BypeArrayRef in_buffer, - GpgFrontend::ByteArrayPtr& out_buffer, GpgFrontend::GpgEncrResult& result) { - // gpgme_encrypt_result_t e_result; - gpgme_key_t recipients[keys->size() + 1]; +namespace GpgFrontend { - int index = 0; - for (const auto& key : *keys) recipients[index++] = gpgme_key_t(key); +GpgBasicOperator::GpgBasicOperator(int channel) + : SingletonFunctionObject<GpgBasicOperator>(channel) {} - // Last entry data_in array has to be nullptr - recipients[keys->size()] = nullptr; +void GpgBasicOperator::Encrypt(KeyArgsList keys, GFBuffer in_buffer, bool ascii, + const GpgOperationCallback& cb) { + RunGpgOperaAsync([=](const DataObjectPtr& data_object) -> GpgError { + if (keys.empty()) return GPG_ERR_CANCELED; - GpgData data_in(in_buffer.data(), in_buffer.size()), data_out; + std::vector<gpgme_key_t> recipients(keys.begin(), keys.end()); - gpgme_error_t err = check_gpg_error(gpgme_op_encrypt( - ctx_, recipients, GPGME_ENCRYPT_ALWAYS_TRUST, data_in, data_out)); + // Last entry data_in array has to be nullptr + recipients.emplace_back(nullptr); - auto temp_data_out = data_out.Read2Buffer(); - std::swap(temp_data_out, out_buffer); + GpgData data_in(in_buffer); + GpgData data_out; - auto temp_result = _new_result(gpgme_op_encrypt_result(ctx_)); - std::swap(result, temp_result); + auto* ctx = ascii ? ctx_.DefaultContext() : ctx_.BinaryContext(); + auto err = CheckGpgError(gpgme_op_encrypt(ctx, recipients.data(), + GPGME_ENCRYPT_ALWAYS_TRUST, + data_in, data_out)); + data_object->Swap({GpgEncryptResult(gpgme_op_encrypt_result(ctx)), + data_out.Read2GFBuffer()}); - return err; + return err; + }, + cb, "gpgme_op_encrypt", "2.1.0"); } -GpgFrontend::GpgError GpgFrontend::GpgBasicOperator::Decrypt( - BypeArrayRef in_buffer, GpgFrontend::ByteArrayPtr& out_buffer, - GpgFrontend::GpgDecrResult& result) { - gpgme_error_t err; - - GpgData data_in(in_buffer.data(), in_buffer.size()), data_out; - err = check_gpg_error(gpgme_op_decrypt(ctx_, data_in, data_out)); - - auto temp_data_out = data_out.Read2Buffer(); - std::swap(temp_data_out, out_buffer); - - auto temp_result = _new_result(gpgme_op_decrypt_result(ctx_)); - std::swap(result, temp_result); - - return err; +void GpgBasicOperator::Decrypt(GFBuffer in_buffer, + const GpgOperationCallback& cb) { + RunGpgOperaAsync( + [=](const DataObjectPtr& data_object) -> GpgError { + GpgData data_in(in_buffer); + GpgData data_out; + + auto err = CheckGpgError( + gpgme_op_decrypt(ctx_.DefaultContext(), data_in, data_out)); + data_object->Swap( + {GpgDecryptResult(gpgme_op_decrypt_result(ctx_.DefaultContext())), + data_out.Read2GFBuffer()}); + + return err; + }, + cb, "gpgme_op_decrypt", "2.1.0"); } -GpgFrontend::GpgError GpgFrontend::GpgBasicOperator::Verify( - BypeArrayRef& in_buffer, ByteArrayPtr& sig_buffer, - GpgVerifyResult& result) const { - gpgme_error_t err; - - GpgData data_in(in_buffer.data(), in_buffer.size()); - GpgData data_out; - - if (sig_buffer != nullptr && sig_buffer->size() > 0) { - GpgData sig_data(sig_buffer->data(), sig_buffer->size()); - err = check_gpg_error(gpgme_op_verify(ctx_, sig_data, data_in, nullptr)); - } else - err = check_gpg_error(gpgme_op_verify(ctx_, data_in, nullptr, data_out)); - - auto temp_result = _new_result(gpgme_op_verify_result(ctx_)); - std::swap(result, temp_result); - - return err; +void GpgBasicOperator::Verify(GFBuffer in_buffer, GFBuffer sig_buffer, + const GpgOperationCallback& cb) { + RunGpgOperaAsync( + [=](const DataObjectPtr& data_object) -> GpgError { + GpgError err; + + GpgData data_in(in_buffer); + GpgData data_out; + + if (!sig_buffer.Empty()) { + GpgData sig_data(sig_buffer); + err = CheckGpgError(gpgme_op_verify(ctx_.DefaultContext(), sig_data, + data_in, nullptr)); + } else { + err = CheckGpgError(gpgme_op_verify(ctx_.DefaultContext(), data_in, + nullptr, data_out)); + } + + data_object->Swap({ + GpgVerifyResult(gpgme_op_verify_result(ctx_.DefaultContext())), + }); + + return err; + }, + cb, "gpgme_op_verify", "2.1.0"); } -GpgFrontend::GpgError GpgFrontend::GpgBasicOperator::Sign( - KeyListPtr signers, BypeArrayRef in_buffer, ByteArrayPtr& out_buffer, - gpgme_sig_mode_t mode, GpgSignResult& result) { - gpgme_error_t err; - - // Set Singers of this opera - SetSigners(*signers); +void GpgBasicOperator::Sign(KeyArgsList signers, GFBuffer in_buffer, + GpgSignMode mode, bool ascii, + const GpgOperationCallback& cb) { + RunGpgOperaAsync( + [=](const DataObjectPtr& data_object) -> GpgError { + if (signers.empty()) return GPG_ERR_CANCELED; - GpgData data_in(in_buffer.data(), in_buffer.size()), data_out; + GpgError err; - err = check_gpg_error(gpgme_op_sign(ctx_, data_in, data_out, mode)); + // Set Singers of this opera + SetSigners(signers, ascii); - auto temp_data_out = data_out.Read2Buffer(); - std::swap(temp_data_out, out_buffer); + GpgData data_in(in_buffer); + GpgData data_out; - auto temp_result = _new_result(gpgme_op_sign_result(ctx_)); + auto* ctx = ascii ? ctx_.DefaultContext() : ctx_.BinaryContext(); + err = CheckGpgError(gpgme_op_sign(ctx, data_in, data_out, mode)); - std::swap(result, temp_result); - - return err; + data_object->Swap({GpgSignResult(gpgme_op_sign_result(ctx)), + data_out.Read2GFBuffer()}); + return err; + }, + cb, "gpgme_op_sign", "2.1.0"); } -gpgme_error_t GpgFrontend::GpgBasicOperator::DecryptVerify( - BypeArrayRef in_buffer, ByteArrayPtr& out_buffer, - GpgDecrResult& decrypt_result, GpgVerifyResult& verify_result) { - gpgme_error_t err; - - GpgData data_in(in_buffer.data(), in_buffer.size()), data_out; - - err = check_gpg_error(gpgme_op_decrypt_verify(ctx_, data_in, data_out)); +void GpgBasicOperator::DecryptVerify(GFBuffer in_buffer, + const GpgOperationCallback& cb) { + RunGpgOperaAsync( + [=](const DataObjectPtr& data_object) -> GpgError { + GpgError err; - auto temp_data_out = data_out.Read2Buffer(); - std::swap(temp_data_out, out_buffer); + GpgData data_in(in_buffer); + GpgData data_out; - auto temp_decr_result = _new_result(gpgme_op_decrypt_result(ctx_)); - std::swap(decrypt_result, temp_decr_result); + err = CheckGpgError( + gpgme_op_decrypt_verify(ctx_.DefaultContext(), data_in, data_out)); - auto temp_verify_result = _new_result(gpgme_op_verify_result(ctx_)); - std::swap(verify_result, temp_verify_result); + data_object->Swap( + {GpgDecryptResult(gpgme_op_decrypt_result(ctx_.DefaultContext())), + GpgVerifyResult(gpgme_op_verify_result(ctx_.DefaultContext())), + data_out.Read2GFBuffer()}); - return err; + return err; + }, + cb, "gpgme_op_decrypt_verify", "2.1.0"); } -gpgme_error_t GpgFrontend::GpgBasicOperator::EncryptSign( - KeyListPtr keys, KeyListPtr signers, BypeArrayRef in_buffer, - ByteArrayPtr& out_buffer, GpgEncrResult& encr_result, - GpgSignResult& sign_result) { - gpgme_error_t err; - SetSigners(*signers); +void GpgBasicOperator::EncryptSign(KeyArgsList keys, KeyArgsList signers, + GFBuffer in_buffer, bool ascii, + const GpgOperationCallback& cb) { + RunGpgOperaAsync( + [=](const DataObjectPtr& data_object) -> GpgError { + if (keys.empty() || signers.empty()) return GPG_ERR_CANCELED; - // gpgme_encrypt_result_t e_result; - gpgme_key_t recipients[keys->size() + 1]; + GpgError err; + std::vector<gpgme_key_t> recipients(keys.begin(), keys.end()); - // set key for user - int index = 0; - for (const auto& key : *keys) recipients[index++] = gpgme_key_t(key); + // Last entry data_in array has to be nullptr + recipients.emplace_back(nullptr); - // Last entry dataIn array has to be nullptr - recipients[keys->size()] = nullptr; + SetSigners(signers, ascii); - GpgData data_in(in_buffer.data(), in_buffer.size()), data_out; + GpgData data_in(in_buffer); + GpgData data_out; - // If the last parameter isnt 0, a private copy of data is made - err = check_gpg_error(gpgme_op_encrypt_sign( - ctx_, recipients, GPGME_ENCRYPT_ALWAYS_TRUST, data_in, data_out)); + auto* ctx = ascii ? ctx_.DefaultContext() : ctx_.BinaryContext(); + err = CheckGpgError(gpgme_op_encrypt_sign(ctx, recipients.data(), + GPGME_ENCRYPT_ALWAYS_TRUST, + data_in, data_out)); - auto temp_data_out = data_out.Read2Buffer(); - std::swap(temp_data_out, out_buffer); + data_object->Swap({GpgEncryptResult(gpgme_op_encrypt_result(ctx)), + GpgSignResult(gpgme_op_sign_result(ctx)), + data_out.Read2GFBuffer()}); + return err; + }, + cb, "gpgme_op_encrypt_sign", "2.1.0"); +} - auto temp_encr_result = _new_result(gpgme_op_encrypt_result(ctx_)); - swap(encr_result, temp_encr_result); - auto temp_sign_result = _new_result(gpgme_op_sign_result(ctx_)); - swap(sign_result, temp_sign_result); +void GpgBasicOperator::SetSigners(const KeyArgsList& signers, bool ascii) { + auto* ctx = ascii ? ctx_.DefaultContext() : ctx_.BinaryContext(); - return err; -} + gpgme_signers_clear(ctx); -void GpgFrontend::GpgBasicOperator::SetSigners(KeyArgsList& signers) { - gpgme_signers_clear(ctx_); for (const GpgKey& key : signers) { - SPDLOG_DEBUG("key fpr: {}", key.GetFingerprint()); + GF_CORE_LOG_DEBUG("key fpr: {}", key.GetFingerprint()); if (key.IsHasActualSigningCapability()) { - SPDLOG_DEBUG("signer"); - auto error = gpgme_signers_add(ctx_, gpgme_key_t(key)); - check_gpg_error(error); + GF_CORE_LOG_DEBUG("signer"); + auto error = gpgme_signers_add(ctx, gpgme_key_t(key)); + CheckGpgError(error); } } - if (signers.size() != gpgme_signers_count(ctx_)) - SPDLOG_DEBUG("not all signers added"); + if (signers.size() != gpgme_signers_count(ctx_.DefaultContext())) + GF_CORE_LOG_DEBUG("not all signers added"); } -std::unique_ptr<GpgFrontend::KeyArgsList> -GpgFrontend::GpgBasicOperator::GetSigners() { - auto count = gpgme_signers_count(ctx_); +auto GpgBasicOperator::GetSigners(bool ascii) -> std::unique_ptr<KeyArgsList> { + auto* ctx = ascii ? ctx_.DefaultContext() : ctx_.BinaryContext(); + + auto count = gpgme_signers_count(ctx); auto signers = std::make_unique<std::vector<GpgKey>>(); - for (auto i = 0u; i < count; i++) { - auto key = GpgKey(gpgme_signers_enum(ctx_, i)); + for (auto i = 0U; i < count; i++) { + auto key = GpgKey(gpgme_signers_enum(ctx, i)); signers->push_back(GpgKey(std::move(key))); } return signers; } -gpg_error_t GpgFrontend::GpgBasicOperator::EncryptSymmetric( - GpgFrontend::ByteArray& in_buffer, GpgFrontend::ByteArrayPtr& out_buffer, - GpgFrontend::GpgEncrResult& result) { - // deepcopy from ByteArray to GpgData - GpgData data_in(in_buffer.data(), in_buffer.size()), data_out; - - gpgme_error_t err = check_gpg_error(gpgme_op_encrypt( - ctx_, nullptr, GPGME_ENCRYPT_SYMMETRIC, data_in, data_out)); - - auto temp_data_out = data_out.Read2Buffer(); - std::swap(temp_data_out, out_buffer); - - // TODO(Saturneric): maybe a bug of gpgme - if (gpgme_err_code(err) == GPG_ERR_NO_ERROR) { - auto temp_result = _new_result(gpgme_op_encrypt_result(ctx_)); - std::swap(result, temp_result); - } - - return err; +void GpgBasicOperator::EncryptSymmetric(GFBuffer in_buffer, bool ascii, + const GpgOperationCallback& cb) { + RunGpgOperaAsync( + [=](const DataObjectPtr& data_object) -> GpgError { + GpgData data_in(in_buffer); + GpgData data_out; + + auto* ctx = ascii ? ctx_.DefaultContext() : ctx_.BinaryContext(); + auto err = CheckGpgError(gpgme_op_encrypt( + ctx, nullptr, GPGME_ENCRYPT_SYMMETRIC, data_in, data_out)); + data_object->Swap({GpgEncryptResult(gpgme_op_encrypt_result(ctx)), + data_out.Read2GFBuffer()}); + + return err; + }, + cb, "gpgme_op_encrypt_symmetric", "2.1.0"); } +} // namespace GpgFrontend diff --git a/src/core/function/gpg/GpgBasicOperator.h b/src/core/function/gpg/GpgBasicOperator.h index 696ac9dc..4b1a2688 100644 --- a/src/core/function/gpg/GpgBasicOperator.h +++ b/src/core/function/gpg/GpgBasicOperator.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,19 +20,20 @@ * 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. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPGFRONTEND_ZH_CN_TS_BASICOPERATOR_H -#define GPGFRONTEND_ZH_CN_TS_BASICOPERATOR_H +#pragma once -#include "core/GpgConstants.h" -#include "core/GpgContext.h" -#include "core/GpgFunctionObject.h" -#include "core/GpgModel.h" +#include "core/function/basic/GpgFunctionObject.h" +#include "core/function/gpg/GpgContext.h" +#include "core/function/result_analyse/GpgResultAnalyse.h" +#include "core/model/GFBuffer.h" +#include "core/typedef/CoreTypedef.h" +#include "core/typedef/GpgTypedef.h" namespace GpgFrontend { @@ -52,19 +53,13 @@ class GPGFRONTEND_CORE_EXPORT GpgBasicOperator int channel = SingletonFunctionObject::GetDefaultChannel()); /** - * @brief Call the interface provided by gpgme for encryption operation + * @brief * * All incoming data pointers out_buffer will be replaced with new valid * values * - * @param keys list of public keys - * @param in_buffer data that needs to be encrypted - * @param out_buffer encrypted data - * @param result the result of the operation - * @return error code */ - gpg_error_t Encrypt(KeyListPtr keys, BypeArrayRef in_buffer, - ByteArrayPtr& out_buffer, GpgEncrResult& result); + void Encrypt(KeyArgsList, GFBuffer, bool, const GpgOperationCallback&); /** * @brief Call the interface provided by GPGME to symmetrical encryption @@ -72,10 +67,10 @@ class GPGFRONTEND_CORE_EXPORT GpgBasicOperator * @param in_buffer Data for encryption * @param out_buffer Encrypted data * @param result Encrypted results - * @return gpg_error_t + * @return GpgError */ - gpg_error_t EncryptSymmetric(BypeArrayRef in_buffer, ByteArrayPtr& out_buffer, - GpgEncrResult& result); + void EncryptSymmetric(GFBuffer in_buffer, bool ascii, + const GpgOperationCallback& cb); /** * @@ -90,10 +85,8 @@ class GPGFRONTEND_CORE_EXPORT GpgBasicOperator * @param sign_result Signature result * @return */ - gpgme_error_t EncryptSign(KeyListPtr keys, KeyListPtr signers, - BypeArrayRef in_buffer, ByteArrayPtr& out_buffer, - GpgEncrResult& encr_result, - GpgSignResult& sign_result); + void EncryptSign(KeyArgsList keys, KeyArgsList signers, GFBuffer in_buffer, + bool ascii, const GpgOperationCallback& cb); /** * @brief Call the interface provided by gpgme for decryption operation @@ -103,8 +96,7 @@ class GPGFRONTEND_CORE_EXPORT GpgBasicOperator * @param result the result of the operation * @return error code */ - gpgme_error_t Decrypt(BypeArrayRef in_buffer, ByteArrayPtr& out_buffer, - GpgDecrResult& result); + void Decrypt(GFBuffer in_buffer, const GpgOperationCallback& cb); /** * @brief Call the interface provided by gpgme to perform decryption and @@ -116,9 +108,7 @@ class GPGFRONTEND_CORE_EXPORT GpgBasicOperator * @param verify_result the result of the verifying operation * @return error code */ - gpgme_error_t DecryptVerify(BypeArrayRef in_buffer, ByteArrayPtr& out_buffer, - GpgDecrResult& decrypt_result, - GpgVerifyResult& verify_result); + void DecryptVerify(GFBuffer in_buffer, const GpgOperationCallback& cb); /** * @brief Call the interface provided by gpgme for verification operation @@ -128,8 +118,8 @@ class GPGFRONTEND_CORE_EXPORT GpgBasicOperator * @param result the result of the operation * @return error code */ - gpgme_error_t Verify(BypeArrayRef in_buffer, ByteArrayPtr& sig_buffer, - GpgVerifyResult& result) const; + void Verify(GFBuffer in_buffer, GFBuffer sig_buffer, + const GpgOperationCallback& cb); /** * @brief Call the interface provided by gpgme for signing operation @@ -151,9 +141,8 @@ class GPGFRONTEND_CORE_EXPORT GpgBasicOperator * @param result the result of the operation * @return error code */ - gpg_error_t Sign(KeyListPtr signers, BypeArrayRef in_buffer, - ByteArrayPtr& out_buffer, gpgme_sig_mode_t mode, - GpgSignResult& result); + void Sign(KeyArgsList signers, GFBuffer in_buffer, GpgSignMode mode, + bool ascii, const GpgOperationCallback& cb); /** * @brief Set the private key for signatures, this operation is a global @@ -161,19 +150,17 @@ class GPGFRONTEND_CORE_EXPORT GpgBasicOperator * * @param keys */ - void SetSigners(KeyArgsList& signers); + void SetSigners(const KeyArgsList& signers, bool ascii); /** * @brief Get a global signature private keys that has been set. * * @return Intelligent pointer pointing to the private key list */ - std::unique_ptr<KeyArgsList> GetSigners(); + auto GetSigners(bool ascii) -> std::unique_ptr<KeyArgsList>; private: GpgContext& ctx_ = GpgContext::GetInstance( SingletonFunctionObject::GetChannel()); ///< Corresponding context }; } // namespace GpgFrontend - -#endif // GPGFRONTEND_ZH_CN_TS_BASICOPERATOR_H diff --git a/src/core/function/gpg/GpgCommandExecutor.cpp b/src/core/function/gpg/GpgCommandExecutor.cpp index 86c47c60..8c994515 100644 --- a/src/core/function/gpg/GpgCommandExecutor.cpp +++ b/src/core/function/gpg/GpgCommandExecutor.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,252 +20,231 @@ * 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. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ #include "GpgCommandExecutor.h" -#include "GpgFunctionObject.h" +#include "core/model/DataObject.h" +#include "core/module/Module.h" +#include "core/thread/Task.h" #include "core/thread/TaskRunnerGetter.h" -GpgFrontend::GpgCommandExecutor::GpgCommandExecutor(int channel) - : SingletonFunctionObject<GpgCommandExecutor>(channel) {} +namespace GpgFrontend { -void GpgFrontend::GpgCommandExecutor::Execute( - std::string cmd, std::vector<std::string> arguments, - std::function<void(int, std::string, std::string)> callback, - std::function<void(QProcess *)> interact_func) { - SPDLOG_DEBUG("called cmd {} arguments size: {}", cmd, arguments.size()); +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; - Thread::Task::TaskCallback result_callback = - [](int rtn, Thread::Task::DataObjectPtr data_object) { - SPDLOG_DEBUG("data object use count: {}", data_object.use_count()); - if (data_object->GetObjectSize() != 4) - throw std::runtime_error("invalid data object size"); + const QString joined_argument = QStringList::fromVector(arguments).join(" "); + + GF_CORE_LOG_DEBUG("building task: called cmd {} arguments size: {}", cmd, + arguments.size()); - auto exit_code = data_object->PopObject<int>(); - auto process_stdout = data_object->PopObject<std::string>(); - auto process_stderr = data_object->PopObject<std::string>(); - auto callback = data_object->PopObject< - std::function<void(int, std::string, std::string)>>(); + Thread::Task::TaskCallback result_callback = + [cmd, joined_argument](int /*rtn*/, const DataObjectPtr &data_object) { + GF_CORE_LOG_DEBUG( + "data object args count of cmd executor result callback: {}", + data_object->GetObjectSize()); + if (!data_object->Check<int, QString, GpgCommandExecutorCallback>()) { + GF_CORE_LOG_ERROR("data object checking failed"); + return; + } + + auto exit_code = ExtractParams<int>(data_object, 0); + auto process_stdout = ExtractParams<QString>(data_object, 1); + auto callback = + ExtractParams<GpgCommandExecutorCallback>(data_object, 2); // call callback - callback(exit_code, process_stdout, process_stderr); + GF_CORE_LOG_DEBUG( + "calling custom callback from caller of cmd {} {}, " + "exit_code: {}", + cmd, joined_argument, exit_code); + callback(exit_code, process_stdout, {}); }; Thread::Task::TaskRunnable runner = - [](GpgFrontend::Thread::Task::DataObjectPtr data_object) -> int { - SPDLOG_DEBUG("process runner called, data object size: {}", - data_object->GetObjectSize()); + [joined_argument](const DataObjectPtr &data_object) -> int { + GF_CORE_LOG_DEBUG("process runner called, data object size: {}", + data_object->GetObjectSize()); - if (data_object->GetObjectSize() != 4) - throw std::runtime_error("invalid data object size"); + if (!data_object->Check<QString, QStringList, GpgCommandExecutorInteractor, + GpgCommandExecutorCallback>()) { + GF_CORE_LOG_ERROR("data object checking failed"); + return -1; + } // get arguments - auto cmd = data_object->PopObject<std::string>(); - SPDLOG_DEBUG("get cmd: {}", cmd); - auto arguments = data_object->PopObject<std::vector<std::string>>(); + auto cmd = ExtractParams<QString>(data_object, 0); + auto arguments = ExtractParams<QStringList>(data_object, 1); auto interact_func = - data_object->PopObject<std::function<void(QProcess *)>>(); + ExtractParams<GpgCommandExecutorInteractor>(data_object, 2); + auto callback = ExtractParams<GpgCommandExecutorCallback>(data_object, 3); + // create process auto *cmd_process = new QProcess(); + // move to current thread + // + cmd_process->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); + + // set arguments + QStringList q_arguments; + for (const auto &argument : arguments) { + q_arguments.append(argument); + } + cmd_process->setArguments(q_arguments); - QObject::connect(cmd_process, &QProcess::started, - []() -> void { SPDLOG_DEBUG("process started"); }); + QObject::connect( + cmd_process, &QProcess::started, [cmd, joined_argument]() -> void { + GF_CORE_LOG_DEBUG( + "\n== Process Execute Started ==\nCommand: {}\nArguments: " + "{}\n========================", + cmd, joined_argument); + }); QObject::connect( cmd_process, &QProcess::readyReadStandardOutput, [interact_func, cmd_process]() { interact_func(cmd_process); }); - QObject::connect(cmd_process, &QProcess::errorOccurred, - [=](QProcess::ProcessError error) { - SPDLOG_ERROR("error in executing command: {} error: {}", - cmd, error); - }); QObject::connect( - cmd_process, qOverload<int, QProcess::ExitStatus>(&QProcess::finished), - [=](int, QProcess::ExitStatus status) { - if (status == QProcess::NormalExit) - SPDLOG_DEBUG( - "proceess finished, succeed in executing command: {}, exit " - "status: {}", - cmd, status); - else - SPDLOG_ERROR( - "proceess finished, error in executing command: {}, exit " - "status: {}", - cmd, status); + cmd_process, &QProcess::errorOccurred, + [=](QProcess::ProcessError error) { + GF_CORE_LOG_ERROR( + "caught error while executing command: {} {}, error: {}", cmd, + joined_argument, error); }); - cmd_process->setProgram(QString::fromStdString(cmd)); - - QStringList q_arguments; - for (const auto &argument : arguments) - q_arguments.append(QString::fromStdString(argument)); - cmd_process->setArguments(q_arguments); - - SPDLOG_DEBUG("process execute ready, cmd: {} {}", cmd, - q_arguments.join(" ").toStdString()); + GF_CORE_LOG_DEBUG( + "\n== Process Execute Ready ==\nCommand: {}\nArguments: " + "{}\n========================", + cmd, joined_argument); cmd_process->start(); cmd_process->waitForFinished(); - std::string process_stdout = - cmd_process->readAllStandardOutput().toStdString(), - process_stderr = - cmd_process->readAllStandardError().toStdString(); + QString process_stdout = cmd_process->readAllStandardOutput(); int exit_code = cmd_process->exitCode(); + GF_CORE_LOG_DEBUG( + "\n==== Process Execution Summary ====\n" + "Command: {}\n" + "Arguments: {}\n" + "Exit Code: {}\n" + "---- Standard Output ----\n" + "{}\n" + "===============================", + cmd, joined_argument, exit_code, process_stdout); + cmd_process->close(); cmd_process->deleteLater(); - // transfer result - SPDLOG_DEBUG("runner append object"); - data_object->AppendObject(std::move(process_stderr)); - data_object->AppendObject(std::move(process_stdout)); - data_object->AppendObject(std::move(exit_code)); - SPDLOG_DEBUG("runner append object done"); - + data_object->Swap({exit_code, process_stdout, callback}); return 0; }; - // data transfer into task - auto data_object = std::make_shared<Thread::Task::DataObject>(); - SPDLOG_DEBUG("executor append object"); - data_object->AppendObject(std::move(callback)); - data_object->AppendObject(std::move(interact_func)); - data_object->AppendObject(std::move(arguments)); - data_object->AppendObject(std::move(std::string{cmd})); - SPDLOG_DEBUG("executor append object done"); - - auto *process_task = new GpgFrontend::Thread::Task( - std::move(runner), fmt::format("Execute/{}", cmd), data_object, + return new Thread::Task( + std::move(runner), QString("GpgCommamdExecutor(%1){%2}").arg(cmd), + TransferParams(cmd, arguments, interact_function, cmd_executor_callback), std::move(result_callback)); +} + +GpgCommandExecutor::ExecuteContext::ExecuteContext( + QString cmd, QList<QString> arguments, GpgCommandExecutorCallback callback, + Module::TaskRunnerPtr task_runner, GpgCommandExecutorInteractor int_func) + : cmd(std::move(cmd)), + arguments(std::move(arguments)), + cb_func(std::move(callback)), + int_func(std::move(int_func)), + task_runner(std::move(task_runner)) {} + +void GpgCommandExecutor::ExecuteSync(ExecuteContext context) { + Thread::Task *task = BuildTaskFromExecCtx(context); QEventLoop looper; - QObject::connect(process_task, &Thread::Task::SignalTaskEnd, &looper, + QObject::connect(task, &Thread::Task::SignalTaskEnd, &looper, &QEventLoop::quit); - GpgFrontend::Thread::TaskRunnerGetter::GetInstance() - .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_External_Process) - ->PostTask(process_task); - + Thread::TaskRunnerPtr target_task_runner = nullptr; + + if (context.task_runner != nullptr) { + target_task_runner = context.task_runner; + } else { + target_task_runner = + GpgFrontend::Thread::TaskRunnerGetter::GetInstance().GetTaskRunner( + Thread::TaskRunnerGetter::kTaskRunnerType_External_Process); + } + target_task_runner->PostTask(task); + + // to arvoid dead lock issue we need to check if current thread is the same as + // target thread. if it is, we can't call exec() because it will block the + // current thread. + GF_CORE_LOG_TRACE("blocking until gpg command finish..."); // block until task finished // this is to keep reference vaild until task finished looper.exec(); } -void GpgFrontend::GpgCommandExecutor::ExecuteConcurrently( - std::string cmd, std::vector<std::string> arguments, - std::function<void(int, std::string, std::string)> callback, - std::function<void(QProcess *)> interact_func) { - SPDLOG_DEBUG("called cmd {} arguments size: {}", cmd, arguments.size()); - - Thread::Task::TaskCallback result_callback = - [](int rtn, Thread::Task::DataObjectPtr data_object) { - if (data_object->GetObjectSize() != 4) - throw std::runtime_error("invalid data object size"); - - auto exit_code = data_object->PopObject<int>(); - auto process_stdout = data_object->PopObject<std::string>(); - auto process_stderr = data_object->PopObject<std::string>(); - auto callback = data_object->PopObject< - std::function<void(int, std::string, std::string)>>(); - - // call callback - callback(exit_code, process_stdout, process_stderr); - }; - - Thread::Task::TaskRunnable runner = - [](GpgFrontend::Thread::Task::DataObjectPtr data_object) -> int { - SPDLOG_DEBUG("process runner called, data object size: {}", - data_object->GetObjectSize()); - - if (data_object->GetObjectSize() != 4) - throw std::runtime_error("invalid data object size"); - - SPDLOG_DEBUG("runner pop object"); - // get arguments - auto cmd = data_object->PopObject<std::string>(); - auto arguments = data_object->PopObject<std::vector<std::string>>(); - auto interact_func = - data_object->PopObject<std::function<void(QProcess *)>>(); - SPDLOG_DEBUG("runner pop object done"); - - auto *cmd_process = new QProcess(); - cmd_process->setProcessChannelMode(QProcess::MergedChannels); - - QObject::connect(cmd_process, &QProcess::started, - []() -> void { SPDLOG_DEBUG("process started"); }); - QObject::connect( - cmd_process, &QProcess::readyReadStandardOutput, - [interact_func, cmd_process]() { interact_func(cmd_process); }); - QObject::connect(cmd_process, &QProcess::errorOccurred, - [=](QProcess::ProcessError error) { - SPDLOG_ERROR("error in executing command: {} error: {}", - cmd, error); - }); - QObject::connect( - cmd_process, qOverload<int, QProcess::ExitStatus>(&QProcess::finished), - [=](int, QProcess::ExitStatus status) { - if (status == QProcess::NormalExit) - SPDLOG_DEBUG( - "proceess finished, succeed in executing command: {}, exit " - "status: {}", - cmd, status); - else - SPDLOG_ERROR( - "proceess finished, error in executing command: {}, exit " - "status: {}", - cmd, status); - }); - - cmd_process->setProgram(QString::fromStdString(cmd)); - cmd_process->setProcessChannelMode(QProcess::SeparateChannels); - - QStringList q_arguments; - for (const auto &argument : arguments) - q_arguments.append(QString::fromStdString(argument)); - cmd_process->setArguments(q_arguments); - - SPDLOG_DEBUG("process start ready, cmd: {} {}", cmd, - q_arguments.join(" ").toStdString()); - - cmd_process->start(); - cmd_process->waitForFinished(); - - std::string process_stdout = - cmd_process->readAllStandardOutput().toStdString(), - process_stderr = - cmd_process->readAllStandardError().toStdString(); - int exit_code = cmd_process->exitCode(); - - cmd_process->close(); - cmd_process->deleteLater(); - - // transfer result - SPDLOG_DEBUG("runner append object"); - data_object->AppendObject(std::move(process_stderr)); - data_object->AppendObject(std::move(process_stdout)); - data_object->AppendObject(std::move(exit_code)); - SPDLOG_DEBUG("runner append object done"); - - return 0; - }; - - // data transfer into task - auto data_object = std::make_shared<Thread::Task::DataObject>(); - data_object->AppendObject(std::move(callback)); - data_object->AppendObject(std::move(interact_func)); - data_object->AppendObject(std::move(arguments)); - data_object->AppendObject(std::move(std::string{cmd})); - - auto *process_task = new GpgFrontend::Thread::Task( - std::move(runner), fmt::format("ExecuteConcurrently/{}", cmd), - data_object, std::move(result_callback), false); +void GpgCommandExecutor::ExecuteConcurrentlyAsync(ExecuteContexts contexts) { + for (auto &context : contexts) { + const auto &cmd = context.cmd; + GF_CORE_LOG_INFO("gpg concurrently called cmd {}", cmd); + + Thread::Task *task = BuildTaskFromExecCtx(context); + + if (context.task_runner != nullptr) { + context.task_runner->PostTask(task); + } else { + GpgFrontend::Thread::TaskRunnerGetter::GetInstance() + .GetTaskRunner( + Thread::TaskRunnerGetter::kTaskRunnerType_External_Process) + ->PostTask(task); + } + } +} - GpgFrontend::Thread::TaskRunnerGetter::GetInstance() - .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_External_Process) - ->PostTask(process_task); +void GpgCommandExecutor::ExecuteConcurrentlySync(ExecuteContexts contexts) { + QEventLoop looper; + auto remaining_tasks = contexts.size(); + Thread::TaskRunnerPtr target_task_runner = nullptr; + + for (auto &context : contexts) { + const auto &cmd = context.cmd; + GF_CORE_LOG_DEBUG("gpg concurrently called cmd: {}", cmd); + + Thread::Task *task = BuildTaskFromExecCtx(context); + + QObject::connect(task, &Thread::Task::SignalTaskEnd, [&]() { + --remaining_tasks; + GF_CORE_LOG_DEBUG("remaining tasks: {}", remaining_tasks); + if (remaining_tasks <= 0) { + GF_CORE_LOG_DEBUG("no remaining task, quit"); + looper.quit(); + } + }); + + if (context.task_runner != nullptr) { + target_task_runner = context.task_runner; + } else { + target_task_runner = + GpgFrontend::Thread::TaskRunnerGetter::GetInstance().GetTaskRunner( + Thread::TaskRunnerGetter::kTaskRunnerType_External_Process); + } + + target_task_runner->PostTask(task); + } + + GF_CORE_LOG_TRACE("blocking until concurrent gpg commands finish..."); + // block until task finished + // this is to keep reference vaild until task finished + looper.exec(); } + +} // 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 da0e7a8b..d161406a 100644 --- a/src/core/function/gpg/GpgCommandExecutor.h +++ b/src/core/function/gpg/GpgCommandExecutor.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,39 +20,43 @@ * 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. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPGFRONTEND_ZH_CN_TS_GPGCOMMANDEXECUTOR_H -#define GPGFRONTEND_ZH_CN_TS_GPGCOMMANDEXECUTOR_H +#pragma once -#ifndef WINDOWS -#include <boost/process.hpp> -#endif - -#include "core/GpgContext.h" -#include "core/GpgFunctionObject.h" -#include "core/thread/Task.h" +#include "core/module/Module.h" namespace GpgFrontend { +using GpgCommandExecutorCallback = std::function<void(int, QString, QString)>; +using GpgCommandExecutorInteractor = std::function<void(QProcess *)>; + /** * @brief Extra commands related to GPG * */ -class GPGFRONTEND_CORE_EXPORT GpgCommandExecutor - : public SingletonFunctionObject<GpgCommandExecutor> { +class GPGFRONTEND_CORE_EXPORT GpgCommandExecutor { public: - /** - * @brief Construct a new Gpg Command Executor object - * - * @param channel Corresponding context - */ - explicit GpgCommandExecutor( - int channel = SingletonFunctionObject::GetDefaultChannel()); + struct ExecuteContext { + QString cmd; + QStringList arguments; + GpgCommandExecutorCallback cb_func; + GpgCommandExecutorInteractor int_func; + Module::TaskRunnerPtr task_runner = nullptr; + + ExecuteContext( + QString cmd, QStringList arguments, + GpgCommandExecutorCallback callback = [](int, const QString &, + const QString &) {}, + Module::TaskRunnerPtr task_runner = nullptr, + GpgCommandExecutorInteractor int_func = [](QProcess *) {}); + }; + + using ExecuteContexts = QList<ExecuteContext>; /** * @brief Excuting a command @@ -60,22 +64,11 @@ class GPGFRONTEND_CORE_EXPORT GpgCommandExecutor * @param arguments Command parameters * @param interact_func Command answering function */ - void Execute( - std::string cmd, std::vector<std::string> arguments, - std::function<void(int, std::string, std::string)> callback = - [](int, std::string, std::string) {}, - std::function<void(QProcess *)> interact_func = [](QProcess *) {}); + static void ExecuteSync(ExecuteContext); - void ExecuteConcurrently( - std::string cmd, std::vector<std::string> arguments, - std::function<void(int, std::string, std::string)> callback, - std::function<void(QProcess *)> interact_func = [](QProcess *) {}); + static void ExecuteConcurrentlyAsync(ExecuteContexts); - private: - GpgContext &ctx_ = GpgContext::GetInstance( - SingletonFunctionObject::GetChannel()); ///< Corresponding context + static void ExecuteConcurrentlySync(ExecuteContexts); }; } // namespace GpgFrontend - -#endif // GPGFRONTEND_ZH_CN_TS_GPGCOMMANDEXECUTOR_H diff --git a/src/core/function/gpg/GpgContext.cpp b/src/core/function/gpg/GpgContext.cpp new file mode 100644 index 00000000..104e254f --- /dev/null +++ b/src/core/function/gpg/GpgContext.cpp @@ -0,0 +1,336 @@ +/** + * Copyright (C) 2021 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 "core/function/gpg/GpgContext.h" + +#include <gpg-error.h> +#include <gpgme.h> + +#include <cassert> +#include <mutex> + +#include "core/function/CoreSignalStation.h" +#include "core/function/basic/GpgFunctionObject.h" +#include "core/model/GpgPassphraseContext.h" +#include "core/module/ModuleManager.h" +#include "core/utils/CacheUtils.h" +#include "core/utils/GpgUtils.h" +#include "core/utils/MemoryUtils.h" + +#ifdef _WIN32 +#include <windows.h> +#endif + +namespace GpgFrontend { + +class GpgContext::Impl { + public: + /** + * Constructor + * Set up gpgme-context, set paths to app-run path + */ + Impl(GpgContext *parent, const GpgContextInitArgs &args) + : parent_(parent), + args_(args), + good_(default_ctx_initialize(args) && binary_ctx_initialize(args)) {} + + ~Impl() { + if (ctx_ref_ != nullptr) { + gpgme_release(ctx_ref_); + } + + if (binary_ctx_ref_ != nullptr) { + gpgme_release(binary_ctx_ref_); + } + } + + [[nodiscard]] auto BinaryContext() const -> gpgme_ctx_t { + return binary_ctx_ref_; + } + + [[nodiscard]] auto DefaultContext() const -> gpgme_ctx_t { return ctx_ref_; } + + [[nodiscard]] auto Good() const -> bool { return good_; } + + auto SetPassphraseCb(const gpgme_ctx_t &ctx, gpgme_passphrase_cb_t cb) + -> bool { + if (gpgme_get_pinentry_mode(ctx) != GPGME_PINENTRY_MODE_LOOPBACK) { + if (CheckGpgError(gpgme_set_pinentry_mode( + ctx, GPGME_PINENTRY_MODE_LOOPBACK)) != GPG_ERR_NO_ERROR) { + return false; + } + } + gpgme_set_passphrase_cb(ctx, cb, reinterpret_cast<void *>(parent_)); + return true; + } + + static auto TestPassphraseCb(void *opaque, const char *uid_hint, + const char *passphrase_info, int last_was_bad, + int fd) -> gpgme_error_t { + size_t res; + QString pass = "abcdefg\n"; + auto pass_len = pass.size(); + + size_t off = 0; + + do { + res = gpgme_io_write(fd, &pass[off], pass_len - off); + if (res > 0) off += res; + } while (res > 0 && off != pass_len); + + return off == pass_len ? 0 : gpgme_error_from_errno(errno); + } + + static auto CustomPassphraseCb(void *hook, const char *uid_hint, + const char *passphrase_info, int prev_was_bad, + int fd) -> gpgme_error_t { + auto context_cache = GetCacheValue("PinentryContext"); + bool ask_for_new = context_cache == "NEW_PASSPHRASE"; + auto context = + QSharedPointer<GpgPassphraseContext>(new GpgPassphraseContext( + uid_hint != nullptr ? uid_hint : "", + passphrase_info != nullptr ? passphrase_info : "", + prev_was_bad != 0, ask_for_new)); + + GF_CORE_LOG_DEBUG( + "custom passphrase cb called, uid: {}, info: {}, last_was_bad: {}", + uid_hint == nullptr ? "<empty>" : QString{uid_hint}, + passphrase_info == nullptr ? "<empty>" : QString{passphrase_info}, + prev_was_bad); + + QEventLoop looper; + QObject::connect(CoreSignalStation::GetInstance(), + &CoreSignalStation::SignalUserInputPassphraseCallback, + &looper, &QEventLoop::quit); + + emit CoreSignalStation::GetInstance()->SignalNeedUserInputPassphrase( + context); + looper.exec(); + + ResetCacheValue("PinentryContext"); + auto passphrase = context->GetPassphrase().toStdString(); + auto passpahrase_size = passphrase.size(); + GF_CORE_LOG_DEBUG("get passphrase from pinentry size: {}", + passpahrase_size); + + size_t res = 0; + if (passpahrase_size > 0) { + size_t off = 0; + do { + res = gpgme_io_write(fd, &passphrase[off], passpahrase_size - off); + if (res > 0) off += res; + } while (res > 0 && off != passpahrase_size); + } + + res += gpgme_io_write(fd, "\n", 1); + + GF_CORE_LOG_DEBUG("custom passphrase cd is about to return, res: {}", res); + return res == passpahrase_size + 1 + ? 0 + : gpgme_error_from_errno(GPG_ERR_CANCELED); + } + + static auto TestStatusCb(void *hook, const char *keyword, const char *args) + -> gpgme_error_t { + GF_CORE_LOG_DEBUG("keyword {}", keyword); + return GPG_ERR_NO_ERROR; + } + + private: + GpgContext *parent_; + GpgContextInitArgs args_{}; ///< + gpgme_ctx_t ctx_ref_ = nullptr; ///< + gpgme_ctx_t binary_ctx_ref_ = nullptr; ///< + bool good_ = true; + std::mutex ctx_ref_lock_; + std::mutex binary_ctx_ref_lock_; + + static auto set_ctx_key_list_mode(const gpgme_ctx_t &ctx) -> bool { + assert(ctx != nullptr); + + const auto gpgme_version = Module::RetrieveRTValueTypedOrDefault<>( + "core", "gpgme.version", QString{"0.0.0"}); + GF_CORE_LOG_DEBUG("got gpgme version version from rt: {}", gpgme_version); + + if (gpgme_get_keylist_mode(ctx) == 0) { + GF_CORE_LOG_ERROR( + "ctx is not a valid pointer, reported by gpgme_get_keylist_mode"); + return false; + } + + // set keylist mode + return CheckGpgError(gpgme_set_keylist_mode( + ctx, GPGME_KEYLIST_MODE_LOCAL | GPGME_KEYLIST_MODE_WITH_SECRET | + GPGME_KEYLIST_MODE_SIGS | + GPGME_KEYLIST_MODE_SIG_NOTATIONS | + GPGME_KEYLIST_MODE_WITH_TOFU)) == GPG_ERR_NO_ERROR; + } + + static auto set_ctx_openpgp_engine_info(gpgme_ctx_t ctx) -> bool { + const auto app_path = Module::RetrieveRTValueTypedOrDefault<>( + "core", "gpgme.ctx.app_path", QString{}); + const auto database_path = Module::RetrieveRTValueTypedOrDefault<>( + "core", "gpgme.ctx.database_path", QString{}); + + GF_CORE_LOG_DEBUG("ctx set engine info, db path: {}, app path: {}", + database_path, app_path); + + auto app_path_buffer = app_path.toUtf8(); + auto database_path_buffer = database_path.toUtf8(); + + auto err = gpgme_ctx_set_engine_info( + ctx, gpgme_get_protocol(ctx), + app_path.isEmpty() ? nullptr : app_path_buffer, + database_path.isEmpty() ? nullptr : database_path_buffer); + + assert(CheckGpgError(err) == GPG_ERR_NO_ERROR); + return CheckGpgError(err) == GPG_ERR_NO_ERROR; + + return true; + } + + auto common_ctx_initialize(const gpgme_ctx_t &ctx, + const GpgContextInitArgs &args) -> bool { + assert(ctx != nullptr); + + if (args.custom_gpgconf && !args.custom_gpgconf_path.isEmpty()) { + GF_CORE_LOG_DEBUG("set custom gpgconf path: {}", + args.custom_gpgconf_path); + auto err = + gpgme_ctx_set_engine_info(ctx, GPGME_PROTOCOL_GPGCONF, + args.custom_gpgconf_path.toUtf8(), nullptr); + + if (CheckGpgError(err) != GPG_ERR_NO_ERROR) { + GF_CORE_LOG_ERROR("set gpg context engine info error: {}", + DescribeGpgErrCode(err).second); + return false; + } + } + + // set context offline mode + GF_CORE_LOG_DEBUG("gpg context offline mode: {}", args_.offline_mode); + gpgme_set_offline(ctx, args_.offline_mode ? 1 : 0); + + // set option auto import missing key + // invalid at offline mode + GF_CORE_LOG_DEBUG("gpg context auto import missing key: {}", + args_.offline_mode); + if (!args.offline_mode && args.auto_import_missing_key) { + if (CheckGpgError(gpgme_set_ctx_flag(ctx, "auto-key-import", "1")) != + GPG_ERR_NO_ERROR) { + return false; + } + } + + if (!set_ctx_key_list_mode(ctx)) { + GF_CORE_LOG_DEBUG("set ctx key list mode failed"); + return false; + } + + // for unit test + if (args_.test_mode) { + if (!SetPassphraseCb(ctx, TestPassphraseCb)) { + GF_CORE_LOG_ERROR("set passphrase cb failed, test"); + return false; + }; + } else if (!args_.use_pinentry) { + if (!SetPassphraseCb(ctx, CustomPassphraseCb)) { + GF_CORE_LOG_DEBUG("set passphrase cb failed, custom"); + return false; + } + } + + // set custom gpg key db path + if (!args_.db_path.isEmpty()) { + Module::UpsertRTValue("core", "gpgme.ctx.database_path", args_.db_path); + } + + if (!set_ctx_openpgp_engine_info(ctx)) { + GF_CORE_LOG_ERROR("set gpgme context openpgp engine info failed"); + return false; + } + + return true; + } + + auto binary_ctx_initialize(const GpgContextInitArgs &args) -> bool { + gpgme_ctx_t p_ctx; + if (auto err = CheckGpgError(gpgme_new(&p_ctx)); err != GPG_ERR_NO_ERROR) { + GF_CORE_LOG_ERROR("get new gpg context error: {}", + DescribeGpgErrCode(err).second); + return false; + } + assert(p_ctx != nullptr); + binary_ctx_ref_ = p_ctx; + + if (!common_ctx_initialize(binary_ctx_ref_, args)) { + GF_CORE_LOG_ERROR("get new ctx failed, binary"); + return false; + } + + gpgme_set_armor(binary_ctx_ref_, 0); + return true; + } + + auto default_ctx_initialize(const GpgContextInitArgs &args) -> bool { + gpgme_ctx_t p_ctx; + if (CheckGpgError(gpgme_new(&p_ctx)) != GPG_ERR_NO_ERROR) { + GF_CORE_LOG_ERROR("get new ctx failed, default"); + return false; + } + assert(p_ctx != nullptr); + ctx_ref_ = p_ctx; + + if (!common_ctx_initialize(ctx_ref_, args)) { + return false; + } + + gpgme_set_armor(ctx_ref_, 1); + return true; + } +}; + +GpgContext::GpgContext(int channel) + : SingletonFunctionObject<GpgContext>(channel), + p_(SecureCreateUniqueObject<Impl>(this, GpgContextInitArgs{})) {} + +GpgContext::GpgContext(GpgContextInitArgs args, int channel) + : SingletonFunctionObject<GpgContext>(channel), + p_(SecureCreateUniqueObject<Impl>(this, args)) {} + +auto GpgContext::Good() const -> bool { return p_->Good(); } + +auto GpgContext::BinaryContext() -> gpgme_ctx_t { return p_->BinaryContext(); } + +auto GpgContext::DefaultContext() -> gpgme_ctx_t { + return p_->DefaultContext(); +} + +GpgContext::~GpgContext() = default; + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/function/gpg/GpgContext.h b/src/core/function/gpg/GpgContext.h new file mode 100644 index 00000000..d473a341 --- /dev/null +++ b/src/core/function/gpg/GpgContext.h @@ -0,0 +1,76 @@ +/** + * Copyright (C) 2021 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/SecureMemoryAllocator.h" +#include "core/function/basic/GpgFunctionObject.h" + +namespace GpgFrontend { + +/** + * @brief + * + */ +struct GpgContextInitArgs { + QString db_path = {}; ///< + + bool test_mode = false; ///< + bool offline_mode = false; ///< + bool auto_import_missing_key = false; ///< + + bool custom_gpgconf = false; ///< + QString custom_gpgconf_path; ///< + + bool use_pinentry = false; ///< +}; + +/** + * @brief + * + */ +class GPGFRONTEND_CORE_EXPORT GpgContext + : public SingletonFunctionObject<GpgContext> { + public: + explicit GpgContext(int channel); + + explicit GpgContext(GpgContextInitArgs args, int channel); + + virtual ~GpgContext() override; + + [[nodiscard]] auto Good() const -> bool; + + auto BinaryContext() -> gpgme_ctx_t; + + auto DefaultContext() -> gpgme_ctx_t; + + private: + class Impl; + SecureUniquePtr<Impl> p_; +}; +} // namespace GpgFrontend diff --git a/src/core/function/gpg/GpgFileOpera.cpp b/src/core/function/gpg/GpgFileOpera.cpp index 30678cf0..e3d47cf6 100644 --- a/src/core/function/gpg/GpgFileOpera.cpp +++ b/src/core/function/gpg/GpgFileOpera.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,235 +20,353 @@ * 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. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ #include "GpgFileOpera.h" -#include <memory> -#include <string> +#include "core/function/ArchiveFileOperator.h" +#include "core/function/gpg/GpgBasicOperator.h" +#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" +#include "core/utils/GpgUtils.h" -#include "GpgBasicOperator.h" -#include "GpgConstants.h" -#include "function/FileOperator.h" +namespace GpgFrontend { -GpgFrontend::GpgFileOpera::GpgFileOpera(int channel) +constexpr ssize_t kDataExchangerSize = 8192; + +GpgFileOpera::GpgFileOpera(int channel) : SingletonFunctionObject<GpgFileOpera>(channel) {} -GpgFrontend::GpgError GpgFrontend::GpgFileOpera::EncryptFile( - KeyListPtr keys, const std::string& in_path, const std::string& out_path, - GpgEncrResult& result, int _channel) { -#ifdef WINDOWS - auto in_path_std = - std::filesystem::path(QString::fromStdString(in_path).toStdU16String()); - auto out_path_std = - std::filesystem::path(QString::fromStdString(out_path).toStdU16String()); -#else - auto in_path_std = std::filesystem::path(in_path); - auto out_path_std = std::filesystem::path(out_path); -#endif - - std::string in_buffer; - if (!FileOperator::ReadFileStd(in_path_std, in_buffer)) { - throw std::runtime_error("read file error"); - } - - std::unique_ptr<std::string> out_buffer = nullptr; - - auto err = GpgBasicOperator::GetInstance(_channel).Encrypt( - std::move(keys), in_buffer, out_buffer, result); - - if (check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR) - if (!FileOperator::WriteFileStd(out_path_std, *out_buffer)) { - throw std::runtime_error("write_buffer_to_file error"); - }; - - return err; +void GpgFileOpera::EncryptFile(std::vector<GpgKey> keys, const QString& in_path, + bool ascii, const QString& out_path, + const GpgOperationCallback& cb) { + RunGpgOperaAsync( + [=](const DataObjectPtr& data_object) -> GpgError { + std::vector<gpgme_key_t> recipients(keys.begin(), keys.end()); + + // Last entry data_in array has to be nullptr + recipients.emplace_back(nullptr); + + GpgData data_in(in_path, true); + GpgData data_out(out_path, false); + + auto* ctx = ascii ? ctx_.DefaultContext() : ctx_.BinaryContext(); + auto err = CheckGpgError(gpgme_op_encrypt(ctx, recipients.data(), + GPGME_ENCRYPT_ALWAYS_TRUST, + data_in, data_out)); + data_object->Swap({GpgEncryptResult(gpgme_op_encrypt_result(ctx))}); + + return err; + }, + cb, "gpgme_op_encrypt", "2.1.0"); } -GpgFrontend::GpgError GpgFrontend::GpgFileOpera::DecryptFile( - const std::string& in_path, const std::string& out_path, - GpgDecrResult& result) { -#ifdef WINDOWS - auto in_path_std = - std::filesystem::path(QString::fromStdString(in_path).toStdU16String()); - auto out_path_std = - std::filesystem::path(QString::fromStdString(out_path).toStdU16String()); -#else - auto in_path_std = std::filesystem::path(in_path); - auto out_path_std = std::filesystem::path(out_path); -#endif - - std::string in_buffer; - if (!FileOperator::ReadFileStd(in_path_std, in_buffer)) { - throw std::runtime_error("read file error"); - } - std::unique_ptr<std::string> out_buffer; - - auto err = - GpgBasicOperator::GetInstance().Decrypt(in_buffer, out_buffer, result); - - assert(check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR); - - if (check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR) - if (!FileOperator::WriteFileStd(out_path_std, *out_buffer)) { - throw std::runtime_error("write_buffer_to_file error"); - }; - - return err; +void GpgFileOpera::EncryptDirectory(std::vector<GpgKey> keys, + const QString& in_path, bool ascii, + const QString& out_path, + const GpgOperationCallback& cb) { + auto ex = std::make_shared<GFDataExchanger>(kDataExchangerSize); + + RunGpgOperaAsync( + [=](const DataObjectPtr& data_object) -> GpgError { + std::vector<gpgme_key_t> recipients(keys.begin(), keys.end()); + + // Last entry data_in array has to be nullptr + recipients.emplace_back(nullptr); + + GpgData data_in(ex); + GpgData data_out(out_path, false); + + GF_CORE_LOG_DEBUG("encrypt directory start"); + + auto* ctx = ascii ? ctx_.DefaultContext() : ctx_.BinaryContext(); + auto err = CheckGpgError(gpgme_op_encrypt(ctx, recipients.data(), + GPGME_ENCRYPT_ALWAYS_TRUST, + data_in, data_out)); + data_object->Swap({GpgEncryptResult(gpgme_op_encrypt_result(ctx))}); + + GF_CORE_LOG_DEBUG("encrypt directory finished, err: {}", err); + return err; + }, + cb, "gpgme_op_encrypt", "2.1.0"); + + ArchiveFileOperator::NewArchive2DataExchanger( + in_path, ex, [=](GFError err, const DataObjectPtr&) { + GF_CORE_LOG_DEBUG("new archive 2 data exchanger operation, err: {}", + err); + }); +} + +void GpgFileOpera::DecryptFile(const QString& in_path, const QString& out_path, + const GpgOperationCallback& cb) { + RunGpgOperaAsync( + [=](const DataObjectPtr& data_object) -> GpgError { + GpgData data_in(in_path, true); + GpgData data_out(out_path, false); + + auto err = CheckGpgError( + gpgme_op_decrypt(ctx_.DefaultContext(), data_in, data_out)); + data_object->Swap( + {GpgDecryptResult(gpgme_op_decrypt_result(ctx_.DefaultContext()))}); + + return err; + }, + cb, "gpgme_op_decrypt", "2.1.0"); +} + +void GpgFileOpera::DecryptArchive(const QString& in_path, + const QString& out_path, + const GpgOperationCallback& cb) { + auto ex = std::make_shared<GFDataExchanger>(kDataExchangerSize); + + ArchiveFileOperator::ExtractArchiveFromDataExchanger( + ex, out_path, [](GFError err, const DataObjectPtr&) { + GF_CORE_LOG_DEBUG( + "extract archive from data exchanger operation, err: {}", err); + }); + + RunGpgOperaAsync( + [=](const DataObjectPtr& data_object) -> GpgError { + GpgData data_in(in_path, true); + GpgData data_out(ex); + + auto err = CheckGpgError( + gpgme_op_decrypt(ctx_.DefaultContext(), data_in, data_out)); + + data_object->Swap( + {GpgDecryptResult(gpgme_op_decrypt_result(ctx_.DefaultContext()))}); + return err; + }, + cb, "gpgme_op_decrypt", "2.1.0"); } -gpgme_error_t GpgFrontend::GpgFileOpera::SignFile(KeyListPtr keys, - const std::string& in_path, - const std::string& out_path, - GpgSignResult& result, - int _channel) { -#ifdef WINDOWS - auto in_path_std = - std::filesystem::path(QString::fromStdString(in_path).toStdU16String()); - auto out_path_std = - std::filesystem::path(QString::fromStdString(out_path).toStdU16String()); -#else - auto in_path_std = std::filesystem::path(in_path); - auto out_path_std = std::filesystem::path(out_path); -#endif - - std::string in_buffer; - if (!FileOperator::ReadFileStd(in_path_std, in_buffer)) { - throw std::runtime_error("read file error"); - } - std::unique_ptr<std::string> out_buffer; - - auto err = GpgBasicOperator::GetInstance(_channel).Sign( - std::move(keys), in_buffer, out_buffer, GPGME_SIG_MODE_DETACH, result); - - if (check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR) - if (!FileOperator::WriteFileStd(out_path_std, *out_buffer)) { - throw std::runtime_error("write_buffer_to_file error"); - }; - - return err; +void GpgFileOpera::SignFile(KeyArgsList keys, const QString& in_path, + bool ascii, const QString& out_path, + const GpgOperationCallback& cb) { + RunGpgOperaAsync( + [=](const DataObjectPtr& data_object) -> GpgError { + GpgError err; + + // Set Singers of this opera + GpgBasicOperator::GetInstance().SetSigners(keys, ascii); + + GpgData data_in(in_path, true); + GpgData data_out(out_path, false); + + auto* ctx = ascii ? ctx_.DefaultContext() : ctx_.BinaryContext(); + err = CheckGpgError( + gpgme_op_sign(ctx, data_in, data_out, GPGME_SIG_MODE_DETACH)); + + data_object->Swap({ + GpgSignResult(gpgme_op_sign_result(ctx)), + }); + return err; + }, + cb, "gpgme_op_sign", "2.1.0"); } -gpgme_error_t GpgFrontend::GpgFileOpera::VerifyFile( - const std::string& data_path, const std::string& sign_path, - GpgVerifyResult& result, int _channel) { -#ifdef WINDOWS - auto data_path_std = - std::filesystem::path(QString::fromStdString(data_path).toStdU16String()); - auto sign_path_std = - std::filesystem::path(QString::fromStdString(sign_path).toStdU16String()); -#else - auto data_path_std = std::filesystem::path(data_path); - auto sign_path_std = std::filesystem::path(sign_path); -#endif - - std::string in_buffer; - if (!FileOperator::ReadFileStd(data_path_std, in_buffer)) { - throw std::runtime_error("read file error"); - } - std::unique_ptr<std::string> sign_buffer = nullptr; - if (!sign_path.empty()) { - std::string sign_buffer_str; - if (!FileOperator::ReadFileStd(sign_path_std, sign_buffer_str)) { - throw std::runtime_error("read file error"); - } - sign_buffer = std::make_unique<std::string>(sign_buffer_str); - } - auto err = GpgBasicOperator::GetInstance(_channel).Verify( - in_buffer, sign_buffer, result); - return err; +void GpgFileOpera::VerifyFile(const QString& data_path, + const QString& sign_path, + const GpgOperationCallback& cb) { + RunGpgOperaAsync( + [=](const DataObjectPtr& data_object) -> GpgError { + GpgError err; + + GpgData data_in(data_path, true); + GpgData data_out; + if (!sign_path.isEmpty()) { + GpgData sig_data(sign_path, true); + err = CheckGpgError(gpgme_op_verify(ctx_.DefaultContext(), sig_data, + data_in, nullptr)); + } else { + err = CheckGpgError(gpgme_op_verify(ctx_.DefaultContext(), data_in, + nullptr, data_out)); + } + + data_object->Swap({ + GpgVerifyResult(gpgme_op_verify_result(ctx_.DefaultContext())), + }); + + return err; + }, + cb, "gpgme_op_verify", "2.1.0"); } -gpg_error_t GpgFrontend::GpgFileOpera::EncryptSignFile( - KeyListPtr keys, KeyListPtr signer_keys, const std::string& in_path, - const std::string& out_path, GpgEncrResult& encr_res, - GpgSignResult& sign_res, int _channel) { -#ifdef WINDOWS - auto in_path_std = - std::filesystem::path(QString::fromStdString(in_path).toStdU16String()); - auto out_path_std = - std::filesystem::path(QString::fromStdString(out_path).toStdU16String()); -#else - auto in_path_std = std::filesystem::path(in_path); - auto out_path_std = std::filesystem::path(out_path); -#endif - - std::string in_buffer; - if (!FileOperator::ReadFileStd(in_path_std, in_buffer)) { - throw std::runtime_error("read file error"); - } - std::unique_ptr<std::string> out_buffer = nullptr; - - auto err = GpgBasicOperator::GetInstance(_channel).EncryptSign( - std::move(keys), std::move(signer_keys), in_buffer, out_buffer, encr_res, - sign_res); - - if (check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR) - if (!FileOperator::WriteFileStd(out_path_std, *out_buffer)) { - throw std::runtime_error("write_buffer_to_file error"); - }; - - return err; +void GpgFileOpera::EncryptSignFile(KeyArgsList keys, KeyArgsList signer_keys, + const QString& in_path, bool ascii, + const QString& out_path, + const GpgOperationCallback& cb) { + RunGpgOperaAsync( + [=](const DataObjectPtr& data_object) -> GpgError { + GpgError err; + std::vector<gpgme_key_t> recipients(keys.begin(), keys.end()); + + // Last entry data_in array has to be nullptr + recipients.emplace_back(nullptr); + + GpgBasicOperator::GetInstance().SetSigners(signer_keys, ascii); + + GpgData data_in(in_path, true); + GpgData data_out(out_path, false); + + auto* ctx = ascii ? ctx_.DefaultContext() : ctx_.BinaryContext(); + err = CheckGpgError(gpgme_op_encrypt_sign(ctx, recipients.data(), + GPGME_ENCRYPT_ALWAYS_TRUST, + data_in, data_out)); + + data_object->Swap({ + GpgEncryptResult(gpgme_op_encrypt_result(ctx)), + GpgSignResult(gpgme_op_sign_result(ctx)), + }); + return err; + }, + cb, "gpgme_op_encrypt_sign", "2.1.0"); } -gpg_error_t GpgFrontend::GpgFileOpera::DecryptVerifyFile( - const std::string& in_path, const std::string& out_path, - GpgDecrResult& decr_res, GpgVerifyResult& verify_res) { -#ifdef WINDOWS - auto in_path_std = - std::filesystem::path(QString::fromStdString(in_path).toStdU16String()); - auto out_path_std = - std::filesystem::path(QString::fromStdString(out_path).toStdU16String()); -#else - auto in_path_std = std::filesystem::path(in_path); - auto out_path_std = std::filesystem::path(out_path); -#endif - - std::string in_buffer; - if (!FileOperator::ReadFileStd(in_path_std, in_buffer)) { - throw std::runtime_error("read file error"); - } - - std::unique_ptr<std::string> out_buffer = nullptr; - auto err = GpgBasicOperator::GetInstance().DecryptVerify( - in_buffer, out_buffer, decr_res, verify_res); - - if (check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR) - if (!FileOperator::WriteFileStd(out_path_std, *out_buffer)) { - throw std::runtime_error("write file error"); - }; - - return err; +void GpgFileOpera::EncryptSignDirectory(KeyArgsList keys, + KeyArgsList signer_keys, + const QString& in_path, bool ascii, + const QString& out_path, + const GpgOperationCallback& cb) { + auto ex = std::make_shared<GFDataExchanger>(kDataExchangerSize); + + RunGpgOperaAsync( + [=](const DataObjectPtr& data_object) -> GpgError { + GpgError err; + std::vector<gpgme_key_t> recipients(keys.begin(), keys.end()); + + // Last entry data_in array has to be nullptr + recipients.emplace_back(nullptr); + + GpgBasicOperator::GetInstance().SetSigners(signer_keys, ascii); + + GpgData data_in(ex); + GpgData data_out(out_path, false); + + auto* ctx = ascii ? ctx_.DefaultContext() : ctx_.BinaryContext(); + err = CheckGpgError(gpgme_op_encrypt_sign(ctx, recipients.data(), + GPGME_ENCRYPT_ALWAYS_TRUST, + data_in, data_out)); + + data_object->Swap({ + GpgEncryptResult(gpgme_op_encrypt_result(ctx)), + GpgSignResult(gpgme_op_sign_result(ctx)), + }); + return err; + }, + cb, "gpgme_op_encrypt_sign", "2.1.0"); + + ArchiveFileOperator::NewArchive2DataExchanger( + in_path, ex, [=](GFError err, const DataObjectPtr&) { + GF_CORE_LOG_DEBUG("new archive 2 fd operation, err: {}", err); + }); } -unsigned int GpgFrontend::GpgFileOpera::EncryptFileSymmetric( - const std::string& in_path, const std::string& out_path, - GpgFrontend::GpgEncrResult& result, int _channel) { -#ifdef WINDOWS - auto in_path_std = - std::filesystem::path(QString::fromStdString(in_path).toStdU16String()); - auto out_path_std = - std::filesystem::path(QString::fromStdString(out_path).toStdU16String()); -#else - auto in_path_std = std::filesystem::path(in_path); - auto out_path_std = std::filesystem::path(out_path); -#endif - - std::string in_buffer; - if (!FileOperator::ReadFileStd(in_path_std, in_buffer)) { - throw std::runtime_error("read file error"); - } - - std::unique_ptr<std::string> out_buffer; - auto err = GpgBasicOperator::GetInstance(_channel).EncryptSymmetric( - in_buffer, out_buffer, result); - - if (check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR) - if (!FileOperator::WriteFileStd(out_path_std, *out_buffer)) { - throw std::runtime_error("write_buffer_to_file error"); - }; - - return err; + +void GpgFileOpera::DecryptVerifyFile(const QString& in_path, + const QString& out_path, + const GpgOperationCallback& cb) { + RunGpgOperaAsync( + [=](const DataObjectPtr& data_object) -> GpgError { + GpgError err; + + GpgData data_in(in_path, true); + GpgData data_out(out_path, false); + + err = CheckGpgError( + gpgme_op_decrypt_verify(ctx_.DefaultContext(), data_in, data_out)); + + data_object->Swap({ + GpgDecryptResult(gpgme_op_decrypt_result(ctx_.DefaultContext())), + GpgVerifyResult(gpgme_op_verify_result(ctx_.DefaultContext())), + }); + + return err; + }, + cb, "gpgme_op_decrypt_verify", "2.1.0"); +} + +void GpgFileOpera::DecryptVerifyArchive(const QString& in_path, + const QString& out_path, + const GpgOperationCallback& cb) { + auto ex = std::make_shared<GFDataExchanger>(kDataExchangerSize); + + ArchiveFileOperator::ExtractArchiveFromDataExchanger( + ex, out_path, [](GFError err, const DataObjectPtr&) { + GF_CORE_LOG_DEBUG("extract archive from ex operation, err: {}", err); + }); + + RunGpgOperaAsync( + [=](const DataObjectPtr& data_object) -> GpgError { + GpgError err; + + GpgData data_in(in_path, true); + GpgData data_out(ex); + + err = CheckGpgError( + gpgme_op_decrypt_verify(ctx_.DefaultContext(), data_in, data_out)); + + data_object->Swap({ + GpgDecryptResult(gpgme_op_decrypt_result(ctx_.DefaultContext())), + GpgVerifyResult(gpgme_op_verify_result(ctx_.DefaultContext())), + }); + + return err; + }, + cb, "gpgme_op_decrypt_verify", "2.1.0"); +} + +void GpgFileOpera::EncryptFileSymmetric(const QString& in_path, bool ascii, + const QString& out_path, + const GpgOperationCallback& cb) { + RunGpgOperaAsync( + [=](const DataObjectPtr& data_object) -> GpgError { + GpgData data_in(in_path, true); + GpgData data_out(out_path, false); + + auto* ctx = ascii ? ctx_.DefaultContext() : ctx_.BinaryContext(); + auto err = CheckGpgError(gpgme_op_encrypt( + ctx, nullptr, GPGME_ENCRYPT_SYMMETRIC, data_in, data_out)); + data_object->Swap({ + GpgEncryptResult(gpgme_op_encrypt_result(ctx)), + }); + + return err; + }, + cb, "gpgme_op_encrypt_symmetric", "2.1.0"); +} + +void GpgFileOpera::EncryptDerectorySymmetric(const QString& in_path, bool ascii, + const QString& out_path, + const GpgOperationCallback& cb) { + auto ex = std::make_shared<GFDataExchanger>(kDataExchangerSize); + + RunGpgOperaAsync( + [=](const DataObjectPtr& data_object) -> GpgError { + GpgData data_in(ex); + GpgData data_out(out_path, false); + + auto* ctx = ascii ? ctx_.DefaultContext() : ctx_.BinaryContext(); + auto err = CheckGpgError(gpgme_op_encrypt( + ctx, nullptr, GPGME_ENCRYPT_SYMMETRIC, data_in, data_out)); + data_object->Swap({ + GpgEncryptResult(gpgme_op_encrypt_result(ctx)), + }); + + return err; + }, + cb, "gpgme_op_encrypt_symmetric", "2.1.0"); + + ArchiveFileOperator::NewArchive2DataExchanger( + in_path, ex, [=](GFError err, const DataObjectPtr&) { + GF_CORE_LOG_DEBUG("new archive 2 fd operation, err: {}", err); + }); } +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/function/gpg/GpgFileOpera.h b/src/core/function/gpg/GpgFileOpera.h index dc81bc53..b015ebe9 100644 --- a/src/core/function/gpg/GpgFileOpera.h +++ b/src/core/function/gpg/GpgFileOpera.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,59 +20,87 @@ * 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. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPGFRONTEND_GPGFILEOPERA_H -#define GPGFRONTEND_GPGFILEOPERA_H +#pragma once -#include "core/GpgConstants.h" -#include "core/GpgContext.h" -#include "core/GpgModel.h" +#include "core/function/basic/GpgFunctionObject.h" +#include "core/function/gpg/GpgContext.h" +#include "core/function/result_analyse/GpgResultAnalyse.h" +#include "core/typedef/GpgTypedef.h" namespace GpgFrontend { /** - * @brief Executive files related to the basic operations that are provided by - * GpgBasicOperator + * @brief Executive files related to the basic operations of GPG + * * @class class: GpgBasicOperator */ class GPGFRONTEND_CORE_EXPORT GpgFileOpera : public SingletonFunctionObject<GpgFileOpera> { public: + /** + * @brief Construct a new Gpg File Opera object + * + * @param channel + */ explicit GpgFileOpera( int channel = SingletonFunctionObject::GetDefaultChannel()); /** - * @brief Encrypted file + * @brief Encrypted file with public key * * @param keys Used public key * @param in_path The path where the enter file is located * @param out_path The path where the output file is located * @param result Encrypted results - * @param _channel Channel in context + * @param channel Channel in context * @return unsigned int error code */ - static unsigned int EncryptFile(KeyListPtr keys, const std::string& in_path, - const std::string& out_path, - GpgEncrResult& result, - int _channel = GPGFRONTEND_DEFAULT_CHANNEL); + void EncryptFile(KeyArgsList keys, const QString& in_path, bool ascii, + const QString& out_path, const GpgOperationCallback& cb); + + /** + * @brief + * + * @param keys + * @param in_path + * @param ascii + * @param out_path + * @param cb + */ + void EncryptDirectory(KeyArgsList keys, const QString& in_path, bool ascii, + const QString& out_path, + const GpgOperationCallback& cb); /** - * @brief 运用对称加密算法加密文件 + * @brief Encrypted file symmetrically (with password) * * @param in_path * @param out_path * @param result - * @param _channel + * @param channel * @return unsigned int */ - static unsigned int EncryptFileSymmetric( - const std::string& in_path, const std::string& out_path, - GpgEncrResult& result, int _channel = GPGFRONTEND_DEFAULT_CHANNEL); + void EncryptFileSymmetric(const QString& in_path, bool ascii, + const QString& out_path, + const GpgOperationCallback& cb); + + /** + * @brief + * + * @param in_path + * @param ascii + * @param out_path + * @param cb + */ + void EncryptDerectorySymmetric(const QString& in_path, bool ascii, + const QString& out_path, + const GpgOperationCallback& cb); /** * @brief @@ -82,37 +110,43 @@ class GPGFRONTEND_CORE_EXPORT GpgFileOpera * @param result * @return GpgError */ - static GpgError DecryptFile(const std::string& in_path, - const std::string& out_path, - GpgDecrResult& result); + void DecryptFile(const QString& in_path, const QString& out_path, + const GpgOperationCallback& cb); /** * @brief * + * @param in_path + * @param out_path + * @param cb + */ + void DecryptArchive(const QString& in_path, const QString& out_path, + const GpgOperationCallback& cb); + + /** + * @brief Sign file with private key + * * @param keys * @param in_path * @param out_path * @param result - * @param _channel + * @param channel * @return GpgError */ - static GpgError SignFile(KeyListPtr keys, const std::string& in_path, - const std::string& out_path, GpgSignResult& result, - int _channel = GPGFRONTEND_DEFAULT_CHANNEL); + void SignFile(KeyArgsList keys, const QString& in_path, bool ascii, + const QString& out_path, const GpgOperationCallback& cb); /** - * @brief + * @brief Verify file with public key * - * @param data_path - * @param sign_path - * @param result - * @param _channel + * @param data_path The path where the enter file is located + * @param sign_path The path where the signature file is located + * @param result Verify results + * @param channel Channel in context * @return GpgError */ - static GpgError VerifyFile(const std::string& data_path, - const std::string& sign_path, - GpgVerifyResult& result, - int _channel = GPGFRONTEND_DEFAULT_CHANNEL); + void VerifyFile(const QString& data_path, const QString& sign_path, + const GpgOperationCallback& cb); /** * @brief @@ -120,18 +154,28 @@ class GPGFRONTEND_CORE_EXPORT GpgFileOpera * @param keys * @param signer_keys * @param in_path + * @param ascii * @param out_path - * @param encr_res - * @param sign_res - * @param _channel - * @return GpgError + * @param cb */ - static GpgError EncryptSignFile(KeyListPtr keys, KeyListPtr signer_keys, - const std::string& in_path, - const std::string& out_path, - GpgEncrResult& encr_res, - GpgSignResult& sign_res, - int _channel = GPGFRONTEND_DEFAULT_CHANNEL); + void EncryptSignFile(KeyArgsList keys, KeyArgsList signer_keys, + const QString& in_path, bool ascii, + const QString& out_path, const GpgOperationCallback& cb); + + /** + * @brief + * + * @param keys + * @param signer_keys + * @param in_path + * @param ascii + * @param out_path + * @param cb + */ + void EncryptSignDirectory(KeyArgsList keys, KeyArgsList signer_keys, + const QString& in_path, bool ascii, + const QString& out_path, + const GpgOperationCallback& cb); /** * @brief @@ -142,12 +186,22 @@ class GPGFRONTEND_CORE_EXPORT GpgFileOpera * @param verify_res * @return GpgError */ - static GpgError DecryptVerifyFile(const std::string& in_path, - const std::string& out_path, - GpgDecrResult& decr_res, - GpgVerifyResult& verify_res); + void DecryptVerifyFile(const QString& in_path, const QString& out_path, + const GpgOperationCallback& cb); + + /** + * @brief + * + * @param in_path + * @param out_path + * @param cb + */ + void DecryptVerifyArchive(const QString& in_path, const QString& out_path, + const GpgOperationCallback& cb); + + private: + GpgContext& ctx_ = GpgContext::GetInstance( + SingletonFunctionObject::GetChannel()); ///< Corresponding context }; } // namespace GpgFrontend - -#endif // GPGFRONTEND_GPGFILEOPERA_H diff --git a/src/core/function/gpg/GpgKeyGetter.cpp b/src/core/function/gpg/GpgKeyGetter.cpp index ee6d2b09..e22979d7 100644 --- a/src/core/function/gpg/GpgKeyGetter.cpp +++ b/src/core/function/gpg/GpgKeyGetter.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,7 +20,7 @@ * 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. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * @@ -32,136 +32,212 @@ #include <mutex> #include <shared_mutex> -#include <utility> -#include "GpgConstants.h" -#include "model/GpgKey.h" +#include "core/GpgModel.h" +#include "core/function/gpg/GpgContext.h" +#include "core/utils/GpgUtils.h" -GpgFrontend::GpgKeyGetter::GpgKeyGetter(int channel) - : SingletonFunctionObject<GpgKeyGetter>(channel) { - SPDLOG_DEBUG("called channel: {}", channel); -} +namespace GpgFrontend { -GpgFrontend::GpgKey GpgFrontend::GpgKeyGetter::GetKey(const std::string& fpr, - bool use_cache) { - // find in cache first - if (use_cache) { - auto key = get_key_in_cache(fpr); - if (key.IsGood()) return key; +class GpgKeyGetter::Impl : public SingletonFunctionObject<GpgKeyGetter::Impl> { + public: + explicit Impl(int channel) + : SingletonFunctionObject<GpgKeyGetter::Impl>(channel) { + GF_CORE_LOG_DEBUG("called channel: {}", channel); } - gpgme_key_t _p_key = nullptr; - gpgme_get_key(ctx_, fpr.c_str(), &_p_key, 1); - if (_p_key == nullptr) { - SPDLOG_WARN("GpgKeyGetter GetKey Private _p_key Null fpr", fpr); - return GetPubkey(fpr); - } else { - return GpgKey(std::move(_p_key)); - } -} + auto GetKey(const QString& fpr, bool use_cache) -> GpgKey { + // find in cache first + if (use_cache) { + auto key = get_key_in_cache(fpr); + if (key.IsGood()) return key; + } -GpgFrontend::GpgKey GpgFrontend::GpgKeyGetter::GetPubkey(const std::string& fpr, - bool use_cache) { - // find in cache first - if (use_cache) { - auto key = get_key_in_cache(fpr); - if (key.IsGood()) return key; + gpgme_key_t p_key = nullptr; + gpgme_get_key(ctx_.DefaultContext(), fpr.toUtf8(), &p_key, 1); + if (p_key == nullptr) { + GF_CORE_LOG_WARN("GpgKeyGetter GetKey Private _p_key Null fpr", fpr); + return GetPubkey(fpr, true); + } + return GpgKey(std::move(p_key)); } - gpgme_key_t _p_key = nullptr; - gpgme_get_key(ctx_, fpr.c_str(), &_p_key, 0); - if (_p_key == nullptr) SPDLOG_WARN("GpgKeyGetter GetKey _p_key Null", fpr); - return GpgKey(std::move(_p_key)); -} + auto GetPubkey(const QString& fpr, bool use_cache) -> GpgKey { + // find in cache first + if (use_cache) { + auto key = get_key_in_cache(fpr); + if (key.IsGood()) return key; + } -GpgFrontend::KeyLinkListPtr GpgFrontend::GpgKeyGetter::FetchKey() { - // get the lock - std::lock_guard<std::mutex> lock(keys_cache_mutex_); + gpgme_key_t p_key = nullptr; + gpgme_get_key(ctx_.DefaultContext(), fpr.toUtf8(), &p_key, 0); + if (p_key == nullptr) + GF_CORE_LOG_WARN("GpgKeyGetter GetKey _p_key Null", fpr); + return GpgKey(std::move(p_key)); + } - auto keys_list = std::make_unique<GpgKeyLinkList>(); + auto FetchKey() -> KeyLinkListPtr { + if (keys_cache_.empty()) { + FlushKeyCache(); + } - for (const auto& [key, value] : keys_cache_) { - keys_list->push_back(value.Copy()); + auto keys_list = std::make_unique<GpgKeyLinkList>(); + + { + // get the lock + std::lock_guard<std::mutex> lock(keys_cache_mutex_); + for (const auto& [key, value] : keys_cache_) { + keys_list->push_back(value); + } + } + return keys_list; } - return keys_list; -} -void GpgFrontend::GpgKeyGetter::FlushKeyCache() { - SPDLOG_DEBUG("called channel id: {}", GetChannel()); + auto FlushKeyCache() -> bool { + GF_CORE_LOG_DEBUG("flush key channel called, channel: {}", GetChannel()); - // clear the keys cache - keys_cache_.clear(); + // clear the keys cache + keys_cache_.clear(); - // init - GpgError err = gpgme_op_keylist_start(ctx_, nullptr, 0); + // init + GpgError err = gpgme_op_keylist_start(ctx_.DefaultContext(), nullptr, 0); - // for debug - assert(check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR); + // for debug + assert(CheckGpgError(err) == GPG_ERR_NO_ERROR); - // return when error - if (check_gpg_error_2_err_code(err) != GPG_ERR_NO_ERROR) return; + // return when error + if (CheckGpgError(err) != GPG_ERR_NO_ERROR) return false; - { - // get the lock - std::lock_guard<std::mutex> lock(keys_cache_mutex_); - gpgme_key_t key; - while ((err = gpgme_op_keylist_next(ctx_, &key)) == GPG_ERR_NO_ERROR) { - auto gpg_key = GpgKey(std::move(key)); - - // detect if the key is in a smartcard - // if so, try to get full information using gpgme_get_key() - // this maybe a bug in gpgme - if (gpg_key.IsHasCardKey()) { - gpg_key = GetKey(gpg_key.GetId(), false); + { + // get the lock + std::lock_guard<std::mutex> lock(keys_cache_mutex_); + gpgme_key_t key; + while ((err = gpgme_op_keylist_next(ctx_.DefaultContext(), &key)) == + GPG_ERR_NO_ERROR) { + auto gpg_key = GpgKey(std::move(key)); + + // detect if the key is in a smartcard + // if so, try to get full information using gpgme_get_key() + // this maybe a bug in gpgme + if (gpg_key.IsHasCardKey()) { + gpg_key = GetKey(gpg_key.GetId(), false); + } + + keys_cache_.insert({gpg_key.GetId(), std::move(gpg_key)}); } + } + + GF_CORE_LOG_DEBUG("flush key channel cache address: {} object address: {}", + static_cast<void*>(&keys_cache_), + static_cast<void*>(this)); + + // for debug + assert(CheckGpgError2ErrCode(err, GPG_ERR_EOF) == GPG_ERR_EOF); + + err = gpgme_op_keylist_end(ctx_.DefaultContext()); + assert(CheckGpgError2ErrCode(err, GPG_ERR_EOF) == GPG_ERR_NO_ERROR); - keys_cache_.insert({gpg_key.GetId(), std::move(gpg_key)}); + GF_CORE_LOG_DEBUG("flush key channel done, channel: {}", GetChannel()); + return true; + } + + auto GetKeys(const KeyIdArgsListPtr& ids) -> KeyListPtr { + auto keys = std::make_unique<KeyArgsList>(); + for (const auto& key_id : *ids) keys->emplace_back(GetKey(key_id, true)); + return keys; + } + + auto GetKeysCopy(const KeyLinkListPtr& keys) -> KeyLinkListPtr { + // get the lock + std::lock_guard<std::mutex> lock(ctx_mutex_); + auto keys_copy = std::make_unique<GpgKeyLinkList>(); + for (const auto& key : *keys) keys_copy->emplace_back(key); + return keys_copy; + } + + auto GetKeysCopy(const KeyListPtr& keys) -> KeyListPtr { + // get the lock + std::lock_guard<std::mutex> lock(ctx_mutex_); + auto keys_copy = std::make_unique<KeyArgsList>(); + for (const auto& key : *keys) keys_copy->emplace_back(key); + return keys_copy; + } + + private: + /** + * @brief Get the gpgme context object + * + */ + GpgContext& ctx_ = + GpgContext::GetInstance(SingletonFunctionObject::GetChannel()); + + /** + * @brief shared mutex for the keys cache + * + */ + mutable std::mutex ctx_mutex_; + + /** + * @brief cache the keys with key id + * + */ + std::map<QString, GpgKey> keys_cache_; + + /** + * @brief shared mutex for the keys cache + * + */ + mutable std::mutex keys_cache_mutex_; + + /** + * @brief Get the Key object + * + * @param id + * @return GpgKey + */ + auto get_key_in_cache(const QString& key_id) -> GpgKey { + std::lock_guard<std::mutex> lock(keys_cache_mutex_); + if (keys_cache_.find(key_id) != keys_cache_.end()) { + std::lock_guard<std::mutex> lock(ctx_mutex_); + // return a copy of the key in cache + return keys_cache_[key_id]; } + + // return a bad key + return {}; } +}; - SPDLOG_DEBUG("cache address: {} object address: {}", - static_cast<void*>(&keys_cache_), static_cast<void*>(this)); +GpgKeyGetter::GpgKeyGetter(int channel) + : SingletonFunctionObject<GpgKeyGetter>(channel), + p_(SecureCreateUniqueObject<Impl>(channel)) { + GF_CORE_LOG_DEBUG("called channel: {}", channel); +} - // for debug - assert(check_gpg_error_2_err_code(err, GPG_ERR_EOF) == GPG_ERR_EOF); +GpgKeyGetter::~GpgKeyGetter() = default; - err = gpgme_op_keylist_end(ctx_); - assert(check_gpg_error_2_err_code(err, GPG_ERR_EOF) == GPG_ERR_NO_ERROR); +auto GpgKeyGetter::GetKey(const QString& key_id, bool use_cache) -> GpgKey { + return p_->GetKey(key_id, use_cache); } -GpgFrontend::KeyListPtr GpgFrontend::GpgKeyGetter::GetKeys( - const KeyIdArgsListPtr& ids) { - auto keys = std::make_unique<KeyArgsList>(); - for (const auto& id : *ids) keys->emplace_back(GetKey(id)); - return keys; +auto GpgKeyGetter::GetPubkey(const QString& key_id, bool use_cache) -> GpgKey { + return p_->GetPubkey(key_id, use_cache); } -GpgFrontend::KeyLinkListPtr GpgFrontend::GpgKeyGetter::GetKeysCopy( - const GpgFrontend::KeyLinkListPtr& keys) { - // get the lock - std::lock_guard<std::mutex> lock(ctx_mutex_); - auto keys_copy = std::make_unique<GpgKeyLinkList>(); - for (const auto& key : *keys) keys_copy->emplace_back(key.Copy()); - return keys_copy; +auto GpgKeyGetter::FlushKeyCache() -> bool { return p_->FlushKeyCache(); } + +auto GpgKeyGetter::GetKeys(const KeyIdArgsListPtr& ids) -> KeyListPtr { + return p_->GetKeys(ids); } -GpgFrontend::KeyListPtr GpgFrontend::GpgKeyGetter::GetKeysCopy( - const GpgFrontend::KeyListPtr& keys) { - // get the lock - std::lock_guard<std::mutex> lock(ctx_mutex_); - auto keys_copy = std::make_unique<KeyArgsList>(); - for (const auto& key : *keys) keys_copy->emplace_back(key.Copy()); - return keys_copy; +auto GpgKeyGetter::GetKeysCopy(const KeyLinkListPtr& keys) -> KeyLinkListPtr { + return p_->GetKeysCopy(keys); } -GpgFrontend::GpgKey GpgFrontend::GpgKeyGetter::get_key_in_cache( - const std::string& id) { - std::lock_guard<std::mutex> lock(keys_cache_mutex_); - if (keys_cache_.find(id) != keys_cache_.end()) { - std::lock_guard<std::mutex> lock(ctx_mutex_); - // return a copy of the key in cache - return keys_cache_[id].Copy(); - } - // return a bad key - return GpgKey(); +auto GpgKeyGetter::GetKeysCopy(const KeyListPtr& keys) -> KeyListPtr { + return p_->GetKeysCopy(keys); } + +auto GpgKeyGetter::FetchKey() -> KeyLinkListPtr { return p_->FetchKey(); } + +} // namespace GpgFrontend diff --git a/src/core/function/gpg/GpgKeyGetter.h b/src/core/function/gpg/GpgKeyGetter.h index c96dbea7..91138623 100644 --- a/src/core/function/gpg/GpgKeyGetter.h +++ b/src/core/function/gpg/GpgKeyGetter.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,21 +20,16 @@ * 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. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPGFRONTEND_ZH_CN_TS_GPGKEYGETTER_H -#define GPGFRONTEND_ZH_CN_TS_GPGKEYGETTER_H +#pragma once -#include <mutex> -#include <vector> - -#include "core/GpgContext.h" -#include "core/GpgFunctionObject.h" -#include "core/GpgModel.h" +#include "core/function/basic/GpgFunctionObject.h" +#include "core/typedef/GpgTypedef.h" namespace GpgFrontend { @@ -50,8 +45,13 @@ class GPGFRONTEND_CORE_EXPORT GpgKeyGetter * * @param channel */ - explicit GpgKeyGetter( - int channel = SingletonFunctionObject::GetDefaultChannel()); + explicit GpgKeyGetter(int channel = kGpgFrontendDefaultChannel); + + /** + * @brief Destroy the Gpg Key Getter object + * + */ + ~GpgKeyGetter(); /** * @brief Get the Key object @@ -59,7 +59,7 @@ class GPGFRONTEND_CORE_EXPORT GpgKeyGetter * @param fpr * @return GpgKey */ - GpgKey GetKey(const std::string& id, bool use_cache = true); + auto GetKey(const QString& key_id, bool use_cache = true) -> GpgKey; /** * @brief Get the Keys object @@ -67,7 +67,7 @@ class GPGFRONTEND_CORE_EXPORT GpgKeyGetter * @param ids * @return KeyListPtr */ - KeyListPtr GetKeys(const KeyIdArgsListPtr& ids); + auto GetKeys(const KeyIdArgsListPtr& key_ids) -> KeyListPtr; /** * @brief Get the Pubkey object @@ -75,20 +75,20 @@ class GPGFRONTEND_CORE_EXPORT GpgKeyGetter * @param fpr * @return GpgKey */ - GpgKey GetPubkey(const std::string& id, bool use_cache = true); + auto GetPubkey(const QString& key_id, bool use_cache = true) -> GpgKey; /** * @brief Get all the keys by receiving a linked list * * @return KeyLinkListPtr */ - KeyLinkListPtr FetchKey(); + auto FetchKey() -> KeyLinkListPtr; /** * @brief flush the keys in the cache * */ - void FlushKeyCache(); + auto FlushKeyCache() -> bool; /** * @brief Get the Keys Copy object @@ -96,7 +96,7 @@ class GPGFRONTEND_CORE_EXPORT GpgKeyGetter * @param keys * @return KeyListPtr */ - KeyListPtr GetKeysCopy(const KeyListPtr& keys); + auto GetKeysCopy(const KeyListPtr& keys) -> KeyListPtr; /** * @brief Get the Keys Copy object @@ -104,42 +104,10 @@ class GPGFRONTEND_CORE_EXPORT GpgKeyGetter * @param keys * @return KeyLinkListPtr */ - KeyLinkListPtr GetKeysCopy(const KeyLinkListPtr& keys); + auto GetKeysCopy(const KeyLinkListPtr& keys) -> KeyLinkListPtr; private: - /** - * @brief Get the gpgme context object - * - */ - GpgContext& ctx_ = - GpgContext::GetInstance(SingletonFunctionObject::GetChannel()); - - /** - * @brief shared mutex for the keys cache - * - */ - mutable std::mutex ctx_mutex_; - - /** - * @brief cache the keys with key id - * - */ - std::map<std::string, GpgKey> keys_cache_; - - /** - * @brief shared mutex for the keys cache - * - */ - mutable std::mutex keys_cache_mutex_; - - /** - * @brief Get the Key object - * - * @param id - * @return GpgKey - */ - GpgKey get_key_in_cache(const std::string& id); + class Impl; + SecureUniquePtr<Impl> p_; }; } // namespace GpgFrontend - -#endif // GPGFRONTEND_ZH_CN_TS_GPGKEYGETTER_H diff --git a/src/core/function/gpg/GpgKeyImportExporter.cpp b/src/core/function/gpg/GpgKeyImportExporter.cpp index 01349c94..09b51359 100644 --- a/src/core/function/gpg/GpgKeyImportExporter.cpp +++ b/src/core/function/gpg/GpgKeyImportExporter.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,7 +20,7 @@ * 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. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * @@ -28,79 +28,76 @@ #include "GpgKeyImportExporter.h" -#include <memory> +#include "core/GpgModel.h" +#include "core/model/GpgImportInformation.h" +#include "core/utils/AsyncUtils.h" +#include "core/utils/GpgUtils.h" -#include "GpgConstants.h" -#include "GpgKeyGetter.h" +namespace GpgFrontend { -GpgFrontend::GpgKeyImportExporter::GpgKeyImportExporter(int channel) - : SingletonFunctionObject<GpgKeyImportExporter>(channel) {} +GpgKeyImportExporter::GpgKeyImportExporter(int channel) + : SingletonFunctionObject<GpgKeyImportExporter>(channel), + ctx_(GpgContext::GetInstance(SingletonFunctionObject::GetChannel())) {} /** * Import key pair * @param inBuffer input byte array * @return Import information */ -GpgFrontend::GpgImportInformation GpgFrontend::GpgKeyImportExporter::ImportKey( - StdBypeArrayPtr in_buffer) { - if (in_buffer->empty()) return {}; +auto GpgKeyImportExporter::ImportKey(const GFBuffer& in_buffer) + -> std::shared_ptr<GpgImportInformation> { + if (in_buffer.Empty()) return {}; - GpgData data_in(in_buffer->data(), in_buffer->size()); - auto err = check_gpg_error(gpgme_op_import(ctx_, data_in)); + GpgData data_in(in_buffer); + auto err = CheckGpgError(gpgme_op_import(ctx_.DefaultContext(), data_in)); if (gpgme_err_code(err) != GPG_ERR_NO_ERROR) return {}; gpgme_import_result_t result; - result = gpgme_op_import_result(ctx_); + result = gpgme_op_import_result(ctx_.DefaultContext()); gpgme_import_status_t status = result->imports; - auto import_info = std::make_unique<GpgImportInformation>(result); + auto import_info = SecureCreateSharedObject<GpgImportInformation>(result); while (status != nullptr) { - GpgImportedKey key; + GpgImportInformation::GpgImportedKey key; key.import_status = static_cast<int>(status->status); key.fpr = status->fpr; - import_info->importedKeys.emplace_back(key); + import_info->imported_keys.emplace_back(key); status = status->next; } - return *import_info; + return import_info; } /** - * Export Key - * @param uid_list key ids - * @param out_buffer output byte array + * Export keys + * @param keys keys used + * @param outBuffer output byte array * @return if success */ -bool GpgFrontend::GpgKeyImportExporter::ExportKeys(KeyIdArgsListPtr& uid_list, - ByteArrayPtr& out_buffer, - bool secret) const { - if (uid_list->empty()) return false; +auto GpgKeyImportExporter::ExportKey(const GpgKey& key, bool secret, bool ascii, + bool shortest, bool ssh_mode) const + -> std::tuple<GpgError, GFBuffer> { + if (!key.IsGood()) return {GPG_ERR_CANCELED, {}}; - int _mode = 0; - if (secret) _mode |= GPGME_EXPORT_MODE_SECRET; + int mode = 0; + if (secret) mode |= GPGME_EXPORT_MODE_SECRET; + if (shortest) mode |= GPGME_EXPORT_MODE_MINIMAL; + if (ssh_mode) mode |= GPGME_EXPORT_MODE_SSH; - auto keys = GpgKeyGetter::GetInstance().GetKeys(uid_list); - auto keys_array = new gpgme_key_t[keys->size() + 1]; + std::vector<gpgme_key_t> keys_array; - int index = 0; - for (const auto& key : *keys) { - keys_array[index++] = gpgme_key_t(key); - } - keys_array[index] = nullptr; + // Last entry data_in array has to be nullptr + keys_array.emplace_back(key); + keys_array.emplace_back(nullptr); GpgData data_out; - auto err = gpgme_op_export_keys(ctx_, keys_array, _mode, data_out); - if (gpgme_err_code(err) != GPG_ERR_NO_ERROR) return false; - - delete[] keys_array; - - SPDLOG_DEBUG("export keys read_bytes: {}", - gpgme_data_seek(data_out, 0, SEEK_END)); - - auto temp_out_buffer = data_out.Read2Buffer(); - - swap(temp_out_buffer, out_buffer); + auto* ctx = ascii ? ctx_.DefaultContext() : ctx_.BinaryContext(); + auto err = gpgme_op_export_keys(ctx, keys_array.data(), mode, data_out); + if (gpgme_err_code(err) != GPG_ERR_NO_ERROR) return {}; - return true; + GF_CORE_LOG_DEBUG( + "operation of exporting a key finished, ascii: {}, read_bytes: {}", ascii, + gpgme_data_seek(data_out, 0, SEEK_END)); + return {err, data_out.Read2GFBuffer()}; } /** @@ -109,114 +106,36 @@ bool GpgFrontend::GpgKeyImportExporter::ExportKeys(KeyIdArgsListPtr& uid_list, * @param outBuffer output byte array * @return if success */ -bool GpgFrontend::GpgKeyImportExporter::ExportKeys(const KeyArgsList& keys, - ByteArrayPtr& out_buffer, - bool secret) const { - KeyIdArgsListPtr key_ids = std::make_unique<std::vector<std::string>>(); - for (const auto& key : keys) key_ids->push_back(key.GetId()); - return ExportKeys(key_ids, out_buffer, secret); +void GpgKeyImportExporter::ExportKeys(const KeyArgsList& keys, bool secret, + bool ascii, bool shortest, bool ssh_mode, + const GpgOperationCallback& cb) const { + RunGpgOperaAsync( + [=](const DataObjectPtr& data_object) -> GpgError { + if (keys.empty()) return GPG_ERR_CANCELED; + + int mode = 0; + if (secret) mode |= GPGME_EXPORT_MODE_SECRET; + if (shortest) mode |= GPGME_EXPORT_MODE_MINIMAL; + if (ssh_mode) mode |= GPGME_EXPORT_MODE_SSH; + + std::vector<gpgme_key_t> keys_array(keys.begin(), keys.end()); + + // Last entry data_in array has to be nullptr + keys_array.emplace_back(nullptr); + + GpgData data_out; + auto* ctx = ascii ? ctx_.DefaultContext() : ctx_.BinaryContext(); + auto err = gpgme_op_export_keys(ctx, keys_array.data(), mode, data_out); + if (gpgme_err_code(err) != GPG_ERR_NO_ERROR) return {}; + + GF_CORE_LOG_DEBUG( + "operation of exporting keys finished, ascii: {}, read_bytes: {}", + ascii, gpgme_data_seek(data_out, 0, SEEK_END)); + + data_object->Swap({data_out.Read2GFBuffer()}); + return err; + }, + cb, "gpgme_op_export_keys", "2.1.0"); } -/** - * Export all the keys both private and public keys - * @param uid_list key ids - * @param out_buffer output byte array - * @return if success - */ -bool GpgFrontend::GpgKeyImportExporter::ExportAllKeys( - KeyIdArgsListPtr& uid_list, ByteArrayPtr& out_buffer, bool secret) const { - bool result = true; - result = ExportKeys(uid_list, out_buffer, false) & result; - - ByteArrayPtr temp_buffer; - if (secret) { - result = ExportKeys(uid_list, temp_buffer, true) & result; - } - out_buffer->append(*temp_buffer); - return result; -} - -/** - * Export the secret key of a key pair(including subkeys) - * @param key target key pair - * @param outBuffer output byte array - * @return if successful - */ -bool GpgFrontend::GpgKeyImportExporter::ExportSecretKey( - const GpgKey& key, ByteArrayPtr& out_buffer) const { - SPDLOG_DEBUG("export secret key: {}", key.GetId().c_str()); - - gpgme_key_t target_key[2] = {gpgme_key_t(key), nullptr}; - - GpgData data_out; - // export private key to outBuffer - gpgme_error_t err = gpgme_op_export_keys(ctx_, target_key, - GPGME_EXPORT_MODE_SECRET, data_out); - - auto temp_out_buffer = data_out.Read2Buffer(); - std::swap(out_buffer, temp_out_buffer); - - return check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR; -} - -bool GpgFrontend::GpgKeyImportExporter::ExportKey( - const GpgFrontend::GpgKey& key, - GpgFrontend::ByteArrayPtr& out_buffer) const { - GpgData data_out; - auto err = gpgme_op_export(ctx_, key.GetId().c_str(), 0, data_out); - - SPDLOG_DEBUG("export keys read_bytes: {}", - gpgme_data_seek(data_out, 0, SEEK_END)); - - auto temp_out_buffer = data_out.Read2Buffer(); - std::swap(out_buffer, temp_out_buffer); - return check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR; -} - -bool GpgFrontend::GpgKeyImportExporter::ExportKeyOpenSSH( - const GpgFrontend::GpgKey& key, - GpgFrontend::ByteArrayPtr& out_buffer) const { - GpgData data_out; - auto err = gpgme_op_export(ctx_, key.GetId().c_str(), GPGME_EXPORT_MODE_SSH, - data_out); - - SPDLOG_DEBUG("read_bytes: {}", gpgme_data_seek(data_out, 0, SEEK_END)); - - auto temp_out_buffer = data_out.Read2Buffer(); - std::swap(out_buffer, temp_out_buffer); - return check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR; -} - -bool GpgFrontend::GpgKeyImportExporter::ExportSecretKeyShortest( - const GpgFrontend::GpgKey& key, - GpgFrontend::ByteArrayPtr& out_buffer) const { - GpgData data_out; - auto err = gpgme_op_export(ctx_, key.GetId().c_str(), - GPGME_EXPORT_MODE_MINIMAL, data_out); - - SPDLOG_DEBUG("read_bytes: {}", gpgme_data_seek(data_out, 0, SEEK_END)); - - auto temp_out_buffer = data_out.Read2Buffer(); - std::swap(out_buffer, temp_out_buffer); - return check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR; -} - -GpgFrontend::GpgImportInformation::GpgImportInformation() = default; - -GpgFrontend::GpgImportInformation::GpgImportInformation( - gpgme_import_result_t result) { - if (result->unchanged) unchanged = result->unchanged; - if (result->considered) considered = result->considered; - if (result->no_user_id) no_user_id = result->no_user_id; - if (result->imported) imported = result->imported; - if (result->imported_rsa) imported_rsa = result->imported_rsa; - if (result->unchanged) unchanged = result->unchanged; - if (result->new_user_ids) new_user_ids = result->new_user_ids; - if (result->new_sub_keys) new_sub_keys = result->new_sub_keys; - if (result->new_signatures) new_signatures = result->new_signatures; - if (result->new_revocations) new_revocations = result->new_revocations; - if (result->secret_read) secret_read = result->secret_read; - if (result->secret_imported) secret_imported = result->secret_imported; - if (result->secret_unchanged) secret_unchanged = result->secret_unchanged; - if (result->not_imported) not_imported = result->not_imported; -} +} // namespace GpgFrontend diff --git a/src/core/function/gpg/GpgKeyImportExporter.h b/src/core/function/gpg/GpgKeyImportExporter.h index 6e90f436..14b2b2bf 100644 --- a/src/core/function/gpg/GpgKeyImportExporter.h +++ b/src/core/function/gpg/GpgKeyImportExporter.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,67 +20,22 @@ * 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. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef _GPGKEYIMPORTEXPORTOR_H -#define _GPGKEYIMPORTEXPORTOR_H +#pragma once -#include <string> - -#include "core/GpgConstants.h" -#include "core/GpgContext.h" -#include "core/GpgFunctionObject.h" -#include "core/GpgModel.h" +#include "core/function/basic/GpgFunctionObject.h" +#include "core/function/gpg/GpgContext.h" +#include "core/model/GFBuffer.h" +#include "core/typedef/GpgTypedef.h" namespace GpgFrontend { -/** - * @brief - * - */ -class GpgImportedKey { - public: - std::string fpr; ///< - int import_status; ///< -}; - -typedef std::list<GpgImportedKey> GpgImportedKeyList; ///< - -/** - * @brief - * - */ -class GPGFRONTEND_CORE_EXPORT GpgImportInformation { - public: - GpgImportInformation(); - - /** - * @brief Construct a new Gpg Import Information object - * - * @param result - */ - explicit GpgImportInformation(gpgme_import_result_t result); - - int considered = 0; ///< - int no_user_id = 0; ///< - int imported = 0; ///< - int imported_rsa = 0; ///< - int unchanged = 0; ///< - int new_user_ids = 0; ///< - int new_sub_keys = 0; ///< - int new_signatures = 0; ///< - int new_revocations = 0; ///< - int secret_read = 0; ///< - int secret_imported = 0; ///< - int secret_unchanged = 0; ///< - int not_imported = 0; ///< - - GpgImportedKeyList importedKeys; ///< -}; +class GpgImportInformation; /** * @brief @@ -103,31 +58,19 @@ class GPGFRONTEND_CORE_EXPORT GpgKeyImportExporter * @param inBuffer * @return GpgImportInformation */ - GpgImportInformation ImportKey(StdBypeArrayPtr inBuffer); + auto ImportKey(const GFBuffer&) -> std::shared_ptr<GpgImportInformation>; /** * @brief * - * @param uid_list - * @param out_buffer - * @param secret - * @return true - * @return false - */ - bool ExportKeys(KeyIdArgsListPtr& uid_list, ByteArrayPtr& out_buffer, - bool secret = false) const; - - /** - * @brief - * - * @param keys - * @param outBuffer + * @param key * @param secret - * @return true - * @return false + * @param ascii + * @return std::tuple<GpgError, GFBuffer> */ - bool ExportKeys(const KeyArgsList& keys, ByteArrayPtr& outBuffer, - bool secret = false) const; + [[nodiscard]] auto ExportKey(const GpgKey& key, bool secret, bool ascii, + bool shortest, bool ssh_mode = false) const + -> std::tuple<GpgError, GFBuffer>; /** * @brief @@ -138,55 +81,12 @@ class GPGFRONTEND_CORE_EXPORT GpgKeyImportExporter * @return true * @return false */ - bool ExportAllKeys(KeyIdArgsListPtr& uid_list, ByteArrayPtr& out_buffer, - bool secret) const; - - /** - * @brief - * - * @param key - * @param out_buffer - * @return true - * @return false - */ - bool ExportKey(const GpgKey& key, ByteArrayPtr& out_buffer) const; - - /** - * @brief - * - * @param key - * @param out_buffer - * @return true - * @return false - */ - bool ExportKeyOpenSSH(const GpgKey& key, ByteArrayPtr& out_buffer) const; - - /** - * @brief - * - * @param key - * @param outBuffer - * @return true - * @return false - */ - bool ExportSecretKey(const GpgKey& key, ByteArrayPtr& outBuffer) const; - - /** - * @brief - * - * @param key - * @param outBuffer - * @return true - * @return false - */ - bool ExportSecretKeyShortest(const GpgKey& key, - ByteArrayPtr& outBuffer) const; + void ExportKeys(const KeyArgsList& keys, bool secret, bool ascii, + bool shortest, bool ssh_mode, + const GpgOperationCallback& cb) const; private: - GpgContext& ctx_ = - GpgContext::GetInstance(SingletonFunctionObject::GetChannel()); ///< + GpgContext& ctx_; }; } // namespace GpgFrontend - -#endif // _GPGKEYIMPORTEXPORTOR_H
\ No newline at end of file diff --git a/src/core/function/gpg/GpgKeyManager.cpp b/src/core/function/gpg/GpgKeyManager.cpp index e556eec6..8d7d9a28 100644 --- a/src/core/function/gpg/GpgKeyManager.cpp +++ b/src/core/function/gpg/GpgKeyManager.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,7 +20,7 @@ * 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. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * @@ -28,150 +28,146 @@ #include "GpgKeyManager.h" -#include <boost/algorithm/string.hpp> -#include <boost/date_time/posix_time/conversion.hpp> -#include <memory> -#include <string> - -#include "GpgBasicOperator.h" -#include "GpgKeyGetter.h" -#include "spdlog/spdlog.h" +#include "core/GpgModel.h" +#include "core/function/gpg/GpgBasicOperator.h" +#include "core/function/gpg/GpgKeyGetter.h" +#include "core/utils/GpgUtils.h" GpgFrontend::GpgKeyManager::GpgKeyManager(int channel) : SingletonFunctionObject<GpgKeyManager>(channel) {} -bool GpgFrontend::GpgKeyManager::SignKey( +auto GpgFrontend::GpgKeyManager::SignKey( const GpgFrontend::GpgKey& target, GpgFrontend::KeyArgsList& keys, - const std::string& uid, - const std::unique_ptr<boost::posix_time::ptime>& expires) { - using namespace boost::posix_time; - - GpgBasicOperator::GetInstance().SetSigners(keys); + const QString& uid, const std::unique_ptr<QDateTime>& expires) -> bool { + GpgBasicOperator::GetInstance().SetSigners(keys, true); unsigned int flags = 0; unsigned int expires_time_t = 0; - if (expires == nullptr) + if (expires == nullptr) { flags |= GPGME_KEYSIGN_NOEXPIRE; - else - expires_time_t = to_time_t(*expires); + } else { + expires_time_t = expires->toSecsSinceEpoch(); + } - auto err = check_gpg_error(gpgme_op_keysign( - ctx_, gpgme_key_t(target), uid.c_str(), expires_time_t, flags)); + auto err = CheckGpgError( + gpgme_op_keysign(ctx_.DefaultContext(), static_cast<gpgme_key_t>(target), + uid.toUtf8(), expires_time_t, flags)); - return check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR; + return CheckGpgError(err) == GPG_ERR_NO_ERROR; } -bool GpgFrontend::GpgKeyManager::RevSign( +auto GpgFrontend::GpgKeyManager::RevSign( const GpgFrontend::GpgKey& key, - const GpgFrontend::SignIdArgsListPtr& signature_id) { + const GpgFrontend::SignIdArgsListPtr& signature_id) -> bool { auto& key_getter = GpgKeyGetter::GetInstance(); for (const auto& sign_id : *signature_id) { auto signing_key = key_getter.GetKey(sign_id.first); assert(signing_key.IsGood()); - auto err = check_gpg_error(gpgme_op_revsig(ctx_, gpgme_key_t(key), - gpgme_key_t(signing_key), - sign_id.second.c_str(), 0)); - if (check_gpg_error_2_err_code(err) != GPG_ERR_NO_ERROR) return false; + auto err = CheckGpgError( + gpgme_op_revsig(ctx_.DefaultContext(), gpgme_key_t(key), + gpgme_key_t(signing_key), sign_id.second.toUtf8(), 0)); + if (CheckGpgError(err) != GPG_ERR_NO_ERROR) return false; } return true; } -bool GpgFrontend::GpgKeyManager::SetExpire( - const GpgFrontend::GpgKey& key, std::unique_ptr<GpgSubKey>& subkey, - std::unique_ptr<boost::posix_time::ptime>& expires) { - using namespace boost::posix_time; - +auto GpgFrontend::GpgKeyManager::SetExpire(const GpgFrontend::GpgKey& key, + std::unique_ptr<GpgSubKey>& subkey, + std::unique_ptr<QDateTime>& expires) + -> bool { unsigned long expires_time = 0; - if (expires != nullptr) expires_time = to_time_t(ptime(*expires)); + if (expires != nullptr) expires_time = expires->toSecsSinceEpoch(); const char* sub_fprs = nullptr; - if (subkey != nullptr) sub_fprs = subkey->GetFingerprint().c_str(); + if (subkey != nullptr) sub_fprs = subkey->GetFingerprint().toUtf8(); - auto err = check_gpg_error( - gpgme_op_setexpire(ctx_, gpgme_key_t(key), expires_time, sub_fprs, 0)); + auto err = CheckGpgError(gpgme_op_setexpire(ctx_.DefaultContext(), + static_cast<gpgme_key_t>(key), + expires_time, sub_fprs, 0)); - return check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR; + return CheckGpgError(err) == GPG_ERR_NO_ERROR; } -bool GpgFrontend::GpgKeyManager::SetOwnerTrustLevel(const GpgKey& key, - int trust_level) { +auto GpgFrontend::GpgKeyManager::SetOwnerTrustLevel(const GpgKey& key, + int trust_level) -> bool { if (trust_level < 0 || trust_level > 5) { - SPDLOG_ERROR("illegal owner trust level: {}", trust_level); + GF_CORE_LOG_ERROR("illegal owner trust level: {}", trust_level); } - AutomatonNextStateHandler next_state_handler = - [](AutomatonState state, std::string status, std::string args) { - SPDLOG_DEBUG("next_state_handler state: {}, gpg_status: {}, args: {}", - state, status, args); - std::vector<std::string> tokens; - boost::split(tokens, args, boost::is_any_of(" ")); - - switch (state) { - case AS_START: - if (status == "GET_LINE" && args == "keyedit.prompt") - return AS_COMMAND; - return AS_ERROR; - case AS_COMMAND: - if (status == "GET_LINE" && args == "edit_ownertrust.value") { - return AS_VALUE; - } - return AS_ERROR; - case AS_VALUE: - if (status == "GET_LINE" && args == "keyedit.prompt") { - return AS_QUIT; - } else if (status == "GET_BOOL" && - args == "edit_ownertrust.set_ultimate.okay") { - return AS_REALLY_ULTIMATE; - } - return AS_ERROR; - case AS_REALLY_ULTIMATE: - if (status == "GET_LINE" && args == "keyedit.prompt") { - return AS_QUIT; - } - return AS_ERROR; - case AS_QUIT: - if (status == "GET_LINE" && args == "keyedit.save.okay") { - return AS_SAVE; - } - return AS_ERROR; - case AS_ERROR: - if (status == "GET_LINE" && args == "keyedit.prompt") { - return AS_QUIT; - } - return AS_ERROR; - default: - return AS_ERROR; - }; - }; + AutomatonNextStateHandler next_state_handler = [](AutomatonState state, + QString status, + QString args) { + GF_CORE_LOG_DEBUG("next_state_handler state: {}, gpg_status: {}, args: {}", + state, status, args); + auto tokens = args.split(' '); + + switch (state) { + case AS_START: + if (status == "GET_LINE" && args == "keyedit.prompt") { + return AS_COMMAND; + } + return AS_ERROR; + case AS_COMMAND: + if (status == "GET_LINE" && args == "edit_ownertrust.value") { + return AS_VALUE; + } + return AS_ERROR; + case AS_VALUE: + if (status == "GET_LINE" && args == "keyedit.prompt") { + return AS_QUIT; + } else if (status == "GET_BOOL" && + args == "edit_ownertrust.set_ultimate.okay") { + return AS_REALLY_ULTIMATE; + } + return AS_ERROR; + case AS_REALLY_ULTIMATE: + if (status == "GET_LINE" && args == "keyedit.prompt") { + return AS_QUIT; + } + return AS_ERROR; + case AS_QUIT: + if (status == "GET_LINE" && args == "keyedit.save.okay") { + return AS_SAVE; + } + return AS_ERROR; + case AS_ERROR: + if (status == "GET_LINE" && args == "keyedit.prompt") { + return AS_QUIT; + } + return AS_ERROR; + default: + return AS_ERROR; + }; + }; AutomatonActionHandler action_handler = [trust_level](AutomatonHandelStruct& handler, AutomatonState state) { - SPDLOG_DEBUG("action_handler state: {}", state); + GF_CORE_LOG_DEBUG("action_handler state: {}", state); switch (state) { case AS_COMMAND: - return std::string("trust"); + return QString("trust"); case AS_VALUE: handler.SetSuccess(true); - return std::to_string(trust_level); + return QString::number(trust_level); case AS_REALLY_ULTIMATE: handler.SetSuccess(true); - return std::string("Y"); + return QString("Y"); case AS_QUIT: - return std::string("quit"); + return QString("quit"); case AS_SAVE: handler.SetSuccess(true); - return std::string("Y"); + return QString("Y"); case AS_START: case AS_ERROR: - return std::string(""); + return QString(""); default: - return std::string(""); + return QString(""); } - return std::string(""); + return QString(""); }; auto key_fpr = key.GetFingerprint(); @@ -180,49 +176,43 @@ bool GpgFrontend::GpgKeyManager::SetOwnerTrustLevel(const GpgKey& key, GpgData data_out; - auto err = gpgme_op_interact(ctx_, gpgme_key_t(key), 0, - GpgKeyManager::interactor_cb_fnc, - (void*)&handel_struct, data_out); - if (err != GPG_ERR_NO_ERROR) { - SPDLOG_ERROR("fail to set owner trust level {} to key {}, err: {}", - trust_level, key.GetId(), gpgme_strerror(err)); - } - - return check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR && - handel_struct.Success(); + auto err = gpgme_op_interact( + ctx_.DefaultContext(), static_cast<gpgme_key_t>(key), 0, + GpgKeyManager::interactor_cb_fnc, (void*)&handel_struct, data_out); + return CheckGpgError(err) == GPG_ERR_NO_ERROR && handel_struct.Success(); } -gpgme_error_t GpgFrontend::GpgKeyManager::interactor_cb_fnc(void* handle, - const char* status, - const char* args, - int fd) { - auto handle_struct = static_cast<AutomatonHandelStruct*>(handle); - std::string status_s = status; - std::string args_s = args; - SPDLOG_DEBUG("cb start status: {}, args: {}, fd: {}, handle struct state: {}", - status_s, args_s, fd, handle_struct->CuurentStatus()); +auto GpgFrontend::GpgKeyManager::interactor_cb_fnc(void* handle, + const char* status, + const char* args, int fd) + -> gpgme_error_t { + auto* handle_struct = static_cast<AutomatonHandelStruct*>(handle); + QString status_s = status; + QString args_s = args; + GF_CORE_LOG_DEBUG( + "cb start status: {}, args: {}, fd: {}, handle struct state: {}", + status_s, args_s, fd, handle_struct->CuurentStatus()); if (status_s == "KEY_CONSIDERED") { - std::vector<std::string> tokens; - boost::split(tokens, args, boost::is_any_of(" ")); + auto tokens = QString(args).split(' '); if (tokens.empty() || tokens[0] != handle_struct->KeyFpr()) { - SPDLOG_ERROR("handle struct key fpr {} mismatch token: {}, exit...", - handle_struct->KeyFpr(), tokens[0]); + GF_CORE_LOG_ERROR("handle struct key fpr {} mismatch token: {}, exit...", + handle_struct->KeyFpr(), tokens[0]); return -1; } return 0; } - if (status_s == "GOT_IT" || status_s.empty()) { - SPDLOG_DEBUG("status GOT_IT, continue..."); + if (status_s == "GOT_IT" || status_s.isEmpty()) { + GF_CORE_LOG_DEBUG("status GOT_IT, continue..."); return 0; } AutomatonState next_state = handle_struct->NextState(status_s, args_s); if (next_state == AS_ERROR) { - SPDLOG_DEBUG("handle struct next state caught error, skipping..."); + GF_CORE_LOG_DEBUG("handle struct next state caught error, skipping..."); return GPG_ERR_FALSE; } @@ -233,10 +223,11 @@ gpgme_error_t GpgFrontend::GpgKeyManager::interactor_cb_fnc(void* handle, // set state and preform action handle_struct->SetStatus(next_state); Command cmd = handle_struct->Action(); - SPDLOG_DEBUG("handle struct action done, next state: {}, action cmd: {}", - next_state, cmd); - if (!cmd.empty()) { - gpgme_io_write(fd, cmd.c_str(), cmd.size()); + GF_CORE_LOG_DEBUG("handle struct action done, next state: {}, action cmd: {}", + next_state, cmd); + if (!cmd.isEmpty()) { + auto btye_array = cmd.toUtf8(); + gpgme_io_write(fd, btye_array, btye_array.size()); gpgme_io_write(fd, "\n", 1); } else if (status_s == "GET_LINE") { // avoid trapping in this state diff --git a/src/core/function/gpg/GpgKeyManager.h b/src/core/function/gpg/GpgKeyManager.h index 62f7baca..8b4d41b2 100644 --- a/src/core/function/gpg/GpgKeyManager.h +++ b/src/core/function/gpg/GpgKeyManager.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,21 +20,19 @@ * 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. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPGFRONTEND_ZH_CN_TS_GPGKEYMANAGER_H -#define GPGFRONTEND_ZH_CN_TS_GPGKEYMANAGER_H +#pragma once #include <functional> -#include <string> -#include "core/GpgContext.h" -#include "core/GpgFunctionObject.h" -#include "core/GpgModel.h" +#include "core/function/basic/GpgFunctionObject.h" +#include "core/function/gpg/GpgContext.h" +#include "core/typedef/GpgTypedef.h" namespace GpgFrontend { @@ -60,8 +58,8 @@ class GPGFRONTEND_CORE_EXPORT GpgKeyManager * @param expires expire date and time of the signature * @return if successful */ - bool SignKey(const GpgKey& target, KeyArgsList& keys, const std::string& uid, - const std::unique_ptr<boost::posix_time::ptime>& expires); + auto SignKey(const GpgKey& target, KeyArgsList& keys, const QString& uid, + const std::unique_ptr<QDateTime>& expires) -> bool; /** * @brief @@ -71,8 +69,8 @@ class GPGFRONTEND_CORE_EXPORT GpgKeyManager * @return true * @return false */ - bool RevSign(const GpgFrontend::GpgKey& key, - const GpgFrontend::SignIdArgsListPtr& signature_id); + auto RevSign(const GpgFrontend::GpgKey& key, + const GpgFrontend::SignIdArgsListPtr& signature_id) -> bool; /** * @brief Set the Expire object @@ -83,21 +81,21 @@ class GPGFRONTEND_CORE_EXPORT GpgKeyManager * @return true * @return false */ - bool SetExpire(const GpgKey& key, std::unique_ptr<GpgSubKey>& subkey, - std::unique_ptr<boost::posix_time::ptime>& expires); + auto SetExpire(const GpgKey& key, std::unique_ptr<GpgSubKey>& subkey, + std::unique_ptr<QDateTime>& expires) -> bool; /** * @brief * * @return */ - bool SetOwnerTrustLevel(const GpgKey& key, int trust_level); + auto SetOwnerTrustLevel(const GpgKey& key, int trust_level) -> bool; private: - static gpgme_error_t interactor_cb_fnc(void* handle, const char* status, - const char* args, int fd); + static auto interactor_cb_fnc(void* handle, const char* status, + const char* args, int fd) -> gpgme_error_t; - using Command = std::string; + using Command = QString; using AutomatonState = enum { AS_START, AS_COMMAND, @@ -113,35 +111,37 @@ class GPGFRONTEND_CORE_EXPORT GpgKeyManager using AutomatonActionHandler = std::function<Command(AutomatonHandelStruct&, AutomatonState)>; using AutomatonNextStateHandler = - std::function<AutomatonState(AutomatonState, std::string, std::string)>; + std::function<AutomatonState(AutomatonState, QString, QString)>; struct AutomatonHandelStruct { void SetStatus(AutomatonState next_state) { current_state_ = next_state; } - AutomatonState CuurentStatus() { return current_state_; } + auto CuurentStatus() -> AutomatonState { return current_state_; } void SetHandler(AutomatonNextStateHandler next_state_handler, AutomatonActionHandler action_handler) { - next_state_handler_ = next_state_handler; - action_handler_ = action_handler; + next_state_handler_ = std::move(next_state_handler); + action_handler_ = std::move(action_handler); } - AutomatonState NextState(std::string gpg_status, std::string args) { - return next_state_handler_(current_state_, gpg_status, args); + auto NextState(QString gpg_status, QString args) -> AutomatonState { + return next_state_handler_(current_state_, std::move(gpg_status), + std::move(args)); } - Command Action() { return action_handler_(*this, current_state_); } + auto Action() -> Command { return action_handler_(*this, current_state_); } void SetSuccess(bool success) { success_ = success; } - bool Success() { return success_; } + [[nodiscard]] auto Success() const -> bool { return success_; } - std::string KeyFpr() { return key_fpr_; } + auto KeyFpr() -> QString { return key_fpr_; } - AutomatonHandelStruct(std::string key_fpr) : key_fpr_(key_fpr) {} + explicit AutomatonHandelStruct(QString key_fpr) + : key_fpr_(std::move(key_fpr)) {} private: AutomatonState current_state_ = AS_START; AutomatonNextStateHandler next_state_handler_; AutomatonActionHandler action_handler_; bool success_ = false; - std::string key_fpr_; + QString key_fpr_; }; GpgContext& ctx_ = @@ -149,5 +149,3 @@ class GPGFRONTEND_CORE_EXPORT GpgKeyManager }; } // namespace GpgFrontend - -#endif // GPGFRONTEND_ZH_CN_TS_GPGKEYMANAGER_H diff --git a/src/core/function/gpg/GpgKeyOpera.cpp b/src/core/function/gpg/GpgKeyOpera.cpp index d5919cff..d9133905 100644 --- a/src/core/function/gpg/GpgKeyOpera.cpp +++ b/src/core/function/gpg/GpgKeyOpera.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,7 +20,7 @@ * 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. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * @@ -28,38 +28,42 @@ #include "GpgKeyOpera.h" -#include <boost/asio.hpp> -#include <boost/date_time/posix_time/conversion.hpp> -#include <boost/format.hpp> -#include <boost/process/async_pipe.hpp> -#include <memory> -#include <string> -#include <vector> +#include <gpg-error.h> -#include "GpgCommandExecutor.h" -#include "GpgKeyGetter.h" -#include "core/GpgConstants.h" -#include "core/GpgGenKeyInfo.h" +#include <memory> -GpgFrontend::GpgKeyOpera::GpgKeyOpera(int channel) +#include "core/GpgModel.h" +#include "core/function/gpg/GpgCommandExecutor.h" +#include "core/function/gpg/GpgKeyGetter.h" +#include "core/model/DataObject.h" +#include "core/model/GpgGenKeyInfo.h" +#include "core/model/GpgGenerateKeyResult.h" +#include "core/module/ModuleManager.h" +#include "core/typedef/GpgTypedef.h" +#include "core/utils/AsyncUtils.h" +#include "core/utils/CommonUtils.h" +#include "core/utils/GpgUtils.h" + +namespace GpgFrontend { + +GpgKeyOpera::GpgKeyOpera(int channel) : SingletonFunctionObject<GpgKeyOpera>(channel) {} /** * Delete keys * @param uidList key ids */ -void GpgFrontend::GpgKeyOpera::DeleteKeys( - GpgFrontend::KeyIdArgsListPtr key_ids) { +void GpgKeyOpera::DeleteKeys(GpgFrontend::KeyIdArgsListPtr key_ids) { GpgError err; for (const auto& tmp : *key_ids) { auto key = GpgKeyGetter::GetInstance().GetKey(tmp); if (key.IsGood()) { - err = check_gpg_error( - gpgme_op_delete_ext(ctx_, gpgme_key_t(key), - GPGME_DELETE_ALLOW_SECRET | GPGME_DELETE_FORCE)); + err = CheckGpgError(gpgme_op_delete_ext( + ctx_.DefaultContext(), static_cast<gpgme_key_t>(key), + GPGME_DELETE_ALLOW_SECRET | GPGME_DELETE_FORCE)); assert(gpg_err_code(err) == GPG_ERR_NO_ERROR); } else { - SPDLOG_WARN("GpgKeyOpera DeleteKeys get key failed", tmp); + GF_CORE_LOG_WARN("GpgKeyOpera DeleteKeys get key failed", tmp); } } } @@ -72,26 +76,24 @@ void GpgFrontend::GpgKeyOpera::DeleteKeys( * @param expires date and time * @return if successful */ -GpgFrontend::GpgError GpgFrontend::GpgKeyOpera::SetExpire( - const GpgKey& key, const SubkeyId& subkey_fpr, - std::unique_ptr<boost::posix_time::ptime>& expires) { +auto GpgKeyOpera::SetExpire(const GpgKey& key, const SubkeyId& subkey_fpr, + std::unique_ptr<QDateTime>& expires) -> GpgError { unsigned long expires_time = 0; if (expires != nullptr) { - using namespace boost::posix_time; - using namespace std::chrono; - expires_time = - to_time_t(*expires) - system_clock::to_time_t(system_clock::now()); + expires_time = QDateTime::currentDateTime().secsTo(*expires); } - SPDLOG_DEBUG(key.GetId(), subkey_fpr, expires_time); - GpgError err; - if (key.GetFingerprint() == subkey_fpr || subkey_fpr.empty()) - err = gpgme_op_setexpire(ctx_, gpgme_key_t(key), expires_time, nullptr, 0); - else - err = gpgme_op_setexpire(ctx_, gpgme_key_t(key), expires_time, - subkey_fpr.c_str(), 0); + if (key.GetFingerprint() == subkey_fpr || subkey_fpr.isEmpty()) { + err = + gpgme_op_setexpire(ctx_.DefaultContext(), static_cast<gpgme_key_t>(key), + expires_time, nullptr, 0); + } else { + err = + gpgme_op_setexpire(ctx_.DefaultContext(), static_cast<gpgme_key_t>(key), + expires_time, subkey_fpr.toUtf8(), 0); + } return err; } @@ -102,48 +104,52 @@ GpgFrontend::GpgError GpgFrontend::GpgKeyOpera::SetExpire( * @param outputFileName out file name(path) * @return the process doing this job */ -void GpgFrontend::GpgKeyOpera::GenerateRevokeCert( - const GpgKey& key, const std::string& output_file_path) { +void GpgKeyOpera::GenerateRevokeCert(const GpgKey& key, + const QString& output_path) { + const auto app_path = Module::RetrieveRTValueTypedOrDefault<>( + "core", "gpgme.ctx.app_path", QString{}); // get all components - GpgCommandExecutor::GetInstance().Execute( - ctx_.GetInfo().AppPath, - {"--command-fd", "0", "--status-fd", "1", "--no-tty", "-o", - output_file_path, "--gen-revoke", key.GetFingerprint().c_str()}, - [=](int exit_code, const std::string& p_out, const std::string& p_err) { - if (exit_code != 0) { - SPDLOG_ERROR( - "gnupg gen revoke execute error, process stderr: {}, process " - "stdout: {}", - p_err, p_out); - } else { - SPDLOG_DEBUG( - "gnupg gen revoke exit_code: {}, process stdout size: {}", - exit_code, p_out.size()); - } - }, - [](QProcess* proc) -> void { - // Code From Gpg4Win - while (proc->canReadLine()) { - const QString line = QString::fromUtf8(proc->readLine()).trimmed(); - SPDLOG_DEBUG("line: {}", line.toStdString()); - if (line == QLatin1String("[GNUPG:] GET_BOOL gen_revoke.okay")) { - proc->write("y\n"); - } else if (line == QLatin1String("[GNUPG:] GET_LINE " - "ask_revocation_reason.code")) { - proc->write("0\n"); - } else if (line == QLatin1String("[GNUPG:] GET_LINE " - "ask_revocation_reason.text")) { - proc->write("\n"); - } else if (line == QLatin1String( - "[GNUPG:] GET_BOOL openfile.overwrite.okay")) { - // We asked before - proc->write("y\n"); - } else if (line == QLatin1String("[GNUPG:] GET_BOOL " - "ask_revocation_reason.okay")) { - proc->write("y\n"); - } - } - }); + GpgCommandExecutor::ExecuteSync( + {app_path, + {"--command-fd", "0", "--status-fd", "1", "--no-tty", "-o", output_path, + "--gen-revoke", key.GetFingerprint()}, + [=](int exit_code, const QString& p_out, const QString& p_err) { + if (exit_code != 0) { + GF_CORE_LOG_ERROR( + "gnupg gen revoke execute error, process stderr: {}, process " + "stdout: {}", + p_err, p_out); + } else { + GF_CORE_LOG_DEBUG( + "gnupg gen revoke exit_code: {}, process stdout size: {}", + exit_code, p_out.size()); + } + }, + nullptr, + [](QProcess* proc) -> void { + // Code From Gpg4Win + while (proc->canReadLine()) { + const QString line = QString::fromUtf8(proc->readLine()).trimmed(); + GF_CORE_LOG_DEBUG("line: {}", line.toStdString()); + if (line == QLatin1String("[GNUPG:] GET_BOOL gen_revoke.okay")) { + proc->write("y\n"); + } else if (line == QLatin1String("[GNUPG:] GET_LINE " + "ask_revocation_reason.code")) { + proc->write("0\n"); + } else if (line == QLatin1String("[GNUPG:] GET_LINE " + "ask_revocation_reason.text")) { + proc->write("\n"); + } else if (line == + QLatin1String( + "[GNUPG:] GET_BOOL openfile.overwrite.okay")) { + // We asked before + proc->write("y\n"); + } else if (line == QLatin1String("[GNUPG:] GET_BOOL " + "ask_revocation_reason.okay")) { + proc->write("y\n"); + } + } + }}); } /** @@ -151,138 +157,199 @@ void GpgFrontend::GpgKeyOpera::GenerateRevokeCert( * @param params key generation args * @return error information */ -GpgFrontend::GpgError GpgFrontend::GpgKeyOpera::GenerateKey( - const std::unique_ptr<GenKeyInfo>& params, GpgGenKeyResult& result) { - auto userid_utf8 = params->GetUserid(); - const char* userid = userid_utf8.c_str(); - auto algo_utf8 = params->GetAlgo() + params->GetKeySizeStr(); - - SPDLOG_DEBUG("params: {} {}", params->GetAlgo(), params->GetKeySizeStr()); - - const char* algo = algo_utf8.c_str(); - unsigned long expires = 0; - { - using namespace boost::posix_time; - using namespace std::chrono; - expires = to_time_t(ptime(params->GetExpireTime())) - - system_clock::to_time_t(system_clock::now()); - } +void GpgKeyOpera::GenerateKey(const std::shared_ptr<GenKeyInfo>& params, + const GpgOperationCallback& callback) { + RunGpgOperaAsync( + [&ctx = ctx_, params](const DataObjectPtr& data_object) -> GpgError { + auto userid_utf8 = params->GetUserid(); + const char* userid = userid_utf8.toUtf8(); + auto algo_utf8 = params->GetAlgo() + params->GetKeySizeStr(); + + GF_CORE_LOG_DEBUG("params: {} {}", params->GetAlgo(), + params->GetKeySizeStr()); + + auto algo = algo_utf8.toUtf8(); + unsigned long expires = + QDateTime::currentDateTime().secsTo(params->GetExpireTime()); + + GpgError err; + unsigned int flags = 0; + + if (!params->IsSubKey()) flags |= GPGME_CREATE_CERT; + if (params->IsAllowEncryption()) flags |= GPGME_CREATE_ENCR; + if (params->IsAllowSigning()) flags |= GPGME_CREATE_SIGN; + if (params->IsAllowAuthentication()) flags |= GPGME_CREATE_AUTH; + if (params->IsNonExpired()) flags |= GPGME_CREATE_NOEXPIRE; + if (params->IsNoPassPhrase()) flags |= GPGME_CREATE_NOPASSWD; + + GF_CORE_LOG_DEBUG("key generation args: {}", userid, algo, expires, + flags); + err = gpgme_op_createkey(ctx.DefaultContext(), userid, algo, 0, expires, + nullptr, flags); + + if (CheckGpgError(err) == GPG_ERR_NO_ERROR) { + data_object->Swap({GpgGenerateKeyResult{ + gpgme_op_genkey_result(ctx.DefaultContext())}}); + } else { + data_object->Swap({GpgGenerateKeyResult{}}); + } - GpgError err; + return CheckGpgError(err); + }, + callback, "gpgme_op_createkey", "2.1.0"); +} - SPDLOG_DEBUG("ctx version, {}", ctx_.GetInfo(false).GnupgVersion); +/** + * Generate a new subkey of a certain key pair + * @param key target key pair + * @param params opera args + * @return error info + */ +void GpgKeyOpera::GenerateSubkey(const GpgKey& key, + const std::shared_ptr<GenKeyInfo>& params, + const GpgOperationCallback& callback) { + RunGpgOperaAsync( + [key, &ctx = ctx_, params](const DataObjectPtr&) -> GpgError { + if (!params->IsSubKey()) return GPG_ERR_CANCELED; + + GF_CORE_LOG_DEBUG("generate subkey algo {} key size {}", + params->GetAlgo(), params->GetKeySizeStr()); + + auto algo = (params->GetAlgo() + params->GetKeySizeStr()).toUtf8(); + unsigned long expires = + QDateTime::currentDateTime().secsTo(params->GetExpireTime()); + unsigned int flags = 0; + + if (!params->IsSubKey()) flags |= GPGME_CREATE_CERT; + if (params->IsAllowEncryption()) flags |= GPGME_CREATE_ENCR; + if (params->IsAllowSigning()) flags |= GPGME_CREATE_SIGN; + if (params->IsAllowAuthentication()) flags |= GPGME_CREATE_AUTH; + if (params->IsNonExpired()) flags |= GPGME_CREATE_NOEXPIRE; + if (params->IsNoPassPhrase()) flags |= GPGME_CREATE_NOPASSWD; + + GF_CORE_LOG_DEBUG("args: {} {} {} {}", key.GetId(), algo, expires, + flags); + + auto err = gpgme_op_createsubkey(ctx.DefaultContext(), + static_cast<gpgme_key_t>(key), algo, 0, + expires, flags); + return CheckGpgError(err); + }, + callback, "gpgme_op_createsubkey", "2.1.13"); +} - if (ctx_.GetInfo(false).GnupgVersion >= "2.1.0") { - unsigned int flags = 0; +void GpgKeyOpera::GenerateKeyWithSubkey( + const std::shared_ptr<GenKeyInfo>& params, + const std::shared_ptr<GenKeyInfo>& subkey_params, + const GpgOperationCallback& callback) { + RunGpgOperaAsync( + [&ctx = ctx_, params, + subkey_params](const DataObjectPtr& data_object) -> GpgError { + auto userid = params->GetUserid().toUtf8(); + auto algo = (params->GetAlgo() + params->GetKeySizeStr()).toUtf8(); + unsigned long expires = expires = + QDateTime::currentDateTime().secsTo(params->GetExpireTime()); + + GpgError err; + unsigned int flags = 0; + + if (!params->IsSubKey()) flags |= GPGME_CREATE_CERT; + if (params->IsAllowEncryption()) flags |= GPGME_CREATE_ENCR; + if (params->IsAllowSigning()) flags |= GPGME_CREATE_SIGN; + if (params->IsAllowAuthentication()) flags |= GPGME_CREATE_AUTH; + if (params->IsNonExpired()) flags |= GPGME_CREATE_NOEXPIRE; + if (params->IsNoPassPhrase()) flags |= GPGME_CREATE_NOPASSWD; + + GF_CORE_LOG_DEBUG("key generation args: {}", userid, algo, expires, + flags); + err = gpgme_op_createkey(ctx.DefaultContext(), userid, algo, 0, expires, + nullptr, flags); + + if (CheckGpgError(err) != GPG_ERR_NO_ERROR) { + data_object->Swap({GpgGenerateKeyResult{}}); + return err; + } - if (!params->IsSubKey()) flags |= GPGME_CREATE_CERT; - if (params->IsAllowEncryption()) flags |= GPGME_CREATE_ENCR; - if (params->IsAllowSigning()) flags |= GPGME_CREATE_SIGN; - if (params->IsAllowAuthentication()) flags |= GPGME_CREATE_AUTH; - if (params->IsNonExpired()) flags |= GPGME_CREATE_NOEXPIRE; - if (params->IsNoPassPhrase()) flags |= GPGME_CREATE_NOPASSWD; + auto genkey_result = + GpgGenerateKeyResult{gpgme_op_genkey_result(ctx.DefaultContext())}; - SPDLOG_DEBUG("args: {}", userid, algo, expires, flags); + auto key = + GpgKeyGetter::GetInstance().GetKey(genkey_result.GetFingerprint()); + if (!key.IsGood()) { + GF_CORE_LOG_ERROR("cannot get key which has been generate, fpr: {}", + genkey_result.GetFingerprint()); + return err; + } - err = gpgme_op_createkey(ctx_, userid, algo, 0, expires, nullptr, flags); + if (subkey_params == nullptr || !subkey_params->IsSubKey()) return err; - } else { - std::stringstream ss; - auto param_format = - boost::format{ - "<GnupgKeyParms format=\"internal\">\n" - "Key-Type: %1%\n" - "Key-Usage: sign\n" - "Key-Length: %2%\n" - "Name-Real: %3%\n" - "Name-Comment: %4%\n" - "Name-Email: %5%\n"} % - params->GetAlgo() % params->GetKeyLength() % params->GetName() % - params->GetComment() % params->GetEmail(); - ss << param_format; - - if (!params->IsNonExpired()) { - auto date = params->GetExpireTime().date(); - ss << boost::format{"Expire-Date: %1%\n"} % to_iso_string(date); - } else - ss << boost::format{"Expire-Date: 0\n"}; - if (!params->IsNoPassPhrase()) - ss << boost::format{"Passphrase: %1%\n"} % params->GetPassPhrase(); - - ss << "</GnupgKeyParms>"; - - SPDLOG_DEBUG("params: {}", ss.str()); - - err = gpgme_op_genkey(ctx_, ss.str().c_str(), nullptr, nullptr); - } + GF_CORE_LOG_DEBUG( + "try to generate subkey of key: {}, algo {} key size {}", + key.GetId(), subkey_params->GetAlgo(), + subkey_params->GetKeySizeStr()); - if (check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR) { - auto temp_result = _new_result(gpgme_op_genkey_result(ctx_)); - std::swap(temp_result, result); - } + algo = (subkey_params->GetAlgo() + subkey_params->GetKeySizeStr()) + .toUtf8(); + expires = + QDateTime::currentDateTime().secsTo(subkey_params->GetExpireTime()); - return check_gpg_error(err); -} + flags = 0; + if (subkey_params->IsAllowEncryption()) flags |= GPGME_CREATE_ENCR; + if (subkey_params->IsAllowSigning()) flags |= GPGME_CREATE_SIGN; + if (subkey_params->IsAllowAuthentication()) flags |= GPGME_CREATE_AUTH; + if (subkey_params->IsNonExpired()) flags |= GPGME_CREATE_NOEXPIRE; + if (subkey_params->IsNoPassPhrase()) flags |= GPGME_CREATE_NOPASSWD; -/** - * Generate a new subkey of a certain key pair - * @param key target key pair - * @param params opera args - * @return error info - */ -GpgFrontend::GpgError GpgFrontend::GpgKeyOpera::GenerateSubkey( - const GpgKey& key, const std::unique_ptr<GenKeyInfo>& params) { - if (!params->IsSubKey()) return GPG_ERR_CANCELED; - - SPDLOG_DEBUG("generate subkey algo {} key size {}", params->GetAlgo(), - params->GetKeySizeStr()); - - auto algo_utf8 = (params->GetAlgo() + params->GetKeySizeStr()); - const char* algo = algo_utf8.c_str(); - unsigned long expires = 0; - { - using namespace boost::posix_time; - using namespace std::chrono; - expires = to_time_t(ptime(params->GetExpireTime())) - - system_clock::to_time_t(system_clock::now()); - } - unsigned int flags = 0; + GF_CORE_LOG_DEBUG("subkey generation args: {} {} {} {}", key.GetId(), + algo, expires, flags); - if (!params->IsSubKey()) flags |= GPGME_CREATE_CERT; - if (params->IsAllowEncryption()) flags |= GPGME_CREATE_ENCR; - if (params->IsAllowSigning()) flags |= GPGME_CREATE_SIGN; - if (params->IsAllowAuthentication()) flags |= GPGME_CREATE_AUTH; - if (params->IsNonExpired()) flags |= GPGME_CREATE_NOEXPIRE; - if (params->IsNoPassPhrase()) flags |= GPGME_CREATE_NOPASSWD; + err = gpgme_op_createsubkey(ctx.DefaultContext(), + static_cast<gpgme_key_t>(key), algo, 0, + expires, flags); - SPDLOG_DEBUG("args: {} {} {} {}", key.GetId(), algo, expires, flags); + if (CheckGpgError(err) == GPG_ERR_NO_ERROR) { + data_object->Swap( + {genkey_result, GpgGenerateKeyResult{gpgme_op_genkey_result( + ctx.DefaultContext())}}); + } else { + data_object->Swap({genkey_result, GpgGenerateKeyResult{}}); + } - auto err = - gpgme_op_createsubkey(ctx_, gpgme_key_t(key), algo, 0, expires, flags); - return check_gpg_error(err); + return CheckGpgError(err); + }, + callback, "gpgme_op_createkey&gpgme_op_createsubkey", "2.1.0"); } -GpgFrontend::GpgError GpgFrontend::GpgKeyOpera::ModifyPassword( - const GpgFrontend::GpgKey& key) { - if (ctx_.GetInfo(false).GnupgVersion < "2.0.15") { - SPDLOG_ERROR("operator not support"); - return GPG_ERR_NOT_SUPPORTED; - } - auto err = gpgme_op_passwd(ctx_, gpgme_key_t(key), 0); - return check_gpg_error(err); +void GpgKeyOpera::ModifyPassword(const GpgKey& key, + const GpgOperationCallback& callback) { + RunGpgOperaAsync( + [&key, &ctx = ctx_](const DataObjectPtr&) -> GpgError { + return gpgme_op_passwd(ctx.DefaultContext(), + static_cast<gpgme_key_t>(key), 0); + }, + callback, "gpgme_op_passwd", "2.0.15"); } -GpgFrontend::GpgError GpgFrontend::GpgKeyOpera::ModifyTOFUPolicy( - const GpgFrontend::GpgKey& key, gpgme_tofu_policy_t tofu_policy) { - if (ctx_.GetInfo(false).GnupgVersion < "2.1.10") { - SPDLOG_ERROR("operator not support"); + +auto GpgKeyOpera::ModifyTOFUPolicy(const GpgKey& key, + gpgme_tofu_policy_t tofu_policy) + -> GpgError { + const auto gnupg_version = Module::RetrieveRTValueTypedOrDefault<>( + "core", "gpgme.ctx.gnupg_version", QString{"2.0.0"}); + GF_CORE_LOG_DEBUG("got gnupg version from rt: {}", gnupg_version); + + if (CompareSoftwareVersion(gnupg_version, "2.1.10") < 0) { + GF_CORE_LOG_ERROR("operator not support"); return GPG_ERR_NOT_SUPPORTED; } - auto err = gpgme_op_tofu_policy(ctx_, gpgme_key_t(key), tofu_policy); - return check_gpg_error(err); + + auto err = gpgme_op_tofu_policy(ctx_.DefaultContext(), + static_cast<gpgme_key_t>(key), tofu_policy); + return CheckGpgError(err); } -void GpgFrontend::GpgKeyOpera::DeleteKey(const GpgFrontend::KeyId& key_id) { +void GpgKeyOpera::DeleteKey(const GpgFrontend::KeyId& key_id) { auto keys = std::make_unique<KeyIdArgsList>(); keys->push_back(key_id); DeleteKeys(std::move(keys)); } +} // namespace GpgFrontend diff --git a/src/core/function/gpg/GpgKeyOpera.h b/src/core/function/gpg/GpgKeyOpera.h index 5446bd66..a060af1a 100644 --- a/src/core/function/gpg/GpgKeyOpera.h +++ b/src/core/function/gpg/GpgKeyOpera.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,18 +20,18 @@ * 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. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef _GPGKEYOPERA_H -#define _GPGKEYOPERA_H +#pragma once -#include "core/GpgConstants.h" -#include "core/GpgContext.h" -#include "core/GpgModel.h" +#include <functional> + +#include "core/function/gpg/GpgContext.h" +#include "core/typedef/GpgTypedef.h" namespace GpgFrontend { /** @@ -77,8 +77,8 @@ class GPGFRONTEND_CORE_EXPORT GpgKeyOpera * @param expires * @return GpgError */ - GpgError SetExpire(const GpgKey& key, const SubkeyId& subkey_fpr, - std::unique_ptr<boost::posix_time::ptime>& expires); + auto SetExpire(const GpgKey& key, const SubkeyId& subkey_fpr, + std::unique_ptr<QDateTime>& expires) -> GpgError; /** * @brief @@ -86,8 +86,7 @@ class GPGFRONTEND_CORE_EXPORT GpgKeyOpera * @param key * @param output_file_name */ - void GenerateRevokeCert(const GpgKey& key, - const std::string& output_file_name); + void GenerateRevokeCert(const GpgKey& key, const QString& output_path); /** * @brief @@ -95,7 +94,7 @@ class GPGFRONTEND_CORE_EXPORT GpgKeyOpera * @param key * @return GpgFrontend::GpgError */ - GpgFrontend::GpgError ModifyPassword(const GpgKey& key); + void ModifyPassword(const GpgKey& key, const GpgOperationCallback&); /** * @brief @@ -104,8 +103,8 @@ class GPGFRONTEND_CORE_EXPORT GpgKeyOpera * @param tofu_policy * @return GpgFrontend::GpgError */ - GpgFrontend::GpgError ModifyTOFUPolicy(const GpgKey& key, - gpgme_tofu_policy_t tofu_policy); + auto ModifyTOFUPolicy(const GpgKey& key, gpgme_tofu_policy_t tofu_policy) + -> GpgFrontend::GpgError; /** * @brief * @@ -113,8 +112,8 @@ class GPGFRONTEND_CORE_EXPORT GpgKeyOpera * @param result * @return GpgFrontend::GpgError */ - GpgFrontend::GpgError GenerateKey(const std::unique_ptr<GenKeyInfo>& params, - GpgGenKeyResult& result); + void GenerateKey(const std::shared_ptr<GenKeyInfo>&, + const GpgOperationCallback&); /** * @brief @@ -123,13 +122,23 @@ class GPGFRONTEND_CORE_EXPORT GpgKeyOpera * @param params * @return GpgFrontend::GpgError */ - GpgFrontend::GpgError GenerateSubkey( - const GpgKey& key, const std::unique_ptr<GenKeyInfo>& params); + void GenerateSubkey(const GpgKey& key, + const std::shared_ptr<GenKeyInfo>& params, + const GpgOperationCallback&); + + /** + * @brief + * + * @param params + * @param subkey_params + * @param callback + */ + void GenerateKeyWithSubkey(const std::shared_ptr<GenKeyInfo>& params, + const std::shared_ptr<GenKeyInfo>& subkey_params, + const GpgOperationCallback& callback); private: GpgContext& ctx_ = GpgContext::GetInstance(SingletonFunctionObject::GetChannel()); ///< }; } // namespace GpgFrontend - -#endif // _GPGKEYOPERA_H
\ No newline at end of file diff --git a/src/core/function/gpg/GpgUIDOperator.cpp b/src/core/function/gpg/GpgUIDOperator.cpp index 7e7a711e..6c0373de 100644 --- a/src/core/function/gpg/GpgUIDOperator.cpp +++ b/src/core/function/gpg/GpgUIDOperator.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,7 +20,7 @@ * 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. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * @@ -28,44 +28,38 @@ #include "GpgUIDOperator.h" -#include "boost/format.hpp" +#include "core/GpgModel.h" +#include "core/utils/GpgUtils.h" -GpgFrontend::GpgUIDOperator::GpgUIDOperator(int channel) +namespace GpgFrontend { + +GpgUIDOperator::GpgUIDOperator(int channel) : SingletonFunctionObject<GpgUIDOperator>(channel) {} -bool GpgFrontend::GpgUIDOperator::AddUID(const GpgFrontend::GpgKey& key, - const std::string& uid) { - auto err = gpgme_op_adduid(ctx_, gpgme_key_t(key), uid.c_str(), 0); - if (check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR) - return true; - else - return false; +auto GpgUIDOperator::AddUID(const GpgKey& key, const QString& uid) -> bool { + auto err = gpgme_op_adduid(ctx_.DefaultContext(), + static_cast<gpgme_key_t>(key), uid.toUtf8(), 0); + return CheckGpgError(err) == GPG_ERR_NO_ERROR; } -bool GpgFrontend::GpgUIDOperator::RevUID(const GpgFrontend::GpgKey& key, - const std::string& uid) { - auto err = - check_gpg_error(gpgme_op_revuid(ctx_, gpgme_key_t(key), uid.c_str(), 0)); - if (check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR) - return true; - else - return false; +auto GpgUIDOperator::RevUID(const GpgKey& key, const QString& uid) -> bool { + auto err = CheckGpgError(gpgme_op_revuid( + ctx_.DefaultContext(), static_cast<gpgme_key_t>(key), uid.toUtf8(), 0)); + return CheckGpgError(err) == GPG_ERR_NO_ERROR; } -bool GpgFrontend::GpgUIDOperator::SetPrimaryUID(const GpgFrontend::GpgKey& key, - const std::string& uid) { - auto err = check_gpg_error(gpgme_op_set_uid_flag( - ctx_, gpgme_key_t(key), uid.c_str(), "primary", nullptr)); - if (check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR) - return true; - else - return false; +auto GpgUIDOperator::SetPrimaryUID(const GpgKey& key, const QString& uid) + -> bool { + auto err = CheckGpgError(gpgme_op_set_uid_flag( + ctx_.DefaultContext(), static_cast<gpgme_key_t>(key), uid.toUtf8(), + "primary", nullptr)); + return CheckGpgError(err) == GPG_ERR_NO_ERROR; } -bool GpgFrontend::GpgUIDOperator::AddUID(const GpgFrontend::GpgKey& key, - const std::string& name, - const std::string& comment, - const std::string& email) { - SPDLOG_DEBUG("new uuid: {} {} {}", name, comment, email); - auto uid = boost::format("%1%(%2%)<%3%>") % name % comment % email; - return AddUID(key, uid.str()); +auto GpgUIDOperator::AddUID(const GpgKey& key, const QString& name, + const QString& comment, const QString& email) + -> bool { + GF_CORE_LOG_DEBUG("new uuid: {} {} {}", name, comment, email); + return AddUID(key, QString("%1(%2)<%3>").arg(name).arg(comment).arg(email)); } + +} // namespace GpgFrontend diff --git a/src/core/function/gpg/GpgUIDOperator.h b/src/core/function/gpg/GpgUIDOperator.h index c4a7d87b..b2cec8bc 100644 --- a/src/core/function/gpg/GpgUIDOperator.h +++ b/src/core/function/gpg/GpgUIDOperator.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,17 +20,16 @@ * 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. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPGFRONTEND_ZH_CN_TS_UIDOPERATOR_H -#define GPGFRONTEND_ZH_CN_TS_UIDOPERATOR_H +#pragma once -#include "core/GpgContext.h" -#include "core/GpgModel.h" +#include "core/function/gpg/GpgContext.h" +#include "core/typedef/GpgTypedef.h" namespace GpgFrontend { /** @@ -54,7 +53,7 @@ class GPGFRONTEND_CORE_EXPORT GpgUIDOperator * @param uid uid args(combine name&comment&email) * @return if successful */ - bool AddUID(const GpgKey& key, const std::string& uid); + auto AddUID(const GpgKey& key, const QString& uid) -> bool; /** * create a new uid in certain key pair @@ -64,8 +63,8 @@ class GPGFRONTEND_CORE_EXPORT GpgUIDOperator * @param email * @return */ - bool AddUID(const GpgKey& key, const std::string& name, - const std::string& comment, const std::string& email); + auto AddUID(const GpgKey& key, const QString& name, const QString& comment, + const QString& email) -> bool; /** * Revoke(Delete) UID from certain key pair @@ -73,7 +72,7 @@ class GPGFRONTEND_CORE_EXPORT GpgUIDOperator * @param uid target uid * @return if successful */ - bool RevUID(const GpgKey& key, const std::string& uid); + auto RevUID(const GpgKey& key, const QString& uid) -> bool; /** * Set one of a uid of a key pair as primary @@ -81,7 +80,7 @@ class GPGFRONTEND_CORE_EXPORT GpgUIDOperator * @param uid target uid * @return if successful */ - bool SetPrimaryUID(const GpgKey& key, const std::string& uid); + auto SetPrimaryUID(const GpgKey& key, const QString& uid) -> bool; private: GpgContext& ctx_ = @@ -89,5 +88,3 @@ class GPGFRONTEND_CORE_EXPORT GpgUIDOperator }; } // namespace GpgFrontend - -#endif // GPGFRONTEND_ZH_CN_TS_UIDOPERATOR_H |