diff options
Diffstat (limited to 'src/core')
158 files changed, 12485 insertions, 7031 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 22a0b88a..ed12ad01 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -1,5 +1,4 @@ -# -# Copyright (C) 2021 Saturneric +# Copyright (C) 2021 Saturneric <[email protected]> # # This file is part of GpgFrontend. # @@ -20,31 +19,41 @@ # 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 -aux_source_directory(./function/result_analyse GPG_SOURCE) -aux_source_directory(./function/gpg GPG_SOURCE) -aux_source_directory(./function/aes GPG_SOURCE) -aux_source_directory(./function GPG_SOURCE) -aux_source_directory(./thread GPG_SOURCE) -aux_source_directory(./model GPG_SOURCE) -aux_source_directory(./common GPG_SOURCE) -aux_source_directory(. GPG_SOURCE) + +aux_source_directory(./function/result_analyse CORE_SOURCE) +aux_source_directory(./function/basic CORE_SOURCE) +aux_source_directory(./function/gpg CORE_SOURCE) +aux_source_directory(./function/secure_memory CORE_SOURCE) +aux_source_directory(./function CORE_SOURCE) +aux_source_directory(./thread CORE_SOURCE) +aux_source_directory(./model CORE_SOURCE) +aux_source_directory(./common CORE_SOURCE) +aux_source_directory(./module CORE_SOURCE) +aux_source_directory(./utils/aes CORE_SOURCE) +aux_source_directory(./utils CORE_SOURCE) +aux_source_directory(. CORE_SOURCE) # define libgpgfrontend_core set(CMAKE_CXX_VISIBILITY_PRESET hidden) set(CMAKE_VISIBILITY_INLINES_HIDDEN 1) -add_library(gpgfrontend_core SHARED ${GPG_SOURCE}) +add_library(gpgfrontend_core SHARED ${CORE_SOURCE}) set(_export_file "${CMAKE_CURRENT_SOURCE_DIR}/GpgFrontendCoreExport.h") generate_export_header(gpgfrontend_core EXPORT_FILE_NAME "${_export_file}") -# link third-party libraries -target_link_libraries(gpgfrontend_core PUBLIC config++) -if (NOT LINUX) - target_link_libraries(gpgfrontend_core PUBLIC config++ intl) -endif () +if(NOT APPLE) + target_link_libraries(gpgfrontend_core PUBLIC mimalloc) + if(MINGW) + set_target_properties(mimalloc + PROPERTIES + LIBRARY_OUTPUT_DIRECTORY "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}" + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}" + ) + endif() +endif() # qt-aes target_sources(gpgfrontend_core PRIVATE @@ -54,24 +63,10 @@ target_sources(gpgfrontend_core PRIVATE aux_source_directory(${CMAKE_SOURCE_DIR}/third_party/encoding-detect ENCODING_DETECT_SOURCE_CODE) target_sources(gpgfrontend_core PUBLIC ${ENCODING_DETECT_SOURCE_CODE}) -# icu -if (APPLE) - target_include_directories(gpgfrontend_core PRIVATE /usr/local/opt/icu4c/include) - target_link_directories(gpgfrontend_core PRIVATE /usr/local/opt/icu4c/lib) - target_link_libraries(gpgfrontend_core PRIVATE icui18n icuuc icudata) -else () - find_package(ICU 60.0 REQUIRED COMPONENTS i18n uc data) - message("ICU version: ${ICU_VERSION}") - message("ICU libraries: ${ICU_LIBRARIES}") - target_link_libraries(gpgfrontend_core PRIVATE ${ICU_LIBRARIES}) -endif () - # link gnupg libraries -target_link_libraries(gpgfrontend_core PRIVATE gpgme assuan gpg-error) +target_link_libraries(gpgfrontend_core PUBLIC gpgme assuan gpg-error) # link openssl target_link_libraries(gpgfrontend_core PUBLIC OpenSSL::SSL OpenSSL::Crypto) -# link boost libraries -target_link_libraries(gpgfrontend_core PUBLIC ${Boost_LIBRARIES}) if (MINGW) # for uuid ability in mingw target_link_libraries(gpgfrontend_core PUBLIC bcrypt) @@ -81,17 +76,15 @@ endif () target_link_libraries(gpgfrontend_core PRIVATE spdlog) # link libarchive +if(APPLE) + set(LibArchive_INCLUDE_DIR "/usr/local/opt/libarchive/include") +endif() +find_package(LibArchive REQUIRED) +target_include_directories(gpgfrontend_core PRIVATE ${LibArchive_INCLUDE_DIR}) target_link_libraries(gpgfrontend_core PRIVATE archive) - -# link json -target_link_libraries(gpgfrontend_core - PUBLIC nlohmann_json::nlohmann_json) + # link Qt core -if(Qt6_DIR) - target_link_libraries(gpgfrontend_core PUBLIC Qt6::Core) -else() - target_link_libraries(gpgfrontend_core PUBLIC Qt5::Core) -endif() +target_link_libraries(gpgfrontend_core PUBLIC Qt6::Core) # set up pch target_precompile_headers(gpgfrontend_core diff --git a/src/core/GpgConstants.cpp b/src/core/GpgConstants.cpp index 35e485d4..ade003a8 100644 --- a/src/core/GpgConstants.cpp +++ b/src/core/GpgConstants.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,177 +28,5 @@ #include "core/GpgConstants.h" -#include <boost/algorithm/string/predicate.hpp> - -#include "function/FileOperator.h" - -const char* GpgFrontend::GpgConstants::PGP_CRYPT_BEGIN = - "-----BEGIN PGP MESSAGE-----"; ///< -const char* GpgFrontend::GpgConstants::PGP_CRYPT_END = - "-----END PGP MESSAGE-----"; ///< -const char* GpgFrontend::GpgConstants::PGP_SIGNED_BEGIN = - "-----BEGIN PGP SIGNED MESSAGE-----"; ///< -const char* GpgFrontend::GpgConstants::PGP_SIGNED_END = - "-----END PGP SIGNATURE-----"; ///< -const char* GpgFrontend::GpgConstants::PGP_SIGNATURE_BEGIN = - "-----BEGIN PGP SIGNATURE-----"; ///< -const char* GpgFrontend::GpgConstants::PGP_SIGNATURE_END = - "-----END PGP SIGNATURE-----"; ///< -const char* GpgFrontend::GpgConstants::PGP_PUBLIC_KEY_BEGIN = - "-----BEGIN PGP PUBLIC KEY BLOCK-----"; ///< -const char* GpgFrontend::GpgConstants::PGP_PRIVATE_KEY_BEGIN = - "-----BEGIN PGP PRIVATE KEY BLOCK-----"; ///< -const char* GpgFrontend::GpgConstants::GPG_FRONTEND_SHORT_CRYPTO_HEAD = - "GpgF_Scpt://"; ///< - -gpgme_error_t GpgFrontend::check_gpg_error(gpgme_error_t err) { - if (gpg_err_code(err) != GPG_ERR_NO_ERROR) { - SPDLOG_ERROR("[error: {}] source: {} description: {}", gpg_err_code(err), - gpgme_strsource(err), gpgme_strerror(err)); - } - return err; -} - -gpg_err_code_t GpgFrontend::check_gpg_error_2_err_code(gpgme_error_t err, - gpgme_error_t predict) { - auto err_code = gpg_err_code(err); - if (err_code != gpg_err_code(predict)) { - if (err_code == GPG_ERR_NO_ERROR) - SPDLOG_WARN("[Warning {}] Source: {} description: {} predict: {}", - gpg_err_code(err), gpgme_strsource(err), gpgme_strerror(err), - gpgme_strerror(err)); - else - SPDLOG_ERROR("[Error {}] Source: {} description: {} predict: {}", - gpg_err_code(err), gpgme_strsource(err), gpgme_strerror(err), - gpgme_strerror(err)); - } - return err_code; -} - -gpgme_error_t GpgFrontend::check_gpg_error(gpgme_error_t err, - const std::string& comment) { - if (gpg_err_code(err) != GPG_ERR_NO_ERROR) { - SPDLOG_WARN("[Error {}] Source: {} description: {} predict: {}", - gpg_err_code(err), gpgme_strsource(err), gpgme_strerror(err), - gpgme_strerror(err)); - } - return err; -} - -std::string GpgFrontend::beautify_fingerprint( - GpgFrontend::BypeArrayConstRef fingerprint) { - auto len = fingerprint.size(); - std::stringstream out; - decltype(len) count = 0; - while (count < len) { - if (count && !(count % 5)) out << " "; - out << fingerprint[count]; - count++; - } - return out.str(); -} - -static inline void ltrim(std::string& s) { - s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) { - return !std::isspace(ch); - })); -} - -static inline void rtrim(std::string& s) { - s.erase(std::find_if(s.rbegin(), s.rend(), - [](unsigned char ch) { return !std::isspace(ch); }) - .base(), - s.end()); -} - -static inline std::string trim(std::string& s) { - ltrim(s); - rtrim(s); - return s; -} - -std::string GpgFrontend::read_all_data_in_file(const std::string& utf8_path) { - std::string data; - FileOperator::ReadFileStd(utf8_path, data); - return data; -} - -bool GpgFrontend::write_buffer_to_file(const std::string& utf8_path, - const std::string& out_buffer) { - return FileOperator::WriteFileStd(utf8_path, out_buffer); -} - -std::string GpgFrontend::get_file_extension(const std::string& path) { - // Create a path object from given string - std::filesystem::path path_obj(path); - - // Check if file name in the path object has extension - if (path_obj.has_extension()) { - // Fetch the extension from path object and return - return path_obj.extension().u8string(); - } - // In case of no extension return empty string - return {}; -} - -std::string GpgFrontend::get_only_file_name_with_path(const std::string& path) { - // Create a path object from given string - std::filesystem::path path_obj(path); - // Check if file name in the path object has extension - if (path_obj.has_filename()) { - // Fetch the extension from path object and return - return (path_obj.parent_path() / path_obj.stem()).u8string(); - } - // In case of no extension return empty string - return {}; -} - -int GpgFrontend::text_is_signed(GpgFrontend::BypeArrayRef text) { - using boost::algorithm::ends_with; - using boost::algorithm::starts_with; - - auto trim_text = trim(text); - if (starts_with(trim_text, GpgConstants::PGP_SIGNED_BEGIN) && - ends_with(trim_text, GpgConstants::PGP_SIGNED_END)) - return 2; - else if (text.find(GpgConstants::PGP_SIGNED_BEGIN) != std::string::npos && - text.find(GpgConstants::PGP_SIGNED_END) != std::string::npos) - return 1; - else - return 0; -} - -GpgFrontend::GpgEncrResult GpgFrontend::_new_result( - gpgme_encrypt_result_t&& result) { - gpgme_result_ref(result); - return {result, _result_ref_deletor()}; -} - -GpgFrontend::GpgDecrResult GpgFrontend::_new_result( - gpgme_decrypt_result_t&& result) { - gpgme_result_ref(result); - return {result, _result_ref_deletor()}; -} - -GpgFrontend::GpgSignResult GpgFrontend::_new_result( - gpgme_sign_result_t&& result) { - gpgme_result_ref(result); - return {result, _result_ref_deletor()}; -} - -GpgFrontend::GpgVerifyResult GpgFrontend::_new_result( - gpgme_verify_result_t&& result) { - gpgme_result_ref(result); - return {result, _result_ref_deletor()}; -} - -GpgFrontend::GpgGenKeyResult GpgFrontend::_new_result( - gpgme_genkey_result_t&& result) { - gpgme_result_ref(result); - return {result, _result_ref_deletor()}; -} - -void GpgFrontend::_result_ref_deletor::operator()(void* _result) { - SPDLOG_TRACE("gpgme unref {}", _result); - if (_result != nullptr) gpgme_result_unref(_result); -} +namespace GpgFrontend { +} // namespace GpgFrontend diff --git a/src/core/GpgConstants.h b/src/core/GpgConstants.h index a8a87835..c2125650 100644 --- a/src/core/GpgConstants.h +++ b/src/core/GpgConstants.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,200 +20,35 @@ * 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 GPG_CONSTANTS_H -#define GPG_CONSTANTS_H - -#include "GpgFrontendCore.h" - -const int RESTART_CODE = 1000; ///< only refresh ui -const int DEEP_RESTART_CODE = 1001; // refresh core and ui +#pragma once namespace GpgFrontend { -using ByteArray = std::string; ///< -using ByteArrayPtr = std::unique_ptr<ByteArray>; ///< -using StdBypeArrayPtr = std::unique_ptr<ByteArray>; ///< -using BypeArrayRef = ByteArray&; ///< -using BypeArrayConstRef = const ByteArray&; ///< -using StringArgsPtr = std::unique_ptr<std::vector<std::string>>; ///< -using StringArgsRef = std::vector<std::string>&; ///< - -using GpgError = gpgme_error_t; - -/** - * @brief Result Deleter - * - */ -struct _result_ref_deletor { - void operator()(void* _result); -}; - -using GpgEncrResult = std::shared_ptr<struct _gpgme_op_encrypt_result>; ///< -using GpgDecrResult = std::shared_ptr<struct _gpgme_op_decrypt_result>; ///< -using GpgSignResult = std::shared_ptr<struct _gpgme_op_sign_result>; ///< -using GpgVerifyResult = std::shared_ptr<struct _gpgme_op_verify_result>; ///< -using GpgGenKeyResult = std::shared_ptr<struct _gpgme_op_genkey_result>; ///< -// Convert from gpgme_xxx_result to GpgXXXResult - -/** - * @brief - * - * @param result - * @return GpgEncrResult - */ -GPGFRONTEND_CORE_EXPORT GpgEncrResult -_new_result(gpgme_encrypt_result_t&& result); - -/** - * @brief - * - * @param result - * @return GpgDecrResult - */ -GPGFRONTEND_CORE_EXPORT GpgDecrResult -_new_result(gpgme_decrypt_result_t&& result); - -/** - * @brief - * - * @param result - * @return GpgSignResult - */ -GPGFRONTEND_CORE_EXPORT GpgSignResult _new_result(gpgme_sign_result_t&& result); - -/** - * @brief - * - * @param result - * @return GpgVerifyResult - */ -GPGFRONTEND_CORE_EXPORT GpgVerifyResult -_new_result(gpgme_verify_result_t&& result); - -/** - * @brief - * - * @param result - * @return GpgGenKeyResult - */ -GPGFRONTEND_CORE_EXPORT GpgGenKeyResult -_new_result(gpgme_genkey_result_t&& result); - -// Error Info Printer - -/** - * @brief - * - * @param err - * @return GpgError - */ -GPGFRONTEND_CORE_EXPORT GpgError check_gpg_error(GpgError err); - -/** - * @brief - * - * @param gpgmeError - * @param comment - * @return GpgError - */ -GPGFRONTEND_CORE_EXPORT GpgError check_gpg_error(GpgError gpgmeError, - const std::string& comment); - -/** - * @brief - * - * @param err - * @param predict - * @return gpg_err_code_t - */ -GPGFRONTEND_CORE_EXPORT gpg_err_code_t check_gpg_error_2_err_code( - gpgme_error_t err, gpgme_error_t predict = GPG_ERR_NO_ERROR); - -// Fingerprint - -/** - * @brief - * - * @param fingerprint - * @return std::string - */ -GPGFRONTEND_CORE_EXPORT std::string beautify_fingerprint( - BypeArrayConstRef fingerprint); - -// File Operation - -/** - * @brief - * - * @param path - * @return std::string - */ -std::string read_all_data_in_file(const std::string& path); - -/** - * @brief - * - * @param path - * @param out_buffer - * @return true - * @return false - */ -GPGFRONTEND_CORE_EXPORT bool write_buffer_to_file( - const std::string& path, const std::string& out_buffer); - -/** - * @brief Get the file extension object - * - * @param path - * @return std::string - */ -std::string get_file_extension(const std::string& path); - -/** - * @brief Get the only file name with path object - * - * @param path - * @return std::string - */ -std::string get_only_file_name_with_path(const std::string& path); - -// Check - -/** - * @brief - * - * @param text - * @return int - */ -int text_is_signed(BypeArrayRef text); +constexpr int kRestartCode = 1000; ///< only refresh ui +constexpr int kDeepRestartCode = 1001; // refresh core and ui // Channels -const int GPGFRONTEND_DEFAULT_CHANNEL = 0; ///< -const int GPGFRONTEND_NON_ASCII_CHANNEL = 2; ///< - -/** - * @brief - * - */ -class GPGFRONTEND_CORE_EXPORT GpgConstants { - public: - static const char* PGP_CRYPT_BEGIN; ///< - static const char* PGP_CRYPT_END; ///< - static const char* PGP_SIGNED_BEGIN; ///< - static const char* PGP_SIGNED_END; ///< - static const char* PGP_SIGNATURE_BEGIN; ///< - static const char* PGP_SIGNATURE_END; ///< - static const char* PGP_PUBLIC_KEY_BEGIN; ///< - static const char* PGP_PRIVATE_KEY_BEGIN; ///< - static const char* GPG_FRONTEND_SHORT_CRYPTO_HEAD; ///< -}; +constexpr int kGpgFrontendDefaultChannel = 0; ///< +constexpr int kGpgFrontendNonAsciiChannel = 2; ///< + +// HEADER +constexpr const char* PGP_CRYPT_BEGIN = "-----BEGIN PGP MESSAGE-----"; ///< +constexpr const char* PGP_CRYPT_END = "-----END PGP MESSAGE-----"; ///< +constexpr const char* PGP_SIGNED_BEGIN = + "-----BEGIN PGP SIGNED MESSAGE-----"; ///< +constexpr const char* PGP_SIGNED_END = "-----END PGP SIGNATURE-----"; ///< +constexpr const char* PGP_SIGNATURE_BEGIN = + "-----BEGIN PGP SIGNATURE-----"; ///< +constexpr const char* PGP_SIGNATURE_END = "-----END PGP SIGNATURE-----"; ///< +constexpr const char* PGP_PUBLIC_KEY_BEGIN = + "-----BEGIN PGP PUBLIC KEY BLOCK-----"; ///< +constexpr const char* PGP_PRIVATE_KEY_BEGIN = + "-----BEGIN PGP PRIVATE KEY BLOCK-----"; ///< } // namespace GpgFrontend - -#endif // GPG_CONSTANTS_H diff --git a/src/core/GpgContext.cpp b/src/core/GpgContext.cpp deleted file mode 100644 index 7d98004d..00000000 --- a/src/core/GpgContext.cpp +++ /dev/null @@ -1,660 +0,0 @@ -/** - * Copyright (C) 2021 Saturneric - * - * This file is part of GpgFrontend. - * - * GpgFrontend is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GpgFrontend is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GpgFrontend. If not, see <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/GpgContext.h" - -#include <gpg-error.h> -#include <gpgme.h> -#include <spdlog/spdlog.h> -#include <unistd.h> - -#include <mutex> -#include <shared_mutex> -#include <string> - -#include "core/GpgConstants.h" -#include "core/common/CoreCommonUtil.h" -#include "core/function/CoreSignalStation.h" -#include "core/function/gpg/GpgCommandExecutor.h" -#include "core/thread/Task.h" -#include "core/thread/TaskRunnerGetter.h" -#include "function/gpg/GpgKeyGetter.h" - -#ifdef _WIN32 -#include <windows.h> -#endif - -namespace GpgFrontend { - -GpgContext::GpgContext(int channel) - : SingletonFunctionObject<GpgContext>(channel) {} - -/** - * Constructor - * Set up gpgme-context, set paths to app-run path - */ -GpgContext::GpgContext(const GpgContextInitArgs &args) : args_(args) { - gpgme_ctx_t _p_ctx; - - // get gpgme library version - info_.GpgMEVersion = gpgme_check_version(nullptr); - - // create a new context - check_gpg_error(gpgme_new(&_p_ctx)); - _ctx_ref = CtxRefHandler(_p_ctx); - - if (args.gpg_alone) { - info_.AppPath = args.gpg_path; - auto err = gpgme_ctx_set_engine_info(_ctx_ref.get(), GPGME_PROTOCOL_OpenPGP, - info_.AppPath.c_str(), - info_.DatabasePath.c_str()); - assert(check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR); - } - - if (args.custom_gpgconf && !args.custom_gpgconf_path.empty()) { - SPDLOG_DEBUG("set custom gpgconf path: {}", args.custom_gpgconf_path); - auto err = - gpgme_ctx_set_engine_info(_ctx_ref.get(), GPGME_PROTOCOL_GPGCONF, - args.custom_gpgconf_path.c_str(), nullptr); - assert(check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR); - } - - // set context offline mode - SPDLOG_DEBUG("gpg context offline mode: {}", args_.offline_mode); - gpgme_set_offline(_ctx_ref.get(), args_.offline_mode ? 1 : 0); - - // set option auto import missing key - // invalid at offline mode - SPDLOG_DEBUG("gpg context auto import missing key: {}", args_.offline_mode); - if (!args.offline_mode && args.auto_import_missing_key) - check_gpg_error(gpgme_set_ctx_flag(_ctx_ref.get(), "auto-key-import", "1")); - - // get engine info - auto engine_info = gpgme_ctx_get_engine_info(*this); - // Check ENV before running - bool check_passed = false, find_openpgp = false, find_gpgconf = false, - find_cms = false; - - while (engine_info != nullptr) { - if (!strcmp(engine_info->version, "1.0.0")) { - engine_info = engine_info->next; - continue; - } - - SPDLOG_DEBUG( - "gpg context engine info: {} {} {} {}", - gpgme_get_protocol_name(engine_info->protocol), - std::string(engine_info->file_name == nullptr ? "null" - : engine_info->file_name), - std::string(engine_info->home_dir == nullptr ? "null" - : engine_info->home_dir), - std::string(engine_info->version ? "null" : engine_info->version)); - - switch (engine_info->protocol) { - case GPGME_PROTOCOL_OpenPGP: - find_openpgp = true; - info_.AppPath = engine_info->file_name; - info_.GnupgVersion = engine_info->version; - info_.DatabasePath = std::string(engine_info->home_dir == nullptr - ? "default" - : engine_info->home_dir); - break; - case GPGME_PROTOCOL_CMS: - find_cms = true; - info_.CMSPath = engine_info->file_name; - break; - case GPGME_PROTOCOL_GPGCONF: - find_gpgconf = true; - info_.GpgConfPath = engine_info->file_name; - break; - case GPGME_PROTOCOL_ASSUAN: - info_.AssuanPath = engine_info->file_name; - break; - case GPGME_PROTOCOL_G13: - break; - case GPGME_PROTOCOL_UISERVER: - break; - case GPGME_PROTOCOL_SPAWN: - break; - case GPGME_PROTOCOL_DEFAULT: - break; - case GPGME_PROTOCOL_UNKNOWN: - break; - } - engine_info = engine_info->next; - } - - // set custom key db path - if (!args.db_path.empty()) { - info_.DatabasePath = args.db_path; - auto err = gpgme_ctx_set_engine_info(_ctx_ref.get(), GPGME_PROTOCOL_OpenPGP, - info_.AppPath.c_str(), - info_.DatabasePath.c_str()); - SPDLOG_DEBUG("ctx set custom key db path: {}", info_.DatabasePath); - assert(check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR); - } - - // conditional check - if ((info_.GnupgVersion >= "2.0.0" && find_gpgconf && find_openpgp && - find_cms) || - (info_.GnupgVersion > "1.0.0" && find_gpgconf)) - check_passed = true; - - if (!check_passed) { - this->good_ = false; - SPDLOG_ERROR("env check failed"); - return; - } else { - // speed up loading process - gpgme_set_offline(*this, 1); - - // set keylist mode - if (info_.GnupgVersion >= "2.0.0") { - check_gpg_error(gpgme_set_keylist_mode( - *this, GPGME_KEYLIST_MODE_LOCAL | GPGME_KEYLIST_MODE_WITH_SECRET | - GPGME_KEYLIST_MODE_SIGS | - GPGME_KEYLIST_MODE_SIG_NOTATIONS | - GPGME_KEYLIST_MODE_WITH_TOFU)); - } else { - check_gpg_error(gpgme_set_keylist_mode( - *this, GPGME_KEYLIST_MODE_LOCAL | GPGME_KEYLIST_MODE_SIGS | - GPGME_KEYLIST_MODE_SIG_NOTATIONS | - GPGME_KEYLIST_MODE_WITH_TOFU)); - } - - // async, init context - Thread::TaskRunnerGetter::GetInstance() - .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_GPG) - ->PostTask(new Thread::Task( - [=](Thread::Task::DataObjectPtr) -> int { - post_init_ctx(); - return 0; - }, - "post_init_ctx")); - - good_ = true; - } -} - -void GpgContext::post_init_ctx() { - // Set Independent Database - if (info_.GnupgVersion <= "2.0.0" && args_.independent_database) { - info_.DatabasePath = args_.db_path; - SPDLOG_DEBUG("custom key db path {}", info_.DatabasePath); - auto err = gpgme_ctx_set_engine_info(_ctx_ref.get(), GPGME_PROTOCOL_OpenPGP, - info_.AppPath.c_str(), - info_.DatabasePath.c_str()); - assert(check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR); - } else { - info_.DatabasePath = "default"; - } - - if (args_.ascii) { - /** Setting the output type must be done at the beginning */ - /** think this means ascii-armor --> ? */ - gpgme_set_armor(*this, 1); - } else { - /** Setting the output type must be done at the beginning */ - /** think this means ascii-armor --> ? */ - gpgme_set_armor(*this, 0); - } - - // for unit test - if (args_.test_mode) { - if (info_.GnupgVersion >= "2.1.0") SetPassphraseCb(test_passphrase_cb); - gpgme_set_status_cb(*this, test_status_cb, nullptr); - } - - // preload info - auto &info = GetInfo(); - - // use custom qt dialog to replace pinentry - if (!args_.use_pinentry) { - SetPassphraseCb(custom_passphrase_cb); - } - - connect(this, &GpgContext::SignalNeedUserInputPassphrase, - CoreSignalStation::GetInstance(), - &CoreSignalStation::SignalNeedUserInputPassphrase); -} - -bool GpgContext::good() const { return good_; } - -void GpgContext::SetPassphraseCb(gpgme_passphrase_cb_t cb) const { - if (info_.GnupgVersion >= "2.1.0") { - if (gpgme_get_pinentry_mode(*this) != GPGME_PINENTRY_MODE_LOOPBACK) { - gpgme_set_pinentry_mode(*this, GPGME_PINENTRY_MODE_LOOPBACK); - } - gpgme_set_passphrase_cb(*this, cb, nullptr); - } else { - SPDLOG_ERROR("not supported for gnupg version: {}", info_.GnupgVersion); - } -} - -gpgme_error_t GpgContext::test_passphrase_cb(void *opaque, const char *uid_hint, - const char *passphrase_info, - int last_was_bad, int fd) { - size_t res; - std::string 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); -} - -gpgme_error_t GpgContext::custom_passphrase_cb(void *opaque, - const char *uid_hint, - const char *passphrase_info, - int last_was_bad, int fd) { - SPDLOG_DEBUG("custom passphrase cb called, bad times: {}", last_was_bad); - - if (last_was_bad > 3) { - SPDLOG_WARN("failure_counts is over three times"); - return gpgme_error_from_errno(GPG_ERR_CANCELED); - } - - std::string passphrase = - CoreCommonUtil::GetInstance()->GetTempCacheValue("__key_passphrase"); - // no pawword is an error situation - if (passphrase.empty()) { - // user input passphrase - SPDLOG_DEBUG("might need user to input passparase"); - passphrase = GpgContext::GetInstance().need_user_input_passphrase(); - if (passphrase.empty()) { - gpgme_io_write(fd, "\n", 1); - return gpgme_error_from_errno(GPG_ERR_CANCELED); - } - } - - // the user must at least write a newline character before returning from the - // callback. - passphrase = passphrase.append("\n"); - auto passpahrase_size = passphrase.size(); - - size_t off = 0, res = 0; - do { - res = gpgme_io_write(fd, &passphrase[off], passpahrase_size - off); - if (res > 0) off += res; - } while (res > 0 && off != passpahrase_size); - - return off == passpahrase_size ? 0 : gpgme_error_from_errno(GPG_ERR_CANCELED); -} - -gpgme_error_t GpgContext::test_status_cb(void *hook, const char *keyword, - const char *args) { - SPDLOG_DEBUG("keyword {}", keyword); - return GPG_ERR_NO_ERROR; -} - -std::string GpgContext::need_user_input_passphrase() { - emit SignalNeedUserInputPassphrase(); - - std::string final_passphrase; - bool input_done = false; - SPDLOG_DEBUG("loop start to wait from user"); - auto connection = - connect(CoreSignalStation::GetInstance(), - &CoreSignalStation::SignalUserInputPassphraseDone, this, - [&](QString passphrase) { - SPDLOG_DEBUG("SignalUserInputPassphraseDone emitted"); - final_passphrase = passphrase.toStdString(); - input_done = true; - }); - while (!input_done) { - QCoreApplication::processEvents(QEventLoop::AllEvents, 800); - } - disconnect(connection); - - SPDLOG_DEBUG("lopper end"); - return final_passphrase; -} - -const GpgInfo &GpgContext::GetInfo(bool refresh) { - if (!extend_info_loaded_ || refresh) { - // try lock - std::unique_lock lock(preload_lock_); - - // check twice - if (extend_info_loaded_ && !refresh) return info_; - - SPDLOG_DEBUG("start to load extra info"); - - // get all components - GpgCommandExecutor::GetInstance().Execute( - info_.GpgConfPath, {"--list-components"}, - [=](int exit_code, const std::string &p_out, const std::string &p_err) { - SPDLOG_DEBUG( - "gpgconf components exit_code: {} process stdout size: {}", - exit_code, p_out.size()); - - if (exit_code != 0) { - SPDLOG_ERROR( - "gpgconf execute error, process stderr: {} ,process stdout: " - "{}", - p_err, p_out); - return; - } - - auto &components_info = info_.ComponentsInfo; - components_info["gpgme"] = {"GPG Made Easy", info_.GpgMEVersion, - _("Embedded In"), "/"}; - - auto gpgconf_binary_checksum = - check_binary_chacksum(info_.GpgConfPath); - components_info["gpgconf"] = {"GPG Configure", "/", info_.GpgConfPath, - gpgconf_binary_checksum.has_value() - ? gpgconf_binary_checksum.value() - : "/"}; - - std::vector<std::string> line_split_list; - boost::split(line_split_list, p_out, boost::is_any_of("\n")); - - for (const auto &line : line_split_list) { - std::vector<std::string> info_split_list; - boost::split(info_split_list, line, boost::is_any_of(":")); - - if (info_split_list.size() != 3) continue; - - auto component_name = info_split_list[0]; - auto component_desc = info_split_list[1]; - auto component_path = info_split_list[2]; - - boost::algorithm::trim(component_name); - boost::algorithm::trim(component_desc); - boost::algorithm::trim(component_path); - -#ifdef WINDOWS - // replace some special substrings on windows platform - boost::replace_all(component_path, "%3a", ":"); -#endif - - auto binary_checksum = check_binary_chacksum(component_path); - - SPDLOG_DEBUG( - "gnupg component name: {} desc: {} checksum: {} path: {} ", - component_name, component_desc, - binary_checksum.has_value() ? binary_checksum.value() : "/", - component_path); - - std::string version = "/"; - - if (component_name == "gpg") { - version = info_.GnupgVersion; - } - if (component_name == "gpg-agent") { - info_.GpgAgentPath = component_path; - } - if (component_name == "dirmngr") { - info_.DirmngrPath = component_path; - } - if (component_name == "keyboxd") { - info_.KeyboxdPath = component_path; - } - - { - // try lock - std::unique_lock lock(info_.Lock); - // add component info to list - components_info[component_name] = { - component_desc, version, component_path, - binary_checksum.has_value() ? binary_checksum.value() : "/"}; - } - } - }); - - SPDLOG_DEBUG("start to get dirs info"); - - GpgCommandExecutor::GetInstance().ExecuteConcurrently( - info_.GpgConfPath, {"--list-dirs"}, - [=](int exit_code, const std::string &p_out, const std::string &p_err) { - SPDLOG_DEBUG( - "gpgconf configurations exit_code: {} process stdout size: {}", - exit_code, p_out.size()); - - if (exit_code != 0) { - SPDLOG_ERROR( - "gpgconf execute error, process stderr: {} process stdout: " - "{}", - p_err, p_out); - return; - } - - auto &configurations_info = info_.ConfigurationsInfo; - - std::vector<std::string> line_split_list; - boost::split(line_split_list, p_out, boost::is_any_of("\n")); - - for (const auto &line : line_split_list) { - std::vector<std::string> info_split_list; - boost::split(info_split_list, line, boost::is_any_of(":")); - SPDLOG_DEBUG("gpgconf info line: {} info size: {}", line, - info_split_list.size()); - - if (info_split_list.size() != 2) continue; - - auto configuration_name = info_split_list[0]; - auto configuration_value = info_split_list[1]; - boost::algorithm::trim(configuration_name); - boost::algorithm::trim(configuration_value); - -#ifdef WINDOWS - // replace some special substrings on windows platform - boost::replace_all(configuration_value, "%3a", ":"); -#endif - - // record gnupg home path - if (configuration_name == "homedir") { - info_.GnuPGHomePath = info_split_list[1]; - } - - { - // try lock - std::unique_lock lock(info_.Lock); - configurations_info[configuration_name] = {configuration_value}; - } - } - }); - - SPDLOG_DEBUG("start to get components info"); - - for (const auto &component : info_.ComponentsInfo) { - SPDLOG_DEBUG("gpgconf check options ready", "component", component.first); - - if (component.first == "gpgme" || component.first == "gpgconf") continue; - - GpgCommandExecutor::GetInstance().ExecuteConcurrently( - info_.GpgConfPath, {"--check-options", component.first}, - [=](int exit_code, const std::string &p_out, - const std::string &p_err) { - SPDLOG_DEBUG( - "gpgconf {} options exit_code: {} process stdout " - "size: {} ", - component.first, exit_code, p_out.size()); - - if (exit_code != 0) { - SPDLOG_ERROR( - "gpgconf {} options execute error, process " - "stderr: {} , process stdout:", - component.first, p_err, p_out); - return; - } - - auto &options_info = info_.OptionsInfo; - - std::vector<std::string> line_split_list; - boost::split(line_split_list, p_out, boost::is_any_of("\n")); - - for (const auto &line : line_split_list) { - std::vector<std::string> info_split_list; - boost::split(info_split_list, line, boost::is_any_of(":")); - - SPDLOG_DEBUG("component {} options line: {} info size: {}", - component.first, line, info_split_list.size()); - - if (info_split_list.size() != 6) continue; - - auto configuration_name = info_split_list[0]; - boost::algorithm::trim(configuration_name); - { - // try lock - std::unique_lock lock(info_.Lock); - options_info[configuration_name] = { - info_split_list[1], info_split_list[2], info_split_list[3], - info_split_list[4], info_split_list[5]}; - - boost::algorithm::trim(options_info[configuration_name][0]); - boost::algorithm::trim(options_info[configuration_name][1]); - boost::algorithm::trim(options_info[configuration_name][2]); - boost::algorithm::trim(options_info[configuration_name][3]); - boost::algorithm::trim(options_info[configuration_name][4]); - } - } - }); - } - - SPDLOG_DEBUG("start to get avaliable component options info"); - - for (const auto &component : info_.ComponentsInfo) { - SPDLOG_DEBUG("gpgconf list options ready", "component", component.first); - - if (component.first == "gpgme" || component.first == "gpgconf") continue; - - GpgCommandExecutor::GetInstance().ExecuteConcurrently( - info_.GpgConfPath, {"--list-options", component.first}, - [=](int exit_code, const std::string &p_out, - const std::string &p_err) { - SPDLOG_DEBUG( - "gpgconf {} avaliable options exit_code: {} process stdout " - "size: {} ", - component.first, exit_code, p_out.size()); - - if (exit_code != 0) { - SPDLOG_ERROR( - "gpgconf {} avaliable options execute error, process stderr: " - "{} , process stdout:", - component.first, p_err, p_out); - return; - } - - auto &available_options_info = info_.AvailableOptionsInfo; - - std::vector<std::string> line_split_list; - boost::split(line_split_list, p_out, boost::is_any_of("\n")); - - for (const auto &line : line_split_list) { - std::vector<std::string> info_split_list; - boost::split(info_split_list, line, boost::is_any_of(":")); - - SPDLOG_DEBUG( - "component {} avaliable options line: {} info size: {}", - component.first, line, info_split_list.size()); - - if (info_split_list.size() != 10) continue; - - auto configuration_name = info_split_list[0]; - boost::algorithm::trim(configuration_name); - { - // try lock - std::unique_lock lock(info_.Lock); - available_options_info[configuration_name] = { - info_split_list[1], info_split_list[2], info_split_list[3], - info_split_list[4], info_split_list[5], info_split_list[6], - info_split_list[7], info_split_list[8], info_split_list[9]}; - - boost::algorithm::trim( - available_options_info[configuration_name][0]); - boost::algorithm::trim( - available_options_info[configuration_name][1]); - boost::algorithm::trim( - available_options_info[configuration_name][2]); - boost::algorithm::trim( - available_options_info[configuration_name][3]); - boost::algorithm::trim( - available_options_info[configuration_name][4]); - boost::algorithm::trim( - available_options_info[configuration_name][5]); - boost::algorithm::trim( - available_options_info[configuration_name][6]); - boost::algorithm::trim( - available_options_info[configuration_name][7]); - boost::algorithm::trim( - available_options_info[configuration_name][8]); - } - } - }); - } - extend_info_loaded_ = true; - } - - // ensure nothing is changing now - std::shared_lock lock(preload_lock_); - return info_; -} - -std::optional<std::string> GpgContext::check_binary_chacksum( - std::filesystem::path path) { - // check file info and access rights - QFileInfo info(QString::fromStdString(path.u8string())); - if (!info.exists() || !info.isFile() || !info.isReadable()) { - SPDLOG_ERROR("get info for file {} error, exists: {}", - info.filePath().toStdString(), info.exists()); - return {}; - } - - // open and read file - QFile f(info.filePath()); - if (!f.open(QIODevice::ReadOnly)) { - SPDLOG_ERROR("open {} to calculate check sum error: {}", path.u8string(), - f.errorString().toStdString()); - return {}; - } - - // read all data from file - auto buffer = f.readAll(); - f.close(); - - auto hash_sha = QCryptographicHash(QCryptographicHash::Sha256); - // md5 - hash_sha.addData(buffer); - auto sha = hash_sha.result().toHex().toStdString(); - SPDLOG_DEBUG("checksum for file {} is {}", path.u8string(), sha); - - return sha.substr(0, 6); -} - -void GpgContext::_ctx_ref_deleter::operator()(gpgme_ctx_t _ctx) { - if (_ctx != nullptr) gpgme_release(_ctx); -} - -} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/GpgContext.h b/src/core/GpgContext.h deleted file mode 100644 index 474530c6..00000000 --- a/src/core/GpgContext.h +++ /dev/null @@ -1,210 +0,0 @@ -/** - * Copyright (C) 2021 Saturneric - * - * This file is part of GpgFrontend. - * - * GpgFrontend is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GpgFrontend is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GpgFrontend. If not, see <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 - * - */ - -#ifndef __SGPGMEPP_CONTEXT_H__ -#define __SGPGMEPP_CONTEXT_H__ - -#include <optional> -#include <string> - -#include "GpgFunctionObject.h" -#include "GpgInfo.h" - -namespace GpgFrontend { - -/** - * @brief - * - */ -struct GpgContextInitArgs { - // make no sense for gpg2 - bool independent_database = false; ///< - std::string db_path = {}; - - bool gpg_alone = false; - std::string gpg_path = {}; - - bool test_mode = false; - bool ascii = true; - bool offline_mode = false; - bool auto_import_missing_key = false; - - bool custom_gpgconf = false; - std::string custom_gpgconf_path; - - bool use_pinentry = false; - - GpgContextInitArgs() = default; -}; - -/** - * @brief - * - */ -class GPGFRONTEND_CORE_EXPORT GpgContext - : public QObject, - public SingletonFunctionObject<GpgContext> { - Q_OBJECT - public: - /** - * @brief Construct a new Gpg Context object - * - * @param args - */ - explicit GpgContext(const GpgContextInitArgs& args = {}); - - /** - * @brief Construct a new Gpg Context object - * - * @param channel - */ - explicit GpgContext(int channel); - - /** - * @brief Destroy the Gpg Context object - * - */ - ~GpgContext() override = default; - - /** - * @brief - * - * @return true - * @return false - */ - [[nodiscard]] bool good() const; - - /** - * @brief Get the Info object - * - * @return const GpgInfo& - */ - [[nodiscard]] const GpgInfo& GetInfo(bool refresh = false); - - /** - * @brief - * - * @return gpgme_ctx_t - */ - operator gpgme_ctx_t() const { return _ctx_ref.get(); } - - private: - GpgInfo info_{}; ///< - GpgContextInitArgs args_{}; ///< - bool extend_info_loaded_ = false; - std::shared_mutex preload_lock_{}; - - /** - * @brief - * - */ - void post_init_ctx(); - - /** - * @brief - * - * @return std::string - */ - std::string need_user_input_passphrase(); - - /** - * @brief Construct a new std::check component existence object - * - */ - std::optional<std::string> check_binary_chacksum(std::filesystem::path); - - /** - * @brief - * - */ - struct _ctx_ref_deleter { - void operator()(gpgme_ctx_t _ctx); - }; - - using CtxRefHandler = - std::unique_ptr<struct gpgme_context, _ctx_ref_deleter>; ///< - CtxRefHandler _ctx_ref = nullptr; ///< - bool good_ = true; ///< - - signals: - /** - * @brief - * - */ - void SignalNeedUserInputPassphrase(); - - public: - /** - * @brief - * - * @param opaque - * @param uid_hint - * @param passphrase_info - * @param last_was_bad - * @param fd - * @return gpgme_error_t - */ - static gpgme_error_t test_passphrase_cb(void* opaque, const char* uid_hint, - const char* passphrase_info, - int last_was_bad, int fd); - - /** - * @brief - * - * @param opaque - * @param uid_hint - * @param passphrase_info - * @param last_was_bad - * @param fd - * @return gpgme_error_t - */ - static gpgme_error_t custom_passphrase_cb(void* opaque, const char* uid_hint, - const char* passphrase_info, - int last_was_bad, int fd); - - /** - * @brief - * - * @param hook - * @param keyword - * @param args - * @return gpgme_error_t - */ - static gpgme_error_t test_status_cb(void* hook, const char* keyword, - const char* args); - - /** - * @brief Set the Passphrase Cb object - * - * @param func - */ - void SetPassphraseCb(gpgme_passphrase_cb_t func) const; -}; -} // namespace GpgFrontend - -#endif // __SGPGMEPP_CONTEXT_H__
\ No newline at end of file diff --git a/src/core/GpgCoreInit.cpp b/src/core/GpgCoreInit.cpp index 6d782439..f231056f 100644 --- a/src/core/GpgCoreInit.cpp +++ b/src/core/GpgCoreInit.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,236 +20,445 @@ * 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 "GpgCoreInit.h" -#include <spdlog/async.h> -#include <spdlog/common.h> -#include <spdlog/sinks/rotating_file_sink.h> -#include <spdlog/sinks/stdout_color_sinks.h> +#include <gpgme.h> -#include <filesystem> -#include <string> - -#include "GpgFunctionObject.h" -#include "core/GpgContext.h" +#include "core/function/CoreSignalStation.h" #include "core/function/GlobalSettingStation.h" -#include "function/gpg/GpgAdvancedOperator.h" -#include "spdlog/spdlog.h" -#include "thread/Task.h" -#include "thread/TaskRunner.h" -#include "thread/TaskRunnerGetter.h" +#include "core/function/basic/ChannelObject.h" +#include "core/function/basic/SingletonStorage.h" +#include "core/function/gpg/GpgAdvancedOperator.h" +#include "core/function/gpg/GpgContext.h" +#include "core/function/gpg/GpgKeyGetter.h" +#include "core/module/ModuleManager.h" +#include "core/thread/Task.h" +#include "core/thread/TaskRunner.h" +#include "core/thread/TaskRunnerGetter.h" +#include "core/utils/CommonUtils.h" +#include "core/utils/GpgUtils.h" +#include "core/utils/MemoryUtils.h" namespace GpgFrontend { -/** - * @brief setup logging system and do proper initialization - * - */ -void InitCoreLoggingSystem() { - using namespace boost::posix_time; - using namespace boost::gregorian; - - // get the log directory - auto logfile_path = - (GlobalSettingStation::GetInstance().GetLogDir() / "core"); - logfile_path.replace_extension(".log"); - - // sinks - std::vector<spdlog::sink_ptr> sinks; - sinks.push_back(std::make_shared<spdlog::sinks::stderr_color_sink_mt>()); - sinks.push_back(std::make_shared<spdlog::sinks::rotating_file_sink_mt>( - logfile_path.u8string(), 1048576 * 32, 8)); - - // thread pool - spdlog::init_thread_pool(1024, 2); - - // logger - auto core_logger = std::make_shared<spdlog::async_logger>( - "core", begin(sinks), end(sinks), spdlog::thread_pool()); - core_logger->set_pattern( - "[%H:%M:%S.%e] [T:%t] [%=4n] %^[%=8l]%$ [%s:%#] [%!] -> %v (+%ius)"); - -#ifdef DEBUG - core_logger->set_level(spdlog::level::trace); -#else - core_logger->set_level(spdlog::level::info); -#endif +void DestroyGpgFrontendCore() { SingletonStorageCollection::Destroy(); } - // flush policy - core_logger->flush_on(spdlog::level::err); - spdlog::flush_every(std::chrono::seconds(5)); +auto VerifyGpgconfPath(const QFileInfo& gnupg_install_fs_path) -> bool { + return gnupg_install_fs_path.isAbsolute() && gnupg_install_fs_path.exists() && + gnupg_install_fs_path.isFile(); +} - // register it as default logger - spdlog::set_default_logger(core_logger); +auto VerifyKeyDatabasePath(const QFileInfo& key_database_fs_path) -> bool { + return key_database_fs_path.isAbsolute() && key_database_fs_path.exists() && + key_database_fs_path.isDir(); } -void ShutdownCoreLoggingSystem() { -#ifdef WINDOWS - // Under VisualStudio, this must be called before main finishes to workaround - // a known VS issue - spdlog::drop_all(); - spdlog::shutdown(); -#endif +auto SearchGpgconfPath(const QList<QString>& candidate_paths) -> QString { + for (const auto& path : candidate_paths) { + if (VerifyGpgconfPath(QFileInfo(path))) { + return path; + } + } + return {}; } -void ResetGpgFrontendCore() { reset_gpgfrontend_core(); } +auto SearchKeyDatabasePath(const QList<QString>& candidate_paths) -> QString { + for (const auto& path : candidate_paths) { + GF_CORE_LOG_DEBUG("searh for candidate key database path: {}", path); + if (VerifyKeyDatabasePath(QFileInfo(path))) { + return path; + } + } + return {}; +} + +auto InitGpgME(const QString& gnupg_path) -> bool { + // init gpgme subsystem and get gpgme library version + Module::UpsertRTValue("core", "gpgme.version", + QString(gpgme_check_version(nullptr))); -void init_gpgfrontend_core() { - /* Initialize the locale environment. */ - SPDLOG_DEBUG("locale: {}", setlocale(LC_CTYPE, nullptr)); - // init gpgme subsystem - gpgme_check_version(nullptr); gpgme_set_locale(nullptr, LC_CTYPE, setlocale(LC_CTYPE, nullptr)); #ifdef LC_MESSAGES gpgme_set_locale(nullptr, LC_MESSAGES, setlocale(LC_MESSAGES, nullptr)); #endif - // read settings - bool forbid_all_gnupg_connection = - GlobalSettingStation::GetInstance().LookupSettings( - "network.forbid_all_gnupg_connection", false); + if (!gnupg_path.isEmpty()) { + GF_CORE_LOG_DEBUG("gpgme set engine info, gnupg path: {}", gnupg_path); + CheckGpgError(gpgme_set_engine_info(GPGME_PROTOCOL_OPENPGP, + gnupg_path.toUtf8(), nullptr)); + } + + gpgme_ctx_t p_ctx; + CheckGpgError(gpgme_new(&p_ctx)); + + // get engine info + auto* engine_info = gpgme_ctx_get_engine_info(p_ctx); + // Check ENV before running + bool find_openpgp = false; + bool find_gpgconf = false; + bool find_cms = false; + + while (engine_info != nullptr) { + if (strcmp(engine_info->version, "1.0.0") == 0) { + engine_info = engine_info->next; + continue; + } + + GF_CORE_LOG_DEBUG( + "gpg context engine info: {} {} {} {}", + gpgme_get_protocol_name(engine_info->protocol), + QString(engine_info->file_name == nullptr ? "null" + : engine_info->file_name), + QString(engine_info->home_dir == nullptr ? "null" + : engine_info->home_dir), + QString(engine_info->version ? "null" : engine_info->version)); + + switch (engine_info->protocol) { + case GPGME_PROTOCOL_OpenPGP: + find_openpgp = true; + + Module::UpsertRTValue("core", "gpgme.engine.openpgp", 1); + Module::UpsertRTValue("core", "gpgme.ctx.app_path", + QString(engine_info->file_name)); + Module::UpsertRTValue("core", "gpgme.ctx.gnupg_version", + QString(engine_info->version)); + Module::UpsertRTValue( + "core", "gpgme.ctx.database_path", + QString(engine_info->home_dir == nullptr ? "" + : engine_info->home_dir)); + break; + case GPGME_PROTOCOL_CMS: + find_cms = true; + Module::UpsertRTValue("core", "gpgme.engine.cms", 1); + Module::UpsertRTValue("core", "gpgme.ctx.cms_path", + QString(engine_info->file_name)); + + break; + case GPGME_PROTOCOL_GPGCONF: + find_gpgconf = true; + + Module::UpsertRTValue("core", "gpgme.engine.gpgconf", 1); + Module::UpsertRTValue("core", "gpgme.ctx.gpgconf_path", + QString(engine_info->file_name)); + break; + case GPGME_PROTOCOL_ASSUAN: + + Module::UpsertRTValue("core", "gpgme.engine.assuan", 1); + Module::UpsertRTValue("core", "gpgme.ctx.assuan_path", + QString(engine_info->file_name)); + break; + case GPGME_PROTOCOL_G13: + break; + case GPGME_PROTOCOL_UISERVER: + break; + case GPGME_PROTOCOL_SPAWN: + break; + case GPGME_PROTOCOL_DEFAULT: + break; + case GPGME_PROTOCOL_UNKNOWN: + break; + } + engine_info = engine_info->next; + } + + // release gpgme context + gpgme_release(p_ctx); + + const auto gnupg_version = Module::RetrieveRTValueTypedOrDefault<>( + "core", "gpgme.ctx.gnupg_version", QString{"0.0.0"}); + GF_CORE_LOG_DEBUG("got gnupg version from rt: {}", gnupg_version); - bool auto_import_missing_key = - GlobalSettingStation::GetInstance().LookupSettings( - "network.auto_import_missing_key", false); + // conditional check: only support gpg 2.1.x now + if (!(CompareSoftwareVersion(gnupg_version, "2.1.0") >= 0 && find_gpgconf && + find_openpgp && find_cms)) { + GF_CORE_LOG_ERROR("gpgme env check failed, abort"); + return false; + } + + Module::UpsertRTValue("core", "env.state.gpgme", 1); + return true; +} - bool use_custom_key_database_path = - GlobalSettingStation::GetInstance().LookupSettings( - "general.use_custom_key_database_path", false); +auto GetGnuPGPathByGpgConf(const QString& gnupg_install_fs_path) -> QString { + auto* process = new QProcess(); + process->setProgram(gnupg_install_fs_path); + process->start(); + process->waitForFinished(1000); + auto output_buffer = process->readAllStandardOutput(); + process->deleteLater(); - std::string custom_key_database_path = - GlobalSettingStation::GetInstance().LookupSettings( - "general.custom_key_database_path", std::string{}); + if (output_buffer.isEmpty()) return {}; - bool use_custom_gnupg_install_path = - GlobalSettingStation::GetInstance().LookupSettings( - "general.use_custom_gnupg_install_path", false); + auto line_split_list = QString(output_buffer).split("\n"); + for (const auto& line : line_split_list) { + auto info_split_list = line.split(":"); - std::string custom_gnupg_install_path = - GlobalSettingStation::GetInstance().LookupSettings( - "general.custom_gnupg_install_path", std::string{}); + if (info_split_list.size() != 3) continue; - bool use_pinentry_as_password_input_dialog = - GpgFrontend::GlobalSettingStation::GetInstance().LookupSettings( - "general.use_pinentry_as_password_input_dialog", false); + auto component_name = info_split_list[0].trimmed(); + auto component_desc = info_split_list[1].trimmed(); + auto component_path = info_split_list[2].trimmed(); - SPDLOG_DEBUG("core loaded if use custom key databse path: {}", - use_custom_key_database_path); - SPDLOG_DEBUG("core loaded custom key databse path: {}", - custom_key_database_path); + if (component_name.toLower() == "gpg") { +#ifdef WINDOWS + // replace some special substrings on windows platform + component_path.replace("%3a", ":"); +#endif + QFileInfo file_info(component_path); + if (file_info.exists() && file_info.isFile()) { + return file_info.absoluteFilePath(); + } + return {}; + } + } + return ""; +} - // check gpgconf path - std::filesystem::path custom_gnupg_install_fs_path = - custom_gnupg_install_path; +auto DetectGnuPGPath() -> QString { + auto settings = GlobalSettingStation::GetInstance().GetSettings(); + auto use_custom_gnupg_install_path = + settings.value("basic/use_custom_gnupg_install_path", false).toBool(); + auto custom_gnupg_install_path = + settings.value("basic/custom_gnupg_install_path", QString{}).toString(); + + QString gnupg_install_fs_path; + // user defined + if (use_custom_gnupg_install_path && !custom_gnupg_install_path.isEmpty()) { + // check gpgconf path + gnupg_install_fs_path = custom_gnupg_install_path; #ifdef WINDOWS - custom_gnupg_install_fs_path /= "gpgconf.exe"; + gnupg_install_fs_path += "/gpgconf.exe"; #else - custom_gnupg_install_fs_path /= "gpgconf"; + gnupg_install_fs_path += "/gpgconf"; #endif - if (!custom_gnupg_install_fs_path.is_absolute() || - !std::filesystem::exists(custom_gnupg_install_fs_path) || - !std::filesystem::is_regular_file(custom_gnupg_install_fs_path)) { - use_custom_gnupg_install_path = false; - SPDLOG_ERROR("core loaded custom gpgconf path is illegal: {}", - custom_gnupg_install_fs_path.u8string()); - } else { - SPDLOG_DEBUG("core loaded custom gpgconf path: {}", - custom_gnupg_install_fs_path.u8string()); + if (!VerifyGpgconfPath(QFileInfo(gnupg_install_fs_path))) { + GF_CORE_LOG_ERROR("core loaded custom gpgconf path is illegal: {}", + gnupg_install_fs_path); + gnupg_install_fs_path = ""; + } } - // check key database path - std::filesystem::path custom_key_database_fs_path = custom_key_database_path; - if (!custom_key_database_fs_path.is_absolute() || - !std::filesystem::exists(custom_key_database_fs_path) || - !std::filesystem::is_directory(custom_key_database_fs_path)) { - use_custom_key_database_path = false; - SPDLOG_ERROR("core loaded custom gpg key database is illegal: {}", - custom_key_database_fs_path.u8string()); - } else { - SPDLOG_DEBUG("core loaded custom gpg key database path: {}", - custom_key_database_fs_path.u8string()); + // fallback to default path + if (gnupg_install_fs_path.isEmpty()) { +#ifdef MACOS + gnupg_install_fs_path = SearchGpgconfPath( + {"/usr/local/bin/gpgconf", "/opt/homebrew/bin/gpgconf"}); + GF_CORE_LOG_DEBUG("core loaded searched gpgconf path: {}", + gnupg_install_fs_path); +#endif + +#ifdef WINDOWS + gnupg_install_fs_path = + SearchGpgconfPath({"C:/Program Files (x86)/gnupg/bin"}); + GF_CORE_LOG_DEBUG("core loaded searched gpgconf path: {}", + gnupg_install_fs_path); +#endif } - // init default channel - auto& default_ctx = GpgFrontend::GpgContext::CreateInstance( - GPGFRONTEND_DEFAULT_CHANNEL, [=]() -> std::unique_ptr<ChannelObject> { - GpgFrontend::GpgContextInitArgs args; + if (!gnupg_install_fs_path.isEmpty()) { + return GetGnuPGPathByGpgConf( + QFileInfo(gnupg_install_fs_path).absoluteFilePath()); + } + return ""; +} - // set key database path - if (use_custom_key_database_path && !custom_key_database_path.empty()) { - args.db_path = custom_key_database_path; - } +void InitGpgFrontendCore(CoreInitArgs args) { + // initialize global register table + Module::UpsertRTValue("core", "env.state.gpgme", 0); + Module::UpsertRTValue("core", "env.state.ctx", 0); + Module::UpsertRTValue("core", "env.state.gnupg", 0); + Module::UpsertRTValue("core", "env.state.basic", 0); + Module::UpsertRTValue("core", "env.state.all", 0); + + // initialize locale environment + GF_CORE_LOG_DEBUG("locale: {}", setlocale(LC_CTYPE, nullptr)); + + auto gnupg_install_fs_path = DetectGnuPGPath(); + GF_CORE_LOG_INFO("detected gnupg path: {}", gnupg_install_fs_path); + + // initialize library gpgme + if (!InitGpgME(gnupg_install_fs_path)) { + CoreSignalStation::GetInstance()->SignalBadGnupgEnv( + QObject::tr("GpgME inilization failed")); + return; + } - if (use_custom_gnupg_install_path) { - args.custom_gpgconf = true; - args.custom_gpgconf_path = custom_gnupg_install_fs_path.u8string(); + auto* task = new Thread::Task( + [args, gnupg_install_fs_path](const DataObjectPtr&) -> int { + auto settings = GlobalSettingStation::GetInstance().GetSettings(); + // read settings from config file + auto forbid_all_gnupg_connection = + settings.value("network/forbid_all_gnupg_connection", false) + .toBool(); + + auto auto_import_missing_key = + settings.value("network/auto_import_missing_key", false).toBool(); + + auto use_custom_key_database_path = + settings.value("basic/use_custom_key_database_path", false) + .toBool(); + + auto custom_key_database_path = + settings.value("basic/custom_key_database_path", QString{}) + .toString(); + + auto custom_gnupg_install_path = + settings.value("basic/custom_gnupg_install_path", QString{}) + .toString(); + + auto use_pinentry_as_password_input_dialog = + settings.value("basic/use_pinentry_as_password_input_dialog", false) + .toBool(); + + GF_CORE_LOG_DEBUG("core loaded if use custom key databse path: {}", + use_custom_key_database_path); + GF_CORE_LOG_DEBUG("core loaded custom key databse path: {}", + custom_key_database_path); + + // check key database path + QString key_database_fs_path; + // user defined + if (use_custom_key_database_path && + !custom_key_database_path.isEmpty()) { + key_database_fs_path = custom_key_database_path; + if (VerifyKeyDatabasePath(QFileInfo(key_database_fs_path))) { + GF_CORE_LOG_ERROR( + "core loaded custom gpg key database is illegal: {}", + key_database_fs_path); + } else { + use_custom_key_database_path = true; + GF_CORE_LOG_DEBUG("core loaded custom gpg key database path: {}", + key_database_fs_path); + } + } else { +#if defined(LINUX) || defined(MACOS) + use_custom_key_database_path = true; + key_database_fs_path = + SearchKeyDatabasePath({QDir::home().path() + "/.gnupg"}); + GF_CORE_LOG_DEBUG("core loaded searched key database path: {}", + key_database_fs_path); +#endif } - args.offline_mode = forbid_all_gnupg_connection; - args.auto_import_missing_key = auto_import_missing_key; - args.use_pinentry = use_pinentry_as_password_input_dialog; - - return std::unique_ptr<ChannelObject>(new GpgContext(args)); - }); - - // exit if failed - if (!default_ctx.good()) { - SPDLOG_ERROR("default gnupg context init error"); - }; - - // async init no-ascii channel - Thread::TaskRunnerGetter::GetInstance() - .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_GPG) - ->PostTask( - new Thread::Task([=](Thread::Task::DataObjectPtr data_obj) -> int { - // init non-ascii channel - auto& ctx = GpgFrontend::GpgContext::CreateInstance( - GPGFRONTEND_NON_ASCII_CHANNEL, - [=]() -> std::unique_ptr<ChannelObject> { - GpgFrontend::GpgContextInitArgs args; - args.ascii = false; - - // set key database path - if (use_custom_key_database_path && - !custom_key_database_path.empty()) { - args.db_path = custom_key_database_path; + if (args.load_default_gpg_context) { + // init ctx, also checking the basical env + auto& ctx = GpgFrontend::GpgContext::CreateInstance( + kGpgFrontendDefaultChannel, [=]() -> ChannelObjectPtr { + GpgFrontend::GpgContextInitArgs args; + + // set key database path + if (use_custom_key_database_path && + !key_database_fs_path.isEmpty()) { + QFileInfo dir_info(key_database_fs_path); + if (dir_info.exists() && dir_info.isDir() && + dir_info.isReadable() && dir_info.isWritable()) { + args.db_path = dir_info.absoluteFilePath(); + GF_CORE_LOG_INFO("using key database path: {}", + args.db_path); + } else { + GF_CORE_LOG_ERROR( + "custom key database path: {}, is not point to " + "an accessible directory", + key_database_fs_path); } + } + + // set custom gnupg path + if (!gnupg_install_fs_path.isEmpty()) { + args.custom_gpgconf = true; + args.custom_gpgconf_path = gnupg_install_fs_path; + } + + args.offline_mode = forbid_all_gnupg_connection; + args.auto_import_missing_key = auto_import_missing_key; + args.use_pinentry = use_pinentry_as_password_input_dialog; + + return ConvertToChannelObjectPtr<>( + SecureCreateUniqueObject<GpgContext>( + args, kGpgFrontendDefaultChannel)); + }); + + // exit if failed + if (!ctx.Good()) { + GF_CORE_LOG_ERROR("default gnupg context init error, abort"); + CoreSignalStation::GetInstance()->SignalBadGnupgEnv( + QObject::tr("GpgME Context inilization failed")); + return -1; + } + Module::UpsertRTValue("core", "env.state.ctx", 1); + } - if (use_custom_gnupg_install_path) { - args.custom_gpgconf = true; - args.custom_gpgconf_path = - custom_gnupg_install_fs_path.u8string(); - } - - args.offline_mode = forbid_all_gnupg_connection; - args.auto_import_missing_key = auto_import_missing_key; - args.use_pinentry = use_pinentry_as_password_input_dialog; - - return std::unique_ptr<ChannelObject>(new GpgContext(args)); - }); - - if (!ctx.good()) SPDLOG_ERROR("no-ascii channel init error"); - return ctx.good() ? 0 : -1; - })); + if (args.load_default_gpg_context) { + if (!GpgKeyGetter::GetInstance().FlushKeyCache()) { + CoreSignalStation::GetInstance()->SignalBadGnupgEnv( + QObject::tr("Gpg Key Detabase inilization failed")); + }; + } + GF_CORE_LOG_DEBUG( + "basic env checking finished, " + "including gpgme, ctx, and key infos"); + Module::UpsertRTValue("core", "env.state.basic", 1); + CoreSignalStation::GetInstance()->SignalGoodGnupgEnv(); + + // if gnupg-info-gathering module activated + if (args.gather_external_gnupg_info && + Module::IsModuleAcivate("com.bktus.gpgfrontend.module." + "integrated.gnupg-info-gathering")) { + GF_CORE_LOG_DEBUG( + "module gnupg-info-gathering is activated, " + "loading external gnupg info..."); + + // gather external gnupg info + Module::TriggerEvent( + "GPGFRONTEND_CORE_INITLIZED", + [](const Module::EventIdentifier& /*e*/, + const Module::Event::ListenerIdentifier& l_id, + DataObjectPtr o) { + GF_CORE_LOG_DEBUG( + "received event GPGFRONTEND_CORE_INITLIZED callback " + "from module: {}", + l_id); + + if (l_id == + "com.bktus.gpgfrontend.module.integrated.gnupg-info-" + "gathering") { + GF_CORE_LOG_DEBUG( + "received callback from gnupg-info-gathering "); + + // try to restart all components + GpgFrontend::GpgAdvancedOperator::RestartGpgComponents(); + Module::UpsertRTValue("core", "env.state.gnupg", 1); + + // announce that all checkings were finished + GF_CORE_LOG_INFO( + "all env checking finished, including gpgme, " + "ctx and gnupg"); + Module::UpsertRTValue("core", "env.state.all", 1); + } + }); + } else { + GF_CORE_LOG_DEBUG("gnupg-info-gathering is not activated"); + Module::UpsertRTValue("core", "env.state.all", 1); + } + return 0; + }, + "core_init_task"); - // try to restart all components - GpgFrontend::GpgAdvancedOperator::GetInstance().RestartGpgComponents(); -} + QObject::connect(task, &Thread::Task::SignalTaskEnd, []() { -void reset_gpgfrontend_core() { SingletonStorageCollection::GetInstance(true); } + }); -void new_default_settings_channel(int channel) { - GpgFrontend::GpgContext::CreateInstance( - channel, [&]() -> std::unique_ptr<ChannelObject> { - GpgFrontend::GpgContextInitArgs args; - return std::unique_ptr<ChannelObject>(new GpgContext(args)); - }); + // start the thread to check ctx and gnupg state + // it may take a few seconds or minutes + GpgFrontend::Thread::TaskRunnerGetter::GetInstance() + .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_Default) + ->PostTask(task); } } // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/GpgCoreInit.h b/src/core/GpgCoreInit.h index 41e04d60..15f0254d 100644 --- a/src/core/GpgCoreInit.h +++ b/src/core/GpgCoreInit.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,57 +20,33 @@ * 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_GPGCOREINIT_H -#define GPGFRONTEND_GPGCOREINIT_H +#pragma once #include "GpgConstants.h" namespace GpgFrontend { -/** - * @brief - * - */ -void GPGFRONTEND_CORE_EXPORT InitCoreLoggingSystem(); - -/** - * @brief - * - */ -void GPGFRONTEND_CORE_EXPORT ShutdownCoreLoggingSystem(); - -/** - * @brief - * - */ -void GPGFRONTEND_CORE_EXPORT ResetGpgFrontendCore(); - -/** - * @brief - * - */ -void init_gpgfrontend_core(); +struct CoreInitArgs { + bool gather_external_gnupg_info; + bool load_default_gpg_context; +}; /** * @brief * */ -void reset_gpgfrontend_core(); +void GPGFRONTEND_CORE_EXPORT DestroyGpgFrontendCore(); /** * @brief * - * @param channel */ -void new_default_settings_channel( - int channel = GpgFrontend::GPGFRONTEND_DEFAULT_CHANNEL); +void GPGFRONTEND_CORE_EXPORT InitGpgFrontendCore(CoreInitArgs); } // namespace GpgFrontend - -#endif // GPGFRONTEND_GPGCOREINIT_H diff --git a/src/core/GpgInfo.cpp b/src/core/GpgFrontendCore.cpp index a77f0ed4..82ed09f4 100644 --- a/src/core/GpgInfo.cpp +++ b/src/core/GpgFrontendCore.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,10 +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 * */ -#include "core/GpgInfo.h" +#include "core/GpgFrontendCore.h" diff --git a/src/core/GpgFrontendCore.h b/src/core/GpgFrontendCore.h index 0b433b96..14b1f878 100644 --- a/src/core/GpgFrontendCore.h +++ b/src/core/GpgFrontendCore.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,56 +20,33 @@ * 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_GPGFRONTENDCORE_H -#define GPGFRONTEND_GPGFRONTENDCORE_H +#pragma once -#include "GpgFrontend.h" - -// gnupg -#include <gpgme.h> +// Qt +#include <QtCore> -// std includes -#include <cassert> -#include <filesystem> -#include <functional> -#include <map> -#include <memory> -#include <mutex> -#include <random> -#include <shared_mutex> -#include <stdexcept> -#include <string> -#include <typeinfo> -#include <utility> +// std +#include <cstdint> #include <vector> -// boost includes -#include <boost/date_time.hpp> -#include <boost/date_time/posix_time/conversion.hpp> -#include <boost/filesystem/operations.hpp> -#include <boost/filesystem/path.hpp> -#include <boost/format.hpp> +// spdlog library configuration +#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_TRACE +#include <spdlog/spdlog.h> -// Qt includes -#include <QtCore> +// logger fmt +#include "log/QtLoggerFmt.h" -// libconfig includes -#include <libconfig.h++> - -// libarchive includes -#include <libarchive/libarchive/archive.h> -#include <libarchive/libarchive/archive_entry.h> +// gpgme library +#include <gpgme.h> -// json includes -#include <nlohmann/json.hpp> +// logbal includes or macroes +#include "GpgFrontend.h" -// dll export macro +// dll export macroes #include "GpgFrontendCoreExport.h" - -#endif // GPGFRONTEND_GPGFRONTENDCORE_H diff --git a/src/core/GpgFunctionObject.cpp b/src/core/GpgFunctionObject.cpp deleted file mode 100644 index 0ddc290c..00000000 --- a/src/core/GpgFunctionObject.cpp +++ /dev/null @@ -1,137 +0,0 @@ -/** - * Copyright (C) 2021 Saturneric - * - * This file is part of GpgFrontend. - * - * GpgFrontend is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GpgFrontend is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GpgFrontend. If not, see <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/GpgFunctionObject.h" - -#include <cassert> -#include <functional> -#include <memory> -#include <mutex> -#include <shared_mutex> - -void GpgFrontend::ChannelObject::SetChannel(int channel) { - this->channel_ = channel; -} - -int GpgFrontend::ChannelObject::GetChannel() const { return channel_; } - -int GpgFrontend::ChannelObject::GetDefaultChannel() { return _default_channel; } - -void GpgFrontend::SingletonStorage::ReleaseChannel(int channel) { - decltype(instances_map_.end()) _it; - { - std::shared_lock<std::shared_mutex> lock(instances_mutex_); - _it = instances_map_.find(channel); - } - if (_it != instances_map_.end()) instances_map_.erase(_it); -} - -GpgFrontend::ChannelObject* GpgFrontend::SingletonStorage::FindObjectInChannel( - int channel) { - // read instances_map_ - decltype(instances_map_.end()) _it; - { - std::shared_lock<std::shared_mutex> lock(instances_mutex_); - _it = instances_map_.find(channel); - if (_it == instances_map_.end()) { - return nullptr; - } else { - return _it->second.get(); - } - } -} - -std::vector<int> GpgFrontend::SingletonStorage::GetAllChannelId() { - std::vector<int> _channels; - for (const auto& [key, value] : instances_map_) { - _channels.push_back(key); - } - return _channels; -} - -GpgFrontend::ChannelObject* GpgFrontend::SingletonStorage::SetObjectInChannel( - int channel, std::unique_ptr<ChannelObject> p_obj) { - { - SPDLOG_TRACE("set channel: {} instance address: {}", channel, - static_cast<void*>(&instances_map_)); - - assert(p_obj != nullptr); - if (p_obj == nullptr) return nullptr; - - auto raw_obj = p_obj.get(); - p_obj->SetChannel(channel); - { - std::unique_lock<std::shared_mutex> lock(instances_mutex_); - instances_map_.insert({channel, std::move(p_obj)}); - } - return raw_obj; - } -} - -GpgFrontend::SingletonStorage* -GpgFrontend::SingletonStorageCollection::GetSingletonStorage( - const std::type_info& type_id) { - const auto hash = type_id.hash_code(); - - while (true) { - decltype(storages_map_.end()) _it; - { - std::shared_lock<std::shared_mutex> lock(storages_mutex_); - _it = storages_map_.find(hash); - } - if (_it == storages_map_.end()) { - { - std::unique_lock<std::shared_mutex> lock(storages_mutex_); - storages_map_.insert({hash, std::make_unique<SingletonStorage>()}); - } - SPDLOG_TRACE("hash: {} created, storage address: {} type_name: {}", hash, - static_cast<void*>(&storages_map_), type_id.name()); - continue; - } else { - return _it->second.get(); - } - } -} - -GpgFrontend::SingletonStorageCollection* -GpgFrontend::SingletonStorageCollection::GetInstance( - bool force_refresh = false) { - static SingletonStorageCollection* instance = nullptr; - - if (force_refresh || instance == nullptr) { - instance = new SingletonStorageCollection(); - SPDLOG_DEBUG("new single storage collection created: {}", - static_cast<void*>(instance)); - } - - return instance; -} - -GpgFrontend::ChannelObject::ChannelObject() noexcept = default; - -GpgFrontend::ChannelObject::ChannelObject(int channel) : channel_(channel) {} diff --git a/src/core/GpgFunctionObject.h b/src/core/GpgFunctionObject.h deleted file mode 100644 index 9b8c2aa3..00000000 --- a/src/core/GpgFunctionObject.h +++ /dev/null @@ -1,311 +0,0 @@ -/** - * Copyright (C) 2021 Saturneric - * - * This file is part of GpgFrontend. - * - * GpgFrontend is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GpgFrontend is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GpgFrontend. If not, see <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 - * - */ - -#ifndef GPGFRONTEND_ZH_CN_TS_FUNCTIONOBJECT_H -#define GPGFRONTEND_ZH_CN_TS_FUNCTIONOBJECT_H - -#include <mutex> - -#include "GpgConstants.h" - -namespace GpgFrontend { - -/** - * @brief object which in channel system - * - */ -class GPGFRONTEND_CORE_EXPORT ChannelObject { - public: - /** - * @brief Construct a new Default Channel Object object - * - */ - ChannelObject() noexcept; - - /** - * @brief Construct a new Channel Object object - * - * @param channel - */ - ChannelObject(int channel); - - /** - * @brief Get the Default Channel object - * - * @return int - */ - static int GetDefaultChannel(); - - /** - * @brief Get the Channel object - * - * @return int - */ - [[nodiscard]] int GetChannel() const; - - /** - * @brief Set the Channel object - * - * @param channel - */ - void SetChannel(int channel); - - private: - int channel_ = _default_channel; ///< The channel id - static constexpr int _default_channel = 0; ///< The default channel id -}; - -class GPGFRONTEND_CORE_EXPORT SingletonStorage { - public: - /** - * @brief - * - * @param channel - */ - void ReleaseChannel(int channel); - - /** - * @brief - * - * @param channel - * @return T* - */ - ChannelObject* FindObjectInChannel(int channel); - - /** - * @brief Get all the channel ids - * - * @return std::vector<int> - */ - std::vector<int> GetAllChannelId(); - - /** - * @brief Set a new object in channel object - * - * @param channel - * @param p_obj - * @return T* - */ - ChannelObject* SetObjectInChannel(int channel, - std::unique_ptr<ChannelObject> p_obj); - - private: - std::shared_mutex instances_mutex_; ///< mutex for _instances_map - std::map<int, std::unique_ptr<ChannelObject>> - instances_map_; ///< map of singleton instances -}; - -class GPGFRONTEND_CORE_EXPORT SingletonStorageCollection { - public: - /** - * @brief Get the Instance object - * - * @return SingletonStorageCollection* - */ - static SingletonStorageCollection* GetInstance(bool force_refresh); - - /** - * @brief Get the Singleton Storage object - * - * @param singleton_function_object - * @return SingletonStorage* - */ - SingletonStorage* GetSingletonStorage(const std::type_info&); - - private: - std::shared_mutex storages_mutex_; ///< mutex for storages_map_ - std::map<size_t, std::unique_ptr<SingletonStorage>> storages_map_; -}; -/** - * @brief - * - * @tparam T - */ -template <typename T> -class SingletonFunctionObject : public ChannelObject { - public: - /** - * @brief prohibit copy - * - */ - SingletonFunctionObject(const SingletonFunctionObject<T>&) = delete; - - /** - * @brief prohibit copy - * - * @return SingletonFunctionObject& - */ - SingletonFunctionObject& operator=(const SingletonFunctionObject<T>&) = - delete; - - /** - * @brief Get the Instance object - * - * @param channel - * @return T& - */ - static T& GetInstance( - int channel = GpgFrontend::GPGFRONTEND_DEFAULT_CHANNEL) { - static std::mutex g_channel_mutex_map_lock; - static std::map<int, std::mutex> g_channel_mutex_map; - - { - std::lock_guard<std::mutex> guard(g_channel_mutex_map_lock); - if (g_channel_mutex_map.find(channel) == g_channel_mutex_map.end()) { - g_channel_mutex_map[channel]; - } - } - - static_assert(std::is_base_of<SingletonFunctionObject<T>, T>::value, - "T not derived from SingletonFunctionObject<T>"); - - auto* p_storage = - SingletonStorageCollection::GetInstance(false)->GetSingletonStorage( - typeid(T)); - auto* _p_pbj = (T*)(p_storage->FindObjectInChannel(channel)); - - if (_p_pbj == nullptr) { - // lock this channel - std::lock_guard<std::mutex> guard(g_channel_mutex_map[channel]); - - // double check - if ((_p_pbj = (T*)(p_storage->FindObjectInChannel(channel))) != nullptr) - return *_p_pbj; - - // do create object of this channel - auto new_obj = std::unique_ptr<ChannelObject>(new T(channel)); - return *(T*)(p_storage->SetObjectInChannel(channel, std::move(new_obj))); - } else { - return *_p_pbj; - } - } - - /** - * @brief Create a Instance object - * - * @param channel - * @param factory - * @return T& - */ - static T& CreateInstance( - int channel, - std::function<std::unique_ptr<ChannelObject>(void)> factory) { - static_assert(std::is_base_of<SingletonFunctionObject<T>, T>::value, - "T not derived from SingletonFunctionObject<T>"); - - auto p_storage = - SingletonStorageCollection::GetInstance(false)->GetSingletonStorage( - typeid(T)); - - auto _p_pbj = (T*)(p_storage->FindObjectInChannel(channel)); - - if (_p_pbj == nullptr) { - return *( - T*)(p_storage->SetObjectInChannel(channel, std::move(factory()))); - } else - return *_p_pbj; - } - - /** - * @brief - * - * @param channel - * @return T& - */ - static void ReleaseChannel(int channel) { - SingletonStorageCollection::GetInstance(false) - ->GetSingletonStorage(typeid(T)) - ->ReleaseChannel(channel); - } - - /** - * @brief Get the Default Channel object - * - * @return int - */ - static int GetDefaultChannel() { return ChannelObject::GetDefaultChannel(); } - - /** - * @brief Get the Channel object - * - * @return int - */ - [[nodiscard]] int GetChannel() const { return ChannelObject::GetChannel(); } - - /** - * @brief Get all the channel ids - * - * @return std::vector<int> - */ - static std::vector<int> GetAllChannelId() { - return SingletonStorageCollection::GetInstance(false) - ->GetSingletonStorage(typeid(T)) - ->GetAllChannelId(); - } - - /** - * @brief Construct a new Singleton Function Object object - * - */ - SingletonFunctionObject(T&&) = delete; - - /** - * @brief Construct a new Singleton Function Object object - * - */ - SingletonFunctionObject(const T&) = delete; - - /** - * @brief - * - */ - void operator=(const T&) = delete; - - protected: - /** - * @brief Construct a new Singleton Function Object object - * - */ - SingletonFunctionObject() = default; - - /** - * @brief Construct a new Singleton Function Object object - * - * @param channel - */ - explicit SingletonFunctionObject(int channel) : ChannelObject(channel) {} - - /** - * @brief Destroy the Singleton Function Object object - * - */ - virtual ~SingletonFunctionObject() = default; -}; -} // namespace GpgFrontend - -#endif // GPGFRONTEND_ZH_CN_TS_FUNCTIONOBJECT_H diff --git a/src/core/GpgGenKeyInfo.cpp b/src/core/GpgGenKeyInfo.cpp deleted file mode 100644 index 290c93c2..00000000 --- a/src/core/GpgGenKeyInfo.cpp +++ /dev/null @@ -1,284 +0,0 @@ -/** - * Copyright (C) 2021 Saturneric - * - * This file is part of GpgFrontend. - * - * GpgFrontend is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GpgFrontend is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GpgFrontend. If not, see <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/GpgGenKeyInfo.h" - -#include <algorithm> -#include <boost/date_time/gregorian/greg_date.hpp> -#include <boost/date_time/gregorian/greg_duration.hpp> -#include <boost/date_time/gregorian/gregorian_types.hpp> -#include <cassert> -#include <string> -#include <vector> - -void GpgFrontend::GenKeyInfo::SetAlgo( - const GpgFrontend::GenKeyInfo::KeyGenAlgo &m_algo) { - SPDLOG_DEBUG("set algo name: {}", m_algo.first); - // Check algo if supported - std::string algo_args = m_algo.second; - if (standalone_) { - if (!subkey_) { - auto support_algo = GetSupportedKeyAlgoStandalone(); - auto it = std::find_if( - support_algo.begin(), support_algo.end(), - [=](const KeyGenAlgo &o) { return o.second == algo_args; }); - // Algo Not Supported - if (it == support_algo.end()) return; - } else { - auto support_algo = GetSupportedSubkeyAlgoStandalone(); - auto it = std::find_if( - support_algo.begin(), support_algo.end(), - [=](const KeyGenAlgo &o) { return o.second == algo_args; }); - // Algo Not Supported - if (it == support_algo.end()) return; - } - } else { - if (!subkey_) { - auto support_algo = GetSupportedKeyAlgo(); - auto it = std::find_if( - support_algo.begin(), support_algo.end(), - [=](const KeyGenAlgo &o) { return o.second == algo_args; }); - // Algo Not Supported - if (it == support_algo.end()) return; - } else { - auto support_algo = GetSupportedSubkeyAlgo(); - auto it = std::find_if( - support_algo.begin(), support_algo.end(), - [=](const KeyGenAlgo &o) { return o.second == algo_args; }); - // Algo Not Supported - if (it == support_algo.end()) return; - } - } - - // reset all options - reset_options(); - - if (!this->subkey_) { - this->SetAllowCertification(true); - } else { - this->SetAllowCertification(false); - } - - this->allow_change_certification_ = false; - - if (!standalone_) boost::algorithm::to_lower(algo_args); - - if (algo_args == "rsa") { - /** - * RSA is the world’s premier asymmetric cryptographic algorithm, - * and is built on the difficulty of factoring extremely large composites. - * GnuPG supports RSA with key sizes of between 1024 and 4096 bits. - */ - suggest_min_key_size_ = 1024; - suggest_max_key_size_ = 4096; - suggest_size_addition_step_ = 1024; - SetKeyLength(2048); - - } else if (algo_args == "dsa") { - /** - * Algorithm (DSA) as a government standard for digital signatures. - * Originally, it supported key lengths between 512 and 1024 bits. - * Recently, NIST has declared 512-bit keys obsolete: - * now, DSA is available in 1024, 2048 and 3072-bit lengths. - */ - SetAllowEncryption(false); - allow_change_encryption_ = false; - - suggest_min_key_size_ = 1024; - suggest_max_key_size_ = 3072; - suggest_size_addition_step_ = 1024; - SetKeyLength(2048); - - } else if (algo_args == "ed25519") { - /** - * GnuPG supports the Elgamal asymmetric encryption algorithm in key lengths - * ranging from 1024 to 4096 bits. - */ - SetAllowEncryption(false); - allow_change_encryption_ = false; - - suggest_min_key_size_ = -1; - suggest_max_key_size_ = -1; - suggest_size_addition_step_ = -1; - SetKeyLength(-1); - } else if (algo_args == "cv25519") { - SetAllowAuthentication(false); - allow_change_authentication_ = false; - - SetAllowSigning(false); - allow_change_signing_ = false; - - SetAllowCertification(false); - allow_change_certification_ = false; - - suggest_min_key_size_ = 1024; - suggest_max_key_size_ = 4096; - suggest_size_addition_step_ = 1024; - SetKeyLength(2048); - } else if (algo_args == "nistp256" || algo_args == "nistp384" || - algo_args == "nistp521") { - SetAllowAuthentication(false); - allow_change_authentication_ = false; - - SetAllowSigning(false); - allow_change_signing_ = false; - - SetAllowCertification(false); - allow_change_certification_ = false; - - suggest_min_key_size_ = -1; - suggest_max_key_size_ = -1; - suggest_size_addition_step_ = -1; - SetKeyLength(-1); - } else if (algo_args == "brainpoolp256r1") { - SetAllowAuthentication(false); - allow_change_authentication_ = false; - - SetAllowSigning(false); - allow_change_signing_ = false; - - SetAllowCertification(false); - allow_change_certification_ = false; - - suggest_min_key_size_ = -1; - suggest_max_key_size_ = -1; - suggest_size_addition_step_ = -1; - SetKeyLength(-1); - } - - this->algo_ = algo_args; -} - -void GpgFrontend::GenKeyInfo::reset_options() { - allow_change_encryption_ = true; - SetAllowEncryption(true); - - allow_change_certification_ = true; - SetAllowCertification(true); - - allow_change_signing_ = true; - SetAllowSigning(true); - - allow_change_authentication_ = true; - SetAllowAuthentication(true); - - passphrase_.clear(); -} - -std::string GpgFrontend::GenKeyInfo::GetKeySizeStr() const { - if (key_size_ > 0) { - return std::to_string(key_size_); - } else { - return {}; - } -} - -void GpgFrontend::GenKeyInfo::SetKeyLength(int m_key_size) { - if (m_key_size < suggest_min_key_size_ || - m_key_size > suggest_max_key_size_) { - return; - } - GenKeyInfo::key_size_ = m_key_size; -} - -void GpgFrontend::GenKeyInfo::SetExpireTime( - const boost::posix_time::ptime &m_expired) { - using namespace boost::gregorian; - if (!IsNonExpired()) { - GenKeyInfo::expired_ = m_expired; - } -} - -void GpgFrontend::GenKeyInfo::SetNonExpired(bool m_non_expired) { - using namespace boost::posix_time; - if (!m_non_expired) this->expired_ = from_time_t(0); - GenKeyInfo::non_expired_ = m_non_expired; -} - -void GpgFrontend::GenKeyInfo::SetAllowEncryption(bool m_allow_encryption) { - if (allow_change_encryption_) - GenKeyInfo::allow_encryption_ = m_allow_encryption; -} - -void GpgFrontend::GenKeyInfo::SetAllowCertification( - bool m_allow_certification) { - if (allow_change_certification_) - GenKeyInfo::allow_certification_ = m_allow_certification; -} - -GpgFrontend::GenKeyInfo::GenKeyInfo(bool m_is_sub_key, bool m_standalone) - : standalone_(m_standalone), subkey_(m_is_sub_key) { - assert(GetSupportedKeyAlgo().size() > 0); - SetAlgo(GetSupportedKeyAlgo()[0]); -} - -const std::vector<GpgFrontend::GenKeyInfo::KeyGenAlgo> - &GpgFrontend::GenKeyInfo::GetSupportedKeyAlgo() { - static const std::vector<GpgFrontend::GenKeyInfo::KeyGenAlgo> - support_key_algo = { - {"RSA", "RSA"}, - {"DSA", "DSA"}, - {"ECDSA", "ED25519"}, - }; - return support_key_algo; -} - -const std::vector<GpgFrontend::GenKeyInfo::KeyGenAlgo> - &GpgFrontend::GenKeyInfo::GetSupportedSubkeyAlgo() { - static const std::vector<GpgFrontend::GenKeyInfo::KeyGenAlgo> - support_subkey_algo = { - {"RSA", "RSA"}, - {"DSA", "DSA"}, - {"ECDSA", "ED25519"}, - {"ECDH NIST P-256", "NISTP256"}, - {"ECDH NIST P-384", "NISTP384"}, - {"ECDH NIST P-521", "NISTP521"}, - // {"ECDH BrainPool P-256", "BRAINPOOlP256R1"} - }; - return support_subkey_algo; -} - -const std::vector<GpgFrontend::GenKeyInfo::KeyGenAlgo> - &GpgFrontend::GenKeyInfo::GetSupportedKeyAlgoStandalone() { - static const std::vector<GpgFrontend::GenKeyInfo::KeyGenAlgo> - support_subkey_algo_standalone = { - {"RSA", "RSA"}, - {"DSA", "DSA"}, - }; - return support_subkey_algo_standalone; -} - -const std::vector<GpgFrontend::GenKeyInfo::KeyGenAlgo> - &GpgFrontend::GenKeyInfo::GetSupportedSubkeyAlgoStandalone() { - static const std::vector<GpgFrontend::GenKeyInfo::KeyGenAlgo> - support_subkey_algo_standalone = { - {"RSA", "RSA"}, - {"DSA", "DSA"}, - }; - return support_subkey_algo_standalone; -} diff --git a/src/core/GpgInfo.h b/src/core/GpgInfo.h deleted file mode 100644 index f4415af1..00000000 --- a/src/core/GpgInfo.h +++ /dev/null @@ -1,65 +0,0 @@ -/** - * Copyright (C) 2021 Saturneric - * - * This file is part of GpgFrontend. - * - * GpgFrontend is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GpgFrontend is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GpgFrontend. If not, see <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 - * - */ - -#ifndef GPGFRONTEND_ZH_CN_TS_GPGINFO_H -#define GPGFRONTEND_ZH_CN_TS_GPGINFO_H - -#include <mutex> -#include <string> - -namespace GpgFrontend { -/** - * @brief Use to record some info about gnupg - * - */ -class GpgInfo { - public: - std::string GnupgVersion; ///< version of gnupg - std::string GpgMEVersion; ///< - - std::string AppPath; ///< executable binary path of gnupg - std::string DatabasePath; ///< key database path - std::string GpgConfPath; ///< executable binary path of gpgconf - std::string AssuanPath; ///< executable binary path of assuan - std::string CMSPath; ///< executable binary path of cms - std::string GpgAgentPath; ///< executable binary path of gpg-agent - std::string DirmngrPath; ///< executable binary path of dirmgr - std::string KeyboxdPath; ///< executable binary path of keyboxd - - std::string GnuPGHomePath; ///< value of ---homedir - - std::map<std::string, std::vector<std::string>> ComponentsInfo; ///< - std::map<std::string, std::vector<std::string>> ConfigurationsInfo; ///< - std::map<std::string, std::vector<std::string>> OptionsInfo; ///< - std::map<std::string, std::vector<std::string>> AvailableOptionsInfo; ///< - - std::shared_mutex Lock; -}; -} // namespace GpgFrontend - -#endif // GPGFRONTEND_ZH_CN_TS_GPGINFO_H diff --git a/src/core/GpgModel.h b/src/core/GpgModel.h index d8d4e6fe..72574988 100644 --- a/src/core/GpgModel.h +++ b/src/core/GpgModel.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,38 +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_GPGMODEL_H -#define GPGFRONTEND_ZH_CN_TS_GPGMODEL_H +#pragma once -#include "core/GpgConstants.h" +// +#include "core/typedef/GpgTypedef.h" + +// #include "core/model/GpgData.h" #include "core/model/GpgKey.h" #include "core/model/GpgSignature.h" -namespace GpgFrontend { - -using KeyId = std::string; ///< -using SubkeyId = std::string; ///< -using KeyIdArgsList = std::vector<KeyId>; ///< -using KeyIdArgsListPtr = std::unique_ptr<KeyIdArgsList>; ///< -using UIDArgsList = std::vector<std::string>; ///< -using UIDArgsListPtr = std::unique_ptr<UIDArgsList>; ///< -using SignIdArgsList = std::vector<std::pair<std::string, std::string>>; ///< -using SignIdArgsListPtr = std::unique_ptr<SignIdArgsList>; ///< -using KeyFprArgsListPtr = std::unique_ptr<std::vector<std::string>>; ///< -using KeyArgsList = std::vector<GpgKey>; ///< -using KeyListPtr = std::unique_ptr<KeyArgsList>; ///< -using GpgKeyLinkList = std::list<GpgFrontend::GpgKey>; ///< -using KeyLinkListPtr = std::unique_ptr<GpgKeyLinkList>; ///< -using KeyPtr = std::unique_ptr<GpgKey>; ///< -using KeyPtrArgsList = const std::initializer_list<KeyPtr>; ///< - -} // namespace GpgFrontend - -#endif // GPGFRONTEND_ZH_CN_TS_GPGMODEL_H +// namespace GpgFrontend diff --git a/src/core/common/CoreCommonUtil.cpp b/src/core/common/CoreCommonUtil.cpp deleted file mode 100644 index 93cad60a..00000000 --- a/src/core/common/CoreCommonUtil.cpp +++ /dev/null @@ -1,58 +0,0 @@ -/**
- * Copyright (C) 2021 Saturneric
- *
- * This file is part of GpgFrontend.
- *
- * GpgFrontend is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * GpgFrontend is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GpgFrontend. If not, see <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.
- *
- * The source code version of this software was modified and released
- * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021.
- *
- */
-
-#include "CoreCommonUtil.h"
-
-#include <string>
-
-namespace GpgFrontend {
-
-std::unique_ptr<CoreCommonUtil> CoreCommonUtil::instance_ = nullptr; ///<
-
-CoreCommonUtil* CoreCommonUtil::GetInstance() {
- if (instance_ == nullptr) {
- instance_ = std::make_unique<CoreCommonUtil>();
- }
- return instance_.get();
-}
-
-void CoreCommonUtil::SetTempCacheValue(const std::string& key,
- const std::string& value) {
- temp_cache_[key] = value;
-}
-
-std::string CoreCommonUtil::GetTempCacheValue(const std::string& key) {
- std::string temp_cache_value;
- std::swap(temp_cache_value, temp_cache_[key]);
- return temp_cache_value;
-}
-
-void CoreCommonUtil::ResetTempCacheValue(const std::string& key) {
- std::string temp_cache_value;
- std::swap(temp_cache_value, temp_cache_[key]);
-}
-
-} // namespace GpgFrontend
diff --git a/src/core/common/CoreCommonUtil.h b/src/core/common/CoreCommonUtil.h deleted file mode 100644 index 58bb4d40..00000000 --- a/src/core/common/CoreCommonUtil.h +++ /dev/null @@ -1,87 +0,0 @@ -/**
- * Copyright (C) 2021 Saturneric
- *
- * This file is part of GpgFrontend.
- *
- * GpgFrontend is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * GpgFrontend is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GpgFrontend. If not, see <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.
- *
- * The source code version of this software was modified and released
- * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021.
- *
- */
-
-#ifndef GPGFRONTEND_CORECOMMONUTIL_H
-#define GPGFRONTEND_CORECOMMONUTIL_H
-
-#include <string>
-
-#include "core/GpgFrontendCore.h"
-
-namespace GpgFrontend {
-
-class GPGFRONTEND_CORE_EXPORT CoreCommonUtil : public QObject {
- Q_OBJECT
- public:
- /**
- * @brief Construct a new Core Common Util object
- *
- */
- static CoreCommonUtil *GetInstance();
-
- /**
- * @brief
- *
- */
- CoreCommonUtil() = default;
-
- /**
- * @brief set a temp cache under a certain key
- *
- */
- void SetTempCacheValue(const std::string &, const std::string &);
-
- /**
- * @brief after get the temp cache, its value will be imediately ease in
- * storage
- *
- * @return std::string
- */
- std::string GetTempCacheValue(const std::string &);
-
- /**
- * @brief imediately ease temp cache in storage
- *
- * @return std::string
- */
- void ResetTempCacheValue(const std::string &);
-
- signals:
-
- /**
- * @brief
- *
- */
- void SignalGnupgNotInstall();
-
- private:
- static std::unique_ptr<CoreCommonUtil> instance_; ///<
- std::map<std::string, std::string> temp_cache_; //<
-};
-
-} // namespace GpgFrontend
-
-#endif // GPGFRONTEND_CORECOMMONUTIL_H
diff --git a/src/core/function/ArchiveFileOperator.cpp b/src/core/function/ArchiveFileOperator.cpp index 8aad0500..f1345f87 100644 --- a/src/core/function/ArchiveFileOperator.cpp +++ b/src/core/function/ArchiveFileOperator.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,7 +28,15 @@ #include "ArchiveFileOperator.h" -int copy_data(struct archive *ar, struct archive *aw) { +#include <archive.h> +#include <archive_entry.h> +#include <sys/fcntl.h> + +#include "core/utils/AsyncUtils.h" + +namespace GpgFrontend { + +auto CopyData(struct archive *ar, struct archive *aw) -> int { int r; const void *buff; size_t size; @@ -38,231 +46,218 @@ int copy_data(struct archive *ar, struct archive *aw) { r = archive_read_data_block(ar, &buff, &size, &offset); if (r == ARCHIVE_EOF) return (ARCHIVE_OK); if (r != ARCHIVE_OK) { - SPDLOG_ERROR("archive_read_data_block() failed: {}", - archive_error_string(ar)); + GF_CORE_LOG_ERROR("archive_read_data_block() failed: {}", + archive_error_string(ar)); return (r); } r = archive_write_data_block(aw, buff, size, offset); if (r != ARCHIVE_OK) { - SPDLOG_ERROR("archive_write_data_block() failed: {}", - archive_error_string(aw)); + GF_CORE_LOG_ERROR("archive_write_data_block() failed: {}", + archive_error_string(aw)); return (r); } } } -void GpgFrontend::ArchiveFileOperator::CreateArchive( - const std::filesystem::path &base_path, - const std::filesystem::path &archive_path, int compress, - const std::vector<std::filesystem::path> &files) { - SPDLOG_DEBUG("CreateArchive: {}", archive_path.u8string()); - - auto current_base_path_backup = QDir::currentPath(); - QDir::setCurrent(base_path.u8string().c_str()); - - auto relative_archive_path = - std::filesystem::relative(archive_path, base_path); - - std::vector<std::filesystem::path> relative_files; - relative_files.reserve(files.size()); - for (const auto &file : files) { - relative_files.push_back(std::filesystem::relative(file, base_path)); - } - - struct archive *a; - struct archive_entry *entry; - ssize_t len; - int fd; - - SPDLOG_DEBUG("compress: {}", compress); - - a = archive_write_new(); - switch (compress) { -#ifndef NO_BZIP2_CREATE - case 'j': - case 'y': - archive_write_add_filter_bzip2(a); - break; -#endif -#ifndef NO_COMPRESS_CREATE - case 'Z': - archive_write_add_filter_compress(a); - break; -#endif -#ifndef NO_GZIP_CREATE - case 'z': - archive_write_add_filter_gzip(a); - break; -#endif - default: - archive_write_add_filter_none(a); - break; - } - archive_write_set_format_ustar(a); - archive_write_set_format_pax_restricted(a); - - auto u8_filename = relative_archive_path.u8string(); - - if (!u8_filename.empty() && u8_filename == u8"-") - throw std::runtime_error("cannot write to stdout"); - -#ifdef WINDOWS - archive_write_open_filename_w(a, relative_archive_path.wstring().c_str()); -#else - archive_write_open_filename(a, u8_filename.c_str()); -#endif - - for (const auto &file : relative_files) { - struct archive *disk = archive_read_disk_new(); -#ifndef NO_LOOKUP - archive_read_disk_set_standard_lookup(disk); -#endif - int r; - - SPDLOG_DEBUG("reading file: {}", file.u8string()); - -#ifdef WINDOWS - r = archive_read_disk_open_w(disk, file.wstring().c_str()); -#else - r = archive_read_disk_open(disk, file.u8string().c_str()); -#endif - - SPDLOG_DEBUG("read file done: {}", file.u8string()); - - if (r != ARCHIVE_OK) { - SPDLOG_ERROR("{archive_read_disk_open() failed: {}", - archive_error_string(disk)); - throw std::runtime_error("archive_read_disk_open() failed"); - } +struct ArchiveReadClientData { + GFDataExchanger *ex; + std::array<std::byte, 1024> buf; + const std::byte *p_buf = buf.data(); +}; + +auto ArchiveReadCallback(struct archive *, void *client_data, + const void **buffer) -> ssize_t { + auto *rdata = static_cast<ArchiveReadClientData *>(client_data); + *buffer = reinterpret_cast<const void *>(rdata->p_buf); + return rdata->ex->Read(rdata->buf.data(), rdata->buf.size()); +} - for (;;) { - entry = archive_entry_new(); - r = archive_read_next_header2(disk, entry); - - if (r == ARCHIVE_EOF) break; - if (r != ARCHIVE_OK) { - SPDLOG_ERROR("archive_read_next_header2() failed: {}", - archive_error_string(disk)); - throw std::runtime_error("archive_read_next_header2() failed"); - } - archive_read_disk_descend(disk); - - SPDLOG_DEBUG("Adding: {} size: {} bytes: {} file type: {}", - archive_entry_pathname_utf8(entry), - archive_entry_size(entry), archive_entry_filetype(entry)); - - r = archive_write_header(a, entry); - if (r < ARCHIVE_OK) { - SPDLOG_ERROR("archive_write_header() failed: {}", - archive_error_string(a)); - throw std::runtime_error("archive_write_header() failed"); - } - if (r == ARCHIVE_FATAL) throw std::runtime_error("archive fatal"); - if (r > ARCHIVE_FAILED) { - QByteArray buff; -#ifdef WINDOWS - FileOperator::ReadFile( - QString::fromStdWString(archive_entry_sourcepath_w(entry)), buff); -#else - FileOperator::ReadFile(archive_entry_sourcepath(entry), buff); -#endif - archive_write_data(a, buff.data(), buff.size()); - } - archive_entry_free(entry); - } - archive_read_close(disk); - archive_read_free(disk); - } - archive_write_close(a); - archive_write_free(a); +auto ArchiveWriteCallback(struct archive *, void *client_data, + const void *buffer, size_t length) -> ssize_t { + auto *ex = static_cast<GFDataExchanger *>(client_data); + return ex->Write(static_cast<const std::byte *>(buffer), length); +} - QDir::setCurrent(current_base_path_backup); +auto ArchiveCloseWriteCallback(struct archive *, void *client_data) -> int { + auto *ex = static_cast<GFDataExchanger *>(client_data); + ex->CloseWrite(); + return 0; } -void GpgFrontend::ArchiveFileOperator::ExtractArchive( - const std::filesystem::path &archive_path, - const std::filesystem::path &base_path) { - SPDLOG_DEBUG("ExtractArchive: {}", archive_path.u8string()); +void ArchiveFileOperator::NewArchive2DataExchanger( + const QString &target_directory, std::shared_ptr<GFDataExchanger> exchanger, + const OperationCallback &cb) { + RunIOOperaAsync( + [=](const DataObjectPtr &data_object) -> GFError { + std::array<char, 1024> buff{}; + auto ret = 0; + const auto base_path = QDir(QDir(target_directory).absolutePath()); - auto current_base_path_backup = QDir::currentPath(); - QDir::setCurrent(base_path.u8string().c_str()); + auto *archive = archive_write_new(); + archive_write_add_filter_none(archive); + archive_write_set_format_pax_restricted(archive); - struct archive *a; - struct archive *ext; - struct archive_entry *entry; + archive_write_open(archive, exchanger.get(), nullptr, + ArchiveWriteCallback, ArchiveCloseWriteCallback); - a = archive_read_new(); - ext = archive_write_disk_new(); - archive_write_disk_set_options(ext, 0); -#ifndef NO_BZIP2_EXTRACT - archive_read_support_filter_bzip2(a); -#endif -#ifndef NO_GZIP_EXTRACT - archive_read_support_filter_gzip(a); -#endif -#ifndef NO_COMPRESS_EXTRACT - archive_read_support_filter_compress(a); -#endif -#ifndef NO_TAR_EXTRACT - archive_read_support_format_tar(a); -#endif -#ifndef NO_CPIO_EXTRACT - archive_read_support_format_cpio(a); -#endif -#ifndef NO_LOOKUP - archive_write_disk_set_standard_lookup(ext); -#endif + auto *disk = archive_read_disk_new(); + archive_read_disk_set_standard_lookup(disk); - auto filename = archive_path.u8string(); - - if (!filename.empty() && filename == u8"-") { - SPDLOG_ERROR("cannot read from stdin"); - } #ifdef WINDOWS - if (archive_read_open_filename_w(a, archive_path.wstring().c_str(), 10240) != - ARCHIVE_OK) { + auto r = archive_read_disk_open_w( + disk, target_directory.toStdWString().c_str()); #else - if (archive_read_open_filename(a, archive_path.u8string().c_str(), 10240) != - ARCHIVE_OK) { + auto r = archive_read_disk_open(disk, target_directory.toUtf8()); #endif - SPDLOG_ERROR("archive_read_open_filename() failed: {}", - archive_error_string(a)); - throw std::runtime_error("archive_read_open_filename() failed"); - } - - for (;;) { - int r = archive_read_next_header(a, &entry); - if (r == ARCHIVE_EOF) break; - if (r != ARCHIVE_OK) { - SPDLOG_ERROR("archive_read_next_header() failed: {}", - archive_error_string(a)); - throw std::runtime_error("archive_read_next_header() failed"); - } - SPDLOG_DEBUG("Adding: {} size: {} bytes: {} file type: {}", - archive_entry_pathname_utf8(entry), archive_entry_size(entry), - archive_entry_filetype(entry)); - r = archive_write_header(ext, entry); - if (r != ARCHIVE_OK) { - SPDLOG_ERROR("archive_write_header() failed: {}", - archive_error_string(ext)); - } else { - r = copy_data(a, ext); - if (r != ARCHIVE_OK) { - SPDLOG_ERROR("copy_data() failed: {}", archive_error_string(ext)); - } - } - } - archive_read_close(a); - archive_read_free(a); - archive_write_close(ext); - archive_write_free(ext); + if (r != ARCHIVE_OK) { + GF_CORE_LOG_ERROR("archive_read_disk_open() failed: {}, abort...", + archive_error_string(disk)); + archive_read_free(disk); + archive_write_free(archive); + return -1; + } + + for (;;) { + auto *entry = archive_entry_new(); + r = archive_read_next_header2(disk, entry); + if (r == ARCHIVE_EOF) break; + if (r != ARCHIVE_OK) { + GF_CORE_LOG_ERROR( + "archive_read_next_header2() failed, ret: {}, explain: {}", r, + archive_error_string(disk)); + ret = -1; + break; + } + + archive_read_disk_descend(disk); + + // turn absolute path to relative path + archive_entry_set_pathname( + entry, + base_path.relativeFilePath(QString(archive_entry_pathname(entry))) + .toUtf8()); + + r = archive_write_header(archive, entry); + if (r < ARCHIVE_OK) { + GF_CORE_LOG_ERROR( + "archive_write_header() failed, ret: {}, explain: {} ", r, + archive_error_string(archive)); + continue; + } + + if (r == ARCHIVE_FATAL) { + GF_CORE_LOG_ERROR( + "archive_write_header() failed, ret: {}, explain: {}, " + "abort ...", + r, archive_error_string(archive)); + ret = -1; + break; + } + + if (r > ARCHIVE_FAILED) { + auto fd = open(archive_entry_sourcepath(entry), O_RDONLY); + auto len = read(fd, buff.data(), buff.size()); + while (len > 0) { + archive_write_data(archive, buff.data(), len); + len = read(fd, buff.data(), buff.size()); + } + close(fd); + } + archive_entry_free(entry); + } + + archive_read_free(disk); + archive_write_free(archive); + return ret; + }, + cb, "archive_write_new"); +} - QDir::setCurrent(current_base_path_backup); +void ArchiveFileOperator::ExtractArchiveFromDataExchanger( + std::shared_ptr<GFDataExchanger> ex, const QString &target_path, + const OperationCallback &cb) { + GF_CORE_LOG_INFO("target path: {}", target_path); + RunIOOperaAsync( + [=](const DataObjectPtr &data_object) -> GFError { + auto *archive = archive_read_new(); + auto *ext = archive_write_disk_new(); + + auto r = archive_read_support_filter_all(archive); + if (r != ARCHIVE_OK) { + GF_CORE_LOG_ERROR( + "archive_read_support_filter_all(), ret: {}, reason: {}", r, + archive_error_string(archive)); + return r; + } + + r = archive_read_support_format_all(archive); + if (r != ARCHIVE_OK) { + GF_CORE_LOG_ERROR( + "archive_read_support_format_all(), ret: {}, reason: {}", r, + archive_error_string(archive)); + return r; + } + + auto rdata = ArchiveReadClientData{}; + rdata.ex = ex.get(); + + r = archive_read_open(archive, &rdata, nullptr, ArchiveReadCallback, + nullptr); + if (r != ARCHIVE_OK) { + GF_CORE_LOG_ERROR("archive_read_open(), ret: {}, reason: {}", r, + archive_error_string(archive)); + return r; + } + + r = archive_write_disk_set_options(ext, 0); + if (r != ARCHIVE_OK) { + GF_CORE_LOG_ERROR( + "archive_write_disk_set_options(), ret: {}, reason: {}", r, + archive_error_string(archive)); + return r; + } + + for (;;) { + struct archive_entry *entry; + r = archive_read_next_header(archive, &entry); + if (r == ARCHIVE_EOF) break; + if (r != ARCHIVE_OK) { + GF_CORE_LOG_ERROR("archive_read_next_header(), ret: {}, reason: {}", + r, archive_error_string(archive)); + break; + } + + archive_entry_set_pathname( + entry, + (target_path + "/" + archive_entry_pathname(entry)).toUtf8()); + + r = archive_write_header(ext, entry); + if (r != ARCHIVE_OK) { + GF_CORE_LOG_ERROR("archive_write_header(), ret: {}, reason: {}", r, + archive_error_string(archive)); + } else { + r = CopyData(archive, ext); + } + } + + r = archive_read_free(archive); + if (r != ARCHIVE_OK) { + GF_CORE_LOG_ERROR("archive_read_free(), ret: {}, reason: {}", r, + archive_error_string(archive)); + } + r = archive_write_free(ext); + if (r != ARCHIVE_OK) { + GF_CORE_LOG_ERROR("archive_read_free(), ret: {}, reason: {}", r, + archive_error_string(archive)); + } + + return 0; + }, + cb, "archive_read_new"); } -void GpgFrontend::ArchiveFileOperator::ListArchive( - const std::filesystem::path &archive_path) { +void ArchiveFileOperator::ListArchive(const QString &archive_path) { struct archive *a; struct archive_entry *entry; int r; @@ -270,14 +265,16 @@ void GpgFrontend::ArchiveFileOperator::ListArchive( a = archive_read_new(); archive_read_support_filter_all(a); archive_read_support_format_all(a); - r = archive_read_open_filename(a, archive_path.u8string().c_str(), + r = archive_read_open_filename(a, archive_path.toUtf8(), 10240); // Note 1 if (r != ARCHIVE_OK) return; while (archive_read_next_header(a, &entry) == ARCHIVE_OK) { - SPDLOG_DEBUG("File: {}", archive_entry_pathname(entry)); - SPDLOG_DEBUG("File Path: {}", archive_entry_pathname(entry)); + GF_CORE_LOG_DEBUG("File: {}", archive_entry_pathname(entry)); + GF_CORE_LOG_DEBUG("File Path: {}", archive_entry_pathname(entry)); archive_read_data_skip(a); // Note 2 } r = archive_read_free(a); // Note 3 if (r != ARCHIVE_OK) return; } + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/function/ArchiveFileOperator.h b/src/core/function/ArchiveFileOperator.h index 4db5af5f..bfeec0c4 100644 --- a/src/core/function/ArchiveFileOperator.h +++ b/src/core/function/ArchiveFileOperator.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,40 +20,50 @@ * 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_ARCHIVEFILEOPERATOR_H -#define GPGFRONTEND_ARCHIVEFILEOPERATOR_H +#pragma once #include "core/GpgFrontendCore.h" -#include "core/function/FileOperator.h" +#include "core/model/GFDataExchanger.h" +#include "core/typedef/CoreTypedef.h" +#include "core/utils/IOUtils.h" namespace GpgFrontend { -struct ArchiveStruct { - struct archive *archive; - struct archive_entry *entry; - int fd; - bool is_open; - std::string name; -}; - class GPGFRONTEND_CORE_EXPORT ArchiveFileOperator { public: - static void ListArchive(const std::filesystem::path &archive_path); + /** + * @brief + * + * @param archive_path + */ + static void ListArchive(const QString &archive_path); - static void CreateArchive(const std::filesystem::path &base_path, - const std::filesystem::path &archive_path, - int compress, - const std::vector<std::filesystem::path> &files); + /** + * @brief Create a Archive object + * + * @param base_path + * @param archive_path + * @param compress + * @param files + */ + static void NewArchive2DataExchanger(const QString &target_directory, + std::shared_ptr<GFDataExchanger>, + const OperationCallback &cb); - static void ExtractArchive(const std::filesystem::path &archive_path, - const std::filesystem::path &base_path); + /** + * @brief + * + * @param archive_path + * @param base_path + */ + static void ExtractArchiveFromDataExchanger( + std::shared_ptr<GFDataExchanger> fd, const QString &target_path, + const OperationCallback &cb); }; } // namespace GpgFrontend - -#endif // GPGFRONTEND_ARCHIVEFILEOPERATOR_H diff --git a/src/core/function/CacheManager.cpp b/src/core/function/CacheManager.cpp index d9aead66..719c962d 100644 --- a/src/core/function/CacheManager.cpp +++ b/src/core/function/CacheManager.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 * @@ -29,119 +29,256 @@ #include "CacheManager.h" #include <algorithm> -#include <boost/format.hpp> -#include <string> +#include <shared_mutex> +#include <utility> -#include "function/DataObjectOperator.h" -#include "spdlog/spdlog.h" +#include "core/function/DataObjectOperator.h" +#include "core/utils/MemoryUtils.h" -GpgFrontend::CacheManager::CacheManager(int channel) - : m_timer_(new QTimer(this)), - SingletonFunctionObject<CacheManager>(channel) { - connect(m_timer_, &QTimer::timeout, this, &CacheManager::flush_cache_storage); - m_timer_->start(15000); +namespace GpgFrontend { - load_all_cache_storage(); -} +template <typename Key, typename Value> +class ThreadSafeMap { + public: + using MapType = std::map<Key, Value>; + using IteratorType = typename MapType::iterator; -void GpgFrontend::CacheManager::SaveCache(std::string key, - const nlohmann::json& value, - bool flush) { - auto data_object_key = get_data_object_key(key); - cache_storage_.insert(key, value); + void insert(const Key& key, const Value& value) { + std::unique_lock lock(mutex_); + (*map_)[key] = value; + } - if (std::find(key_storage_.begin(), key_storage_.end(), key) == - key_storage_.end()) { - SPDLOG_DEBUG("register new key of cache", key); - key_storage_.push_back(key); + auto get(const Key& key) -> std::optional<Value> { + std::shared_lock lock(mutex_); + auto it = map_->find(key); + if (it != map_->end()) { + return it->second; + } + return std::nullopt; } - if (flush) { - flush_cache_storage(); + auto exists(const Key& key) -> bool { + std::shared_lock lock(mutex_); + return map_->count(key) > 0; } -} -nlohmann::json GpgFrontend::CacheManager::LoadCache(std::string key) { - auto data_object_key = get_data_object_key(key); + auto begin() -> IteratorType { return map_mirror_->begin(); } + + auto end() -> IteratorType { return map_mirror_->end(); } - if (!cache_storage_.exists(key)) { - cache_storage_.insert(key, load_cache_storage(key, {})); + auto mirror() -> ThreadSafeMap& { + std::shared_lock lock(mutex_); + *map_mirror_ = *map_; + return *this; } - auto cache = cache_storage_.get(key); - if (cache) - return *cache; - else - return {}; -} + auto remove(QString key) -> bool { + std::unique_lock lock(mutex_); + auto it = map_->find(key); + if (it != map_->end()) { + map_->erase(it); + return true; + } + return false; + } -nlohmann::json GpgFrontend::CacheManager::LoadCache( - std::string key, nlohmann::json default_value) { - auto data_object_key = get_data_object_key(key); - if (!cache_storage_.exists(key)) { - cache_storage_.insert(key, load_cache_storage(key, default_value)); + private: + std::unique_ptr<MapType, SecureObjectDeleter<MapType>> map_mirror_ = + std::move(SecureCreateUniqueObject<MapType>()); + std::unique_ptr<MapType, SecureObjectDeleter<MapType>> map_ = + std::move(SecureCreateUniqueObject<MapType>()); + mutable std::shared_mutex mutex_; +}; + +class CacheManager::Impl : public QObject { + Q_OBJECT + public: + Impl() : flush_timer_(new QTimer(this)) { + connect(flush_timer_, &QTimer::timeout, this, + &Impl::slot_flush_cache_storage); + flush_timer_->start(15000); + + // load data from storage + load_all_cache_storage(); } - auto cache = cache_storage_.get(key); - if (cache) - return *cache; - else - return {}; -} + void SaveDurableCache(QString key, const QJsonDocument& value, bool flush) { + auto data_object_key = get_data_object_key(key); + durable_cache_storage_.insert(key, value); -std::string GpgFrontend::CacheManager::get_data_object_key(std::string key) { - return (boost::format("__cache_data_%1%") % key).str(); -} + if (!key_storage_.contains(key)) { + GF_CORE_LOG_DEBUG("register new key of cache", key); + key_storage_.push_back(key); + } -nlohmann::json GpgFrontend::CacheManager::load_cache_storage( - std::string key, nlohmann::json default_value) { - auto data_object_key = get_data_object_key(key); - auto stored_data = - GpgFrontend::DataObjectOperator::GetInstance().GetDataObject( - data_object_key); + if (flush) slot_flush_cache_storage(); + } - if (stored_data.has_value()) { - return stored_data.value(); - } else { - return default_value; + auto LoadDurableCache(const QString& key) -> QJsonDocument { + auto data_object_key = get_data_object_key(key); + + if (!durable_cache_storage_.exists(key)) { + durable_cache_storage_.insert(key, load_cache_storage(key, {})); + } + + auto cache = durable_cache_storage_.get(key); + if (cache.has_value()) return cache.value(); + return {}; } -} -void GpgFrontend::CacheManager::flush_cache_storage() { - for (auto cache : cache_storage_.mirror()) { - auto key = get_data_object_key(cache.first); - SPDLOG_DEBUG("save cache into filesystem, key {}, value size: {}", key, - cache.second.size()); - GpgFrontend::DataObjectOperator::GetInstance().SaveDataObj(key, - cache.second); + auto LoadDurableCache(const QString& key, QJsonDocument default_value) + -> QJsonDocument { + auto data_object_key = get_data_object_key(key); + if (!durable_cache_storage_.exists(key)) { + durable_cache_storage_.insert( + key, load_cache_storage(key, std::move(default_value))); + } + + auto cache = durable_cache_storage_.get(key); + if (cache.has_value()) return cache.value(); + return {}; } - GpgFrontend::DataObjectOperator::GetInstance().SaveDataObj(drk_key_, - key_storage_); -} -void GpgFrontend::CacheManager::register_cache_key(std::string key) {} + auto ResetDurableCache(const QString& key) -> bool { + auto data_object_key = get_data_object_key(key); + return durable_cache_storage_.remove(key); + } + + void FlushCacheStorage() { this->slot_flush_cache_storage(); } -void GpgFrontend::CacheManager::load_all_cache_storage() { - SPDLOG_DEBUG("start to load all cache from file system"); - auto stored_data = - GpgFrontend::DataObjectOperator::GetInstance().GetDataObject(drk_key_); + void SaveCache(const QString& key, QString value) { + runtime_cache_storage_.insert(key, new QString(std::move(value))); + } - // get cache data list from file system - nlohmann::json registered_key_list; - if (stored_data.has_value()) { - registered_key_list = std::move(stored_data.value()); + auto LoadCache(const QString& key) -> QString { + auto* value = runtime_cache_storage_.object(key); + if (value == nullptr) return {}; + return *value; } - if (!registered_key_list.is_array()) { + void ResetCache(const QString& key) { runtime_cache_storage_.remove(key); } + + private slots: + + /** + * @brief + * + */ + void slot_flush_cache_storage() { + for (const auto& cache : durable_cache_storage_.mirror()) { + auto key = get_data_object_key(cache.first); + GF_CORE_LOG_TRACE("save cache into filesystem, key {}", key); + GpgFrontend::DataObjectOperator::GetInstance().SaveDataObj( + key, QJsonDocument(cache.second)); + } GpgFrontend::DataObjectOperator::GetInstance().SaveDataObj( - drk_key_, nlohmann::json::array()); - SPDLOG_ERROR("drk_key_ is not an array, abort."); - return; + drk_key_, QJsonDocument(key_storage_)); } - for (auto key : registered_key_list) { - load_cache_storage(key, {}); + private: + QCache<QString, QString> runtime_cache_storage_; + ThreadSafeMap<QString, QJsonDocument> durable_cache_storage_; + QJsonArray key_storage_; + QTimer* flush_timer_; + const QString drk_key_ = "__cache_manage_data_register_key_list"; + + /** + * @brief Get the data object key object + * + * @param key + * @return QString + */ + static auto get_data_object_key(const QString& key) -> QString { + return QString("__cache_data_%1").arg(key); } - key_storage_ = registered_key_list; -}
\ No newline at end of file + /** + * @brief + * + * @param key + * @param default_value + * @return QJsonObject + */ + static auto load_cache_storage(const QString& key, + QJsonDocument default_value) -> QJsonDocument { + auto data_object_key = get_data_object_key(key); + auto stored_data = + GpgFrontend::DataObjectOperator::GetInstance().GetDataObject( + data_object_key); + + if (stored_data.has_value()) return stored_data.value(); + return default_value; + } + + /** + * @brief + * + */ + void load_all_cache_storage() { + GF_CORE_LOG_DEBUG("start to load all cache from file system"); + auto stored_data = + GpgFrontend::DataObjectOperator::GetInstance().GetDataObject(drk_key_); + + // get cache data list from file system + QJsonArray registered_key_list; + if (stored_data->isArray()) { + registered_key_list = stored_data->array(); + } else { + GpgFrontend::DataObjectOperator::GetInstance().SaveDataObj( + drk_key_, QJsonDocument(QJsonArray())); + } + + for (const auto& key : registered_key_list) { + load_cache_storage(key.toString(), {}); + } + + key_storage_ = registered_key_list; + } + + /** + * @brief + * + * @param key + */ + void register_cache_key(const QString& key) {} +}; + +CacheManager::CacheManager(int channel) + : SingletonFunctionObject<CacheManager>(channel), + p_(SecureCreateUniqueObject<Impl>()) {} + +CacheManager::~CacheManager() { p_->FlushCacheStorage(); } + +void CacheManager::SaveDurableCache(const QString& key, + const QJsonDocument& value, bool flush) { + p_->SaveDurableCache(key, value, flush); +} + +auto CacheManager::LoadDurableCache(const QString& key) -> QJsonDocument { + return p_->LoadDurableCache(key); +} + +auto CacheManager::LoadDurableCache(const QString& key, + QJsonDocument default_value) + -> QJsonDocument { + return p_->LoadDurableCache(key, std::move(default_value)); +} + +auto CacheManager::ResetDurableCache(const QString& key) -> bool { + return p_->ResetDurableCache(key); +} + +void CacheManager::SaveCache(const QString& key, QString value) { + p_->SaveCache(key, std::move(value)); +} + +auto CacheManager::LoadCache(const QString& key) -> QString { + return p_->LoadCache(key); +} + +void CacheManager::ResetCache(const QString& key) { + return p_->ResetCache(key); +} +} // namespace GpgFrontend + +#include "CacheManager.moc"
\ No newline at end of file diff --git a/src/core/function/CacheManager.h b/src/core/function/CacheManager.h index 8234de2a..67e7fd75 100644 --- a/src/core/function/CacheManager.h +++ b/src/core/function/CacheManager.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,94 +20,99 @@ * 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_CACHEMANAGER_H -#define GPGFRONTEND_CACHEMANAGER_H +#pragma once -#include <string> - -#include "core/GpgFunctionObject.h" +#include "core/function/basic/GpgFunctionObject.h" namespace GpgFrontend { -template <typename Key, typename Value> -class ThreadSafeMap { - public: - using MapType = std::map<Key, Value>; - using IteratorType = typename MapType::iterator; - - void insert(const Key& key, const Value& value) { - std::unique_lock lock(mutex_); - map_[key] = value; - } - - std::optional<Value> get(const Key& key) { - std::shared_lock lock(mutex_); - auto it = map_.find(key); - if (it != map_.end()) { - return it->second; - } - return std::nullopt; - } - - bool exists(const Key& key) { - std::shared_lock lock(mutex_); - return map_.count(key) > 0; - } - - IteratorType begin() { return map_mirror_.begin(); } - - IteratorType end() { return map_mirror_.end(); } - - ThreadSafeMap& mirror() { - std::shared_lock lock(mutex_); - map_mirror_ = map_; - return *this; - } - - private: - MapType map_mirror_; - MapType map_; - mutable std::shared_mutex mutex_; -}; - class GPGFRONTEND_CORE_EXPORT CacheManager - : public QObject, - public SingletonFunctionObject<CacheManager> { - Q_OBJECT + : public SingletonFunctionObject<CacheManager> { public: - CacheManager(int channel = SingletonFunctionObject::GetDefaultChannel()); - - void SaveCache(std::string key, const nlohmann::json& value, - bool flush = false); - - nlohmann::json LoadCache(std::string key); - - nlohmann::json LoadCache(std::string key, nlohmann::json default_value); + /** + * @brief Construct a new Cache Manager object + * + * @param channel + */ + explicit CacheManager( + int channel = SingletonFunctionObject::GetDefaultChannel()); + + /** + * @brief Destroy the Cache Manager object + * + */ + ~CacheManager() override; + + /** + * @brief + * + * @param key + * @param value + */ + void SaveCache(const QString& key, QString value); + + /** + * @brief + * + * @param key + * @param value + * @param flush + */ + void SaveDurableCache(const QString& key, const QJsonDocument& value, + bool flush = false); + + /** + * @brief + * + * @param key + * @param value + */ + auto LoadCache(const QString& key) -> QString; + + /** + * @brief + * + * @param key + * @return QJsonDocument + */ + auto LoadDurableCache(const QString& key) -> QJsonDocument; + + /** + * @brief + * + * @param key + * @param default_value + * @return QJsonDocument + */ + auto LoadDurableCache(const QString& key, QJsonDocument default_value) + -> QJsonDocument; + + /** + * @brief + * + * @param key + * @return auto + */ + void ResetCache(const QString& key); + + /** + * @brief + * + * @param key + * @return true + * @return false + */ + auto ResetDurableCache(const QString& key) -> bool; private: - std::string get_data_object_key(std::string key); - - nlohmann::json load_cache_storage(std::string key, - nlohmann::json default_value); - - void load_all_cache_storage(); - - void flush_cache_storage(); - - void register_cache_key(std::string key); - - ThreadSafeMap<std::string, nlohmann::json> cache_storage_; - nlohmann::json key_storage_; - QTimer* m_timer_; - const std::string drk_key_ = "__cache_manage_data_register_key_list"; + class Impl; + SecureUniquePtr<Impl> p_; }; } // namespace GpgFrontend - -#endif diff --git a/src/core/function/CharsetOperator.cpp b/src/core/function/CharsetOperator.cpp deleted file mode 100644 index 72c5e72b..00000000 --- a/src/core/function/CharsetOperator.cpp +++ /dev/null @@ -1,133 +0,0 @@ -/** - * Copyright (C) 2021 Saturneric - * - * This file is part of GpgFrontend. - * - * GpgFrontend is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GpgFrontend is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GpgFrontend. If not, see <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/CharsetOperator.h" - -#include <spdlog/spdlog.h> -#include <unicode/ucnv.h> -#include <unicode/ucsdet.h> -#include <unicode/ustring.h> -#include <unicode/utypes.h> - -#include <cstddef> -#include <memory> -#include <string> - -GpgFrontend::CharsetOperator::CharsetInfo GpgFrontend::CharsetOperator::Detect( - const std::string &buffer) { - const UCharsetMatch *ucm; - UErrorCode status = U_ZERO_ERROR; - UCharsetDetector *csd = ucsdet_open(&status); - - status = U_ZERO_ERROR; - if (U_FAILURE(status)) { - SPDLOG_ERROR("failed to open charset detector: {}", u_errorName(status)); - return {"unknown", "unknown", 0}; - } - - SPDLOG_DEBUG("detecting charset buffer: {} bytes", buffer.size()); - - status = U_ZERO_ERROR; - ucsdet_setText(csd, buffer.data(), buffer.size(), &status); - if (U_FAILURE(status)) { - SPDLOG_ERROR("failed to set text to charset detector: {}", - u_errorName(status)); - return {"unknown", "unknown", 0}; - } - - status = U_ZERO_ERROR; - ucm = ucsdet_detect(csd, &status); - - if (U_FAILURE(status)) return {"unknown", "unknown", 0}; - - status = U_ZERO_ERROR; - const char *name = ucsdet_getName(ucm, &status); - if (U_FAILURE(status)) return {"unknown", "unknown", 0}; - - status = U_ZERO_ERROR; - int confidence = ucsdet_getConfidence(ucm, &status); - if (U_FAILURE(status)) return {name, "unknown", 0}; - - status = U_ZERO_ERROR; - const char *language = ucsdet_getLanguage(ucm, &status); - if (U_FAILURE(status)) return {name, "unknown", confidence}; - - SPDLOG_DEBUG("Detected charset: {} {} {}", name, language, confidence); - return {name, language, confidence}; -} - -bool GpgFrontend::CharsetOperator::Convert2Utf8(const std::string &buffer, - std::string &out_buffer, - std::string from_charset_name) { - UErrorCode status = U_ZERO_ERROR; - const auto from_encode = std::string("utf-8"); - const auto to_encode = from_charset_name; - - SPDLOG_DEBUG("Converting buffer: {}", buffer.size()); - - // test if the charset is supported - UConverter *conv = ucnv_open(from_encode.c_str(), &status); - ucnv_close(conv); - if (U_FAILURE(status)) { - SPDLOG_ERROR("failed to open converter: {}, from encode: {}", - u_errorName(status), from_encode); - return false; - } - - // test if the charset is supported - conv = ucnv_open(to_encode.c_str(), &status); - ucnv_close(conv); - if (U_FAILURE(status)) { - SPDLOG_ERROR("failed to open converter: {}, to encode: {}", - u_errorName(status), to_encode); - return false; - } - - status = U_ZERO_ERROR; - int32_t target_limit = 0, target_capacity = 0; - - target_capacity = - ucnv_convert(from_encode.c_str(), to_encode.c_str(), nullptr, - target_limit, buffer.data(), buffer.size(), &status); - - if (status == U_BUFFER_OVERFLOW_ERROR) { - status = U_ZERO_ERROR; - out_buffer.clear(); - out_buffer.resize(target_capacity); - ucnv_convert(from_encode.c_str(), to_encode.c_str(), out_buffer.data(), - out_buffer.size(), buffer.data(), buffer.size(), &status); - } - - if (U_FAILURE(status)) { - SPDLOG_ERROR("failed to convert to utf-8: {}", u_errorName(status)); - return false; - } - - SPDLOG_DEBUG("converted buffer: {} bytes", out_buffer.size()); - return true; -}
\ No newline at end of file diff --git a/src/core/function/CoreSignalStation.cpp b/src/core/function/CoreSignalStation.cpp index f78d417b..8cb84743 100644 --- a/src/core/function/CoreSignalStation.cpp +++ b/src/core/function/CoreSignalStation.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 * @@ -29,11 +29,12 @@ #include "core/function/CoreSignalStation.h" std::unique_ptr<GpgFrontend::CoreSignalStation> - GpgFrontend::CoreSignalStation::_instance = nullptr; + GpgFrontend::CoreSignalStation::instance = nullptr; -GpgFrontend::CoreSignalStation* GpgFrontend::CoreSignalStation::GetInstance() { - if (_instance == nullptr) { - _instance = std::make_unique<CoreSignalStation>(); +auto GpgFrontend::CoreSignalStation::GetInstance() + -> GpgFrontend::CoreSignalStation* { + if (instance == nullptr) { + instance = std::make_unique<CoreSignalStation>(); } - return _instance.get(); + return instance.get(); } diff --git a/src/core/function/CoreSignalStation.h b/src/core/function/CoreSignalStation.h index 7497cab7..e0a11fa3 100644 --- a/src/core/function/CoreSignalStation.h +++ b/src/core/function/CoreSignalStation.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,26 +20,27 @@ * 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_CORESIGNALSTATION_H -#define GPGFRONTEND_CORESIGNALSTATION_H +#pragma once #include "core/GpgFrontendCore.h" namespace GpgFrontend { +class GpgPassphraseContext; + /** * @brief * */ class GPGFRONTEND_CORE_EXPORT CoreSignalStation : public QObject { Q_OBJECT - static std::unique_ptr<CoreSignalStation> _instance; + static std::unique_ptr<CoreSignalStation> instance; public: /** @@ -47,7 +48,7 @@ class GPGFRONTEND_CORE_EXPORT CoreSignalStation : public QObject { * * @return SignalStation* */ - static CoreSignalStation* GetInstance(); + static auto GetInstance() -> CoreSignalStation*; signals: @@ -55,15 +56,25 @@ class GPGFRONTEND_CORE_EXPORT CoreSignalStation : public QObject { * @brief * */ - void SignalUserInputPassphraseDone(QString passparase); + void SignalNeedUserInputPassphrase(QSharedPointer<GpgPassphraseContext>); + + /** + * @brief + * + */ + void SignalUserInputPassphraseCallback(QSharedPointer<GpgPassphraseContext>); /** * @brief * */ - void SignalNeedUserInputPassphrase(); + void SignalBadGnupgEnv(QString); + + /** + * @brief + * + */ + void SignalGoodGnupgEnv(); }; } // namespace GpgFrontend - -#endif // GPGFRONTEND_CORESIGNALSTATION_H diff --git a/src/core/function/DataObjectOperator.cpp b/src/core/function/DataObjectOperator.cpp index 180cef30..cbf21f8e 100644 --- a/src/core/function/DataObjectOperator.cpp +++ b/src/core/function/DataObjectOperator.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 * @@ -30,143 +30,131 @@ #include <qt-aes/qaesencryption.h> -#include <boost/date_time.hpp> - -#include "core/function/FileOperator.h" #include "core/function/PassphraseGenerator.h" +#include "core/utils/IOUtils.h" + +namespace GpgFrontend { -void GpgFrontend::DataObjectOperator::init_app_secure_key() { - SPDLOG_DEBUG("initializing application secure key"); - FileOperator::WriteFileStd(app_secure_key_path_, - PassphraseGenerator::GetInstance().Generate(256)); - std::filesystem::permissions( - app_secure_key_path_, - std::filesystem::perms::owner_read | std::filesystem::perms::owner_write); +void DataObjectOperator::init_app_secure_key() { + GF_CORE_LOG_INFO("initializing application secure key..."); + WriteFile(app_secure_key_path_, + PassphraseGenerator::GetInstance().Generate(256).toUtf8()); + QFile::setPermissions(app_secure_key_path_, + QFileDevice::ReadOwner | QFileDevice::WriteOwner); } -GpgFrontend::DataObjectOperator::DataObjectOperator(int channel) +DataObjectOperator::DataObjectOperator(int channel) : SingletonFunctionObject<DataObjectOperator>(channel) { - if (!is_directory(app_secure_path_)) create_directory(app_secure_path_); - - if (!exists(app_secure_key_path_)) { - init_app_secure_key(); + if (!QDir(app_secure_path_).exists()) QDir(app_secure_path_).mkpath("."); + if (!QFileInfo(app_secure_key_path_).exists()) init_app_secure_key(); + + QByteArray key; + if (!ReadFile(app_secure_key_path_, key)) { + GF_CORE_LOG_ERROR("failed to read app secure key file: {}", + app_secure_key_path_); + // unsafe mode + key = {}; } - std::string key; - if (!FileOperator::ReadFileStd(app_secure_key_path_.u8string(), key)) { - SPDLOG_ERROR("failed to read app secure key file: {}", - app_secure_key_path_.u8string()); - throw std::runtime_error("failed to read app secure key file"); - } - hash_key_ = QCryptographicHash::hash(QByteArray::fromStdString(key), - QCryptographicHash::Sha256); - SPDLOG_DEBUG("app secure key loaded {} bytes", hash_key_.size()); + hash_key_ = QCryptographicHash::hash(key, QCryptographicHash::Sha256); - if (!exists(app_data_objs_path_)) create_directory(app_data_objs_path_); + if (!QDir(app_data_objs_path_).exists()) { + QDir(app_data_objs_path_).mkpath("."); + } } -std::string GpgFrontend::DataObjectOperator::SaveDataObj( - const std::string& _key, const nlohmann::json& value) { - std::string _hash_obj_key = {}; - if (_key.empty()) { - _hash_obj_key = +auto DataObjectOperator::SaveDataObj(const QString& key, + const QJsonDocument& value) -> QString { + QByteArray hash_obj_key; + if (key.isEmpty()) { + hash_obj_key = QCryptographicHash::hash( - hash_key_ + QByteArray::fromStdString( - PassphraseGenerator::GetInstance().Generate(32) + - to_iso_extended_string( - boost::posix_time::second_clock::local_time())), + hash_key_ + + PassphraseGenerator::GetInstance().Generate(32).toUtf8() + + QDateTime::currentDateTime().toString().toUtf8(), QCryptographicHash::Sha256) - .toHex() - .toStdString(); + .toHex(); } else { - _hash_obj_key = - QCryptographicHash::hash(hash_key_ + QByteArray::fromStdString(_key), - QCryptographicHash::Sha256) - .toHex() - .toStdString(); + hash_obj_key = QCryptographicHash::hash(hash_key_ + key.toUtf8(), + QCryptographicHash::Sha256) + .toHex(); } - const auto obj_path = app_data_objs_path_ / _hash_obj_key; - - QAESEncryption encryption(QAESEncryption::AES_256, QAESEncryption::ECB, - QAESEncryption::Padding::ISO); - auto encoded = - encryption.encode(QByteArray::fromStdString(to_string(value)), hash_key_); - - SPDLOG_DEBUG("saving data object {} to {} , size: {} bytes", _hash_obj_key, - obj_path.u8string(), encoded.size()); - - FileOperator::WriteFileStd(obj_path.u8string(), encoded.toStdString()); + const auto target_obj_path = app_data_objs_path_ + "/" + hash_obj_key; + auto encoded_data = + QAESEncryption(QAESEncryption::AES_256, QAESEncryption::ECB, + QAESEncryption::Padding::ISO) + .encode(value.toJson(), hash_key_); + GF_CORE_LOG_TRACE("saving data object {} to disk {} , size: {} bytes", + hash_obj_key, target_obj_path, encoded_data.size()); + + // recreate if not exists + if (!QDir(app_data_objs_path_).exists()) { + QDir(app_data_objs_path_).mkpath("."); + } - return _key.empty() ? _hash_obj_key : std::string(); + if (!WriteFile(target_obj_path, encoded_data)) { + GF_CORE_LOG_ERROR("failed to write data object to disk: {}", key); + } + return key.isEmpty() ? hash_obj_key : QString(); } -std::optional<nlohmann::json> GpgFrontend::DataObjectOperator::GetDataObject( - const std::string& _key) { +auto DataObjectOperator::GetDataObject(const QString& key) + -> std::optional<QJsonDocument> { try { - SPDLOG_DEBUG("get data object {}", _key); - auto _hash_obj_key = - QCryptographicHash::hash(hash_key_ + QByteArray::fromStdString(_key), - QCryptographicHash::Sha256) - .toHex() - .toStdString(); - - const auto obj_path = app_data_objs_path_ / _hash_obj_key; - - if (!std::filesystem::exists(obj_path)) { - SPDLOG_ERROR("data object not found :{}", _key); + GF_CORE_LOG_TRACE("try to get data object from disk, key: {}", key); + auto hash_obj_key = QCryptographicHash::hash(hash_key_ + key.toUtf8(), + QCryptographicHash::Sha256) + .toHex(); + + const auto obj_path = app_data_objs_path_ + "/" + hash_obj_key; + if (!QFileInfo(obj_path).exists()) { + GF_CORE_LOG_WARN("data object not found from disk, key: {}", key); return {}; } - std::string buffer; - if (!FileOperator::ReadFileStd(obj_path.u8string(), buffer)) { - SPDLOG_ERROR("failed to read data object: {}", _key); + QByteArray encoded_data; + if (!ReadFile(obj_path, encoded_data)) { + GF_CORE_LOG_ERROR("failed to read data object from disk, key: {}", key); return {}; } - SPDLOG_DEBUG("data object found {}", _key); - - auto encoded = QByteArray::fromStdString(buffer); QAESEncryption encryption(QAESEncryption::AES_256, QAESEncryption::ECB, QAESEncryption::Padding::ISO); - SPDLOG_DEBUG("decrypting data object {} , hash key size: {}", - encoded.size(), hash_key_.size()); - - auto decoded = - encryption.removePadding(encryption.decode(encoded, hash_key_)); - - SPDLOG_DEBUG("data object decoded: {}", _key); - - return nlohmann::json::parse(decoded.toStdString()); + auto decoded_data = + encryption.removePadding(encryption.decode(encoded_data, hash_key_)); + GF_CORE_LOG_TRACE("data object has been decoded, key: {}, data: {}", key, + decoded_data); + return QJsonDocument::fromJson(decoded_data); } catch (...) { - SPDLOG_ERROR("failed to get data object: {}", _key); + GF_CORE_LOG_ERROR("failed to get data object, caught exception: {}", key); return {}; } } -std::optional<nlohmann::json> -GpgFrontend::DataObjectOperator::GetDataObjectByRef(const std::string& _ref) { +auto DataObjectOperator::GetDataObjectByRef(const QString& _ref) + -> std::optional<QJsonDocument> { if (_ref.size() != 64) return {}; try { - const auto& _hash_obj_key = _ref; - const auto obj_path = app_data_objs_path_ / _hash_obj_key; + const auto& hash_obj_key = _ref; + const auto obj_path = app_data_objs_path_ + "/" + hash_obj_key; - if (!std::filesystem::exists(obj_path)) return {}; + if (!QFileInfo(obj_path).exists()) return {}; - std::string buffer; - if (!FileOperator::ReadFileStd(obj_path.u8string(), buffer)) return {}; - auto encoded = QByteArray::fromStdString(buffer); + QByteArray encoded_data; + if (!ReadFile(obj_path, encoded_data)) return {}; QAESEncryption encryption(QAESEncryption::AES_256, QAESEncryption::ECB, QAESEncryption::Padding::ISO); - auto decoded = - encryption.removePadding(encryption.decode(encoded, hash_key_)); + auto decoded_data = + encryption.removePadding(encryption.decode(encoded_data, hash_key_)); - return nlohmann::json::parse(decoded.toStdString()); + return QJsonDocument::fromJson(decoded_data); } catch (...) { return {}; } } +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/function/DataObjectOperator.h b/src/core/function/DataObjectOperator.h index ae5dc62c..fedbd905 100644 --- a/src/core/function/DataObjectOperator.h +++ b/src/core/function/DataObjectOperator.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,17 +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 GPGFRONTEND_DATAOBJECTOPERATOR_H -#define GPGFRONTEND_DATAOBJECTOPERATOR_H +#pragma once + +#include <optional> -#include "core/GpgFunctionObject.h" #include "core/function/GlobalSettingStation.h" +#include "core/function/basic/GpgFunctionObject.h" namespace GpgFrontend { @@ -45,11 +46,11 @@ class GPGFRONTEND_CORE_EXPORT DataObjectOperator explicit DataObjectOperator( int channel = SingletonFunctionObject::GetDefaultChannel()); - std::string SaveDataObj(const std::string &_key, const nlohmann::json &value); + auto SaveDataObj(const QString &_key, const QJsonDocument &value) -> QString; - std::optional<nlohmann::json> GetDataObject(const std::string &_key); + auto GetDataObject(const QString &_key) -> std::optional<QJsonDocument>; - std::optional<nlohmann::json> GetDataObjectByRef(const std::string &_ref); + auto GetDataObjectByRef(const QString &_ref) -> std::optional<QJsonDocument>; private: /** @@ -60,21 +61,16 @@ class GPGFRONTEND_CORE_EXPORT DataObjectOperator GlobalSettingStation &global_setting_station_ = GlobalSettingStation::GetInstance(); ///< GlobalSettingStation - std::filesystem::path app_secure_path_ = - global_setting_station_.GetAppConfigPath() / - "secure"; ///< Where sensitive information is stored - std::filesystem::path app_secure_key_path_ = - app_secure_path_ / "app.key"; ///< Where the key of data object is stored - std::filesystem::path app_data_objs_path_ = - global_setting_station_.GetAppDataPath() / "data_objs"; ///< Where data - ///< object is - ///< stored + QString app_secure_path_ = + global_setting_station_.GetAppDataPath() + + "/secure"; ///< Where sensitive information is stored + QString app_secure_key_path_ = + app_secure_path_ + + "/app.key"; ///< Where the key of data object is stored + QString app_data_objs_path_ = + global_setting_station_.GetAppDataPath() + "/data_objs"; - std::random_device rd_; ///< Random device - std::mt19937 mt_ = std::mt19937(rd_()); ///< Mersenne twister - QByteArray hash_key_; ///< Hash key + QByteArray hash_key_; ///< Hash key }; } // namespace GpgFrontend - -#endif // GPGFRONTEND_DATAOBJECTOPERATOR_H diff --git a/src/core/function/FileOperator.cpp b/src/core/function/FileOperator.cpp deleted file mode 100644 index 41552246..00000000 --- a/src/core/function/FileOperator.cpp +++ /dev/null @@ -1,124 +0,0 @@ -/** - * Copyright (C) 2021 Saturneric - * - * This file is part of GpgFrontend. - * - * GpgFrontend is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GpgFrontend is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GpgFrontend. If not, see <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 "FileOperator.h" - -bool GpgFrontend::FileOperator::ReadFile(const QString& file_name, - QByteArray& data) { - QFile file(file_name); - if (!file.open(QIODevice::ReadOnly)) { - SPDLOG_ERROR("failed to open file: {}", file_name.toStdString()); - return false; - } - data = file.readAll(); - file.close(); - return true; -} - -bool GpgFrontend::FileOperator::WriteFile(const QString& file_name, - const QByteArray& data) { - QFile file(file_name); - if (!file.open(QIODevice::WriteOnly)) { - SPDLOG_ERROR("failed to open file: {}", file_name.toStdString()); - return false; - } - file.write(data); - file.close(); - return true; -} - -bool GpgFrontend::FileOperator::ReadFileStd( - const std::filesystem::path& file_name, std::string& data) { - QByteArray byte_data; -#ifdef WINDOWS - bool res = ReadFile(QString::fromStdU16String(file_name.u16string()).toUtf8(), - byte_data); -#else - bool res = ReadFile(QString::fromStdString(file_name.u8string()).toUtf8(), - byte_data); -#endif - data = byte_data.toStdString(); - return res; -} - -bool GpgFrontend::FileOperator::WriteFileStd( - const std::filesystem::path& file_name, const std::string& data) { - return WriteFile(QString::fromStdString(file_name.u8string()).toUtf8(), - QByteArray::fromStdString(data)); -} - -std::string GpgFrontend::FileOperator::CalculateHash( - const std::filesystem::path& file_path) { - // Returns empty QByteArray() on failure. - QFileInfo info(QString::fromStdString(file_path.string())); - std::stringstream ss; - - if (info.isFile() && info.isReadable()) { - ss << "[#] " << _("File Hash Information") << std::endl; - ss << " " << _("filename") << _(": ") - << file_path.filename().u8string().c_str() << std::endl; - - QFile f(info.filePath()); - if (f.open(QFile::ReadOnly)) { - // read all data - auto buffer = f.readAll(); - ss << " " << _("file size(bytes)") << _(": ") << buffer.size() - << std::endl; - - // md5 - auto hash_md5 = QCryptographicHash(QCryptographicHash::Md5); - hash_md5.addData(buffer); - auto md5 = hash_md5.result().toHex().toStdString(); - SPDLOG_DEBUG("md5 {}", md5); - ss << " " - << "md5" << _(": ") << md5 << std::endl; - - // sha1 - auto hash_sha1 = QCryptographicHash(QCryptographicHash::Sha1); - hash_sha1.addData(buffer); - auto sha1 = hash_sha1.result().toHex().toStdString(); - SPDLOG_DEBUG("sha1 {}", sha1); - ss << " " - << "sha1" << _(": ") << sha1 << std::endl; - - // sha1 - auto hash_sha256 = QCryptographicHash(QCryptographicHash::Sha256); - hash_sha256.addData(buffer); - auto sha256 = hash_sha256.result().toHex().toStdString(); - SPDLOG_DEBUG("sha256 {}", sha256); - ss << " " - << "sha256" << _(": ") << sha256 << std::endl; - - ss << std::endl; - } - } else { - ss << "[#] " << _("Error in Calculating File Hash ") << std::endl; - } - - return ss.str(); -} diff --git a/src/core/function/FileOperator.h b/src/core/function/FileOperator.h deleted file mode 100644 index a727b1de..00000000 --- a/src/core/function/FileOperator.h +++ /dev/null @@ -1,92 +0,0 @@ -/** - * Copyright (C) 2021 Saturneric - * - * This file is part of GpgFrontend. - * - * GpgFrontend is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GpgFrontend is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GpgFrontend. If not, see <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 - * - */ - -#ifndef GPGFRONTEND_FILEOPERATOR_H -#define GPGFRONTEND_FILEOPERATOR_H - -#include "core/GpgFrontendCore.h" - -namespace GpgFrontend { - -/** - * @brief provides file operations - * - */ -class GPGFRONTEND_CORE_EXPORT FileOperator { - public: - /** - * @brief read file content using std struct - * - * - * @param file_name file name - * @param data data read from file - * @return - */ - static bool ReadFileStd(const std::filesystem::path &file_name, - std::string &data); - - /** - * @brief write file content using std struct - * - * @param file_name file name - * @param data data to write to file - * @return - */ - static bool WriteFileStd(const std::filesystem::path &file_name, - const std::string &data); - - /** - * @brief read file content - * - * @param file_name file name - * @param data data read from file - * @return true if success - * @return false if failed - */ - static bool ReadFile(const QString &file_name, QByteArray &data); - - /** - * @brief write file content - * - * @param file_name file name - * @param data data to write to file - * @return true if success - * @return false if failed - */ - static bool WriteFile(const QString &file_name, const QByteArray &data); - - /** - * calculate the hash of a file - * @param file_path - * @return - */ - static std::string CalculateHash(const std::filesystem::path &file_path); -}; -} // namespace GpgFrontend - -#endif // GPGFRONTEND_FILEOPERATOR_H diff --git a/src/core/function/GlobalSettingStation.cpp b/src/core/function/GlobalSettingStation.cpp index 6b743268..6969c15a 100644 --- a/src/core/function/GlobalSettingStation.cpp +++ b/src/core/function/GlobalSettingStation.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,136 +28,148 @@ #include "GlobalSettingStation.h" -#include "core/function/FileOperator.h" +#include "core/module/ModuleManager.h" +#include "core/utils/FilesystemUtils.h" -void GpgFrontend::GlobalSettingStation::SyncSettings() noexcept { - using namespace libconfig; - try { - ui_cfg_.writeFile(ui_config_path_.u8string().c_str()); - SPDLOG_DEBUG("updated ui configuration successfully written to {}", - ui_config_path_.u8string()); +namespace GpgFrontend { - } catch (const FileIOException &fioex) { - SPDLOG_ERROR("i/o error while writing ui configuration file: {}", - ui_config_path_.u8string()); - } -} +class GlobalSettingStation::Impl { + public: + /** + * @brief Construct a new Global Setting Station object + * + */ + explicit Impl() noexcept { + GF_CORE_LOG_INFO("app path: {}", GetAppDir()); + GF_CORE_LOG_INFO("app working path: {}", working_path_); -GpgFrontend::GlobalSettingStation::GlobalSettingStation(int channel) noexcept - : SingletonFunctionObject<GlobalSettingStation>(channel) { - using namespace std::filesystem; - using namespace libconfig; - - SPDLOG_INFO("app path: {}", app_path_.u8string()); - SPDLOG_INFO("app configure path: {}", app_configure_path_.u8string()); - SPDLOG_INFO("app data path: {}", app_data_path_.u8string()); - SPDLOG_INFO("app log path: {}", app_log_path_.u8string()); - SPDLOG_INFO("app locale path: {}", app_locale_path_.u8string()); - SPDLOG_INFO("app conf path: {}", ui_config_path_.u8string()); - - SPDLOG_INFO("app log files total size: {}", GetLogFilesSize()); - SPDLOG_INFO("app data objects files total size: {}", - GetDataObjectsFilesSize()); - - if (!is_directory(app_configure_path_)) create_directory(app_configure_path_); - if (!is_directory(app_data_path_)) create_directory(app_data_path_); - if (!is_directory(app_log_path_)) create_directory(app_log_path_); - if (!is_directory(ui_config_dir_path_)) create_directory(ui_config_dir_path_); - - if (!exists(ui_config_path_)) { - try { - this->ui_cfg_.writeFile(ui_config_path_.u8string().c_str()); - SPDLOG_DEBUG("user interface configuration successfully written to {}", - ui_config_path_.u8string()); - - } catch (const FileIOException &fioex) { - SPDLOG_DEBUG( - "i/o error while writing UserInterface configuration file {}", - ui_config_path_.u8string()); - } - } else { - try { - this->ui_cfg_.readFile(ui_config_path_.u8string().c_str()); - SPDLOG_DEBUG("user interface configuration successfully read from {}", - ui_config_path_.u8string()); - } catch (const FileIOException &fioex) { - SPDLOG_ERROR("i/o error while reading UserInterface configure file"); - } catch (const ParseException &pex) { - SPDLOG_ERROR("parse error at {} : {} - {}", pex.getFile(), pex.getLine(), - pex.getError()); + auto portable_file_path = working_path_ + "/PORTABLE.txt"; + if (QFileInfo(portable_file_path).exists()) { + GF_CORE_LOG_INFO( + "dectected portable mode, reconfiguring config and data path..."); + Module::UpsertRTValue("core", "env.state.portable", 1); + + app_data_path_ = working_path_; + app_log_path_ = app_data_path_ + "/logs"; + app_data_objs_path_ = app_data_path_ + "/data_objs"; + + portable_mode_ = true; } + + GF_CORE_LOG_INFO("app data path: {}", app_data_path_); + GF_CORE_LOG_INFO("app log path: {}", app_log_path_); + + GF_CORE_LOG_DEBUG("app log files total size: {}", GetLogFilesSize()); + GF_CORE_LOG_DEBUG("app data objects files total size: {}", + GetDataObjectsFilesSize()); + + if (!QDir(app_data_path_).exists()) QDir(app_data_path_).mkpath("."); + if (!QDir(app_log_path_).exists()) QDir(app_log_path_).mkpath("."); } -} -libconfig::Setting & -GpgFrontend::GlobalSettingStation::GetUISettings() noexcept { - return ui_cfg_.getRoot(); -} + [[nodiscard]] auto GetSettings() -> QSettings { + if (!portable_mode_) return QSettings(); + return {app_portable_config_path_, QSettings::IniFormat}; + } -void GpgFrontend::GlobalSettingStation::init_app_secure_key() {} + [[nodiscard]] auto GetLogFilesSize() const -> QString { + return GetHumanFriendlyFileSize(GetFileSizeByPath(app_log_path_, "*.log")); + } -int64_t GpgFrontend::GlobalSettingStation::get_files_size_at_path( - std::filesystem::path path, std::string filename_pattern) const { - auto dir = QDir(QString::fromStdString(path.u8string())); - QFileInfoList fileList = dir.entryInfoList( - QStringList() << QString::fromStdString(filename_pattern), QDir::Files); - qint64 totalSize = 0; + [[nodiscard]] auto GetDataObjectsFilesSize() const -> QString { + return GetHumanFriendlyFileSize( + GetFileSizeByPath(app_data_objs_path_, "*")); + } - for (const QFileInfo &fileInfo : fileList) { - totalSize += fileInfo.size(); + void ClearAllLogFiles() const { + DeleteAllFilesByPattern(app_log_path_, "*.log"); + } + + void ClearAllDataObjects() const { + DeleteAllFilesByPattern(app_data_objs_path_, "*"); + } + + /** + * @brief Get the App Dir object + * + * @return QString + */ + [[nodiscard]] auto GetAppDir() const -> QString { + return QCoreApplication::applicationDirPath(); } - return totalSize; -} -std::string GpgFrontend::GlobalSettingStation::get_human_readable_size( - int64_t size) const { - double num = size; - QStringList list; - list << "KB" - << "MB" - << "GB" - << "TB"; - - QStringListIterator i(list); - QString unit("bytes"); - - while (num >= 1024.0 && i.hasNext()) { - unit = i.next(); - num /= 1024.0; + /** + * @brief Get the App Data Path object + * + * @return QString + */ + [[nodiscard]] auto GetAppDataPath() const -> QString { + return app_data_path_; } - return (QString().setNum(num, 'f', 2) + " " + unit).toStdString(); + + /** + * @brief Get the Log Dir object + * + * @return QString + */ + [[nodiscard]] auto GetLogDir() const -> QString { return app_log_path_; } + + private: + QString working_path_ = QDir::currentPath(); + + QString app_data_path_ = QString{QStandardPaths::writableLocation( + QStandardPaths::AppLocalDataLocation)}; ///< Program Data Location + + QString app_log_path_ = app_data_path_ + "/logs"; ///< Program Data Location + + QString app_data_objs_path_ = + app_data_path_ + "/data_objs"; ///< Object storage path + + bool portable_mode_ = false; ///< + QString app_portable_config_path_ = + working_path_ + "/config.ini"; ///< take effect only in portable mode + + /** + * @brief + * + */ + void init_app_secure_key() {} +}; + +GlobalSettingStation::GlobalSettingStation(int channel) noexcept + : SingletonFunctionObject<GlobalSettingStation>(channel), + p_(SecureCreateUniqueObject<Impl>()) {} + +GlobalSettingStation::~GlobalSettingStation() noexcept = default; + +auto GlobalSettingStation::GetSettings() const -> QSettings { + return p_->GetSettings(); } -std::string GpgFrontend::GlobalSettingStation::GetLogFilesSize() const { - return get_human_readable_size( - get_files_size_at_path(app_log_path_, "*.log")); +auto GlobalSettingStation::GetAppDir() const -> QString { + return p_->GetAppDir(); } -std::string GpgFrontend::GlobalSettingStation::GetDataObjectsFilesSize() const { - return get_human_readable_size( - get_files_size_at_path(app_data_objs_path_, "*")); +auto GlobalSettingStation::GetAppDataPath() const -> QString { + return p_->GetAppDataPath(); } -void GpgFrontend::GlobalSettingStation::ClearAllLogFiles() const { - delete_all_files(app_log_path_, "*.log"); +[[nodiscard]] auto GlobalSettingStation::GetLogDir() const -> QString { + return p_->GetLogDir(); } -void GpgFrontend::GlobalSettingStation::ClearAllDataObjects() const { - delete_all_files(app_data_objs_path_, "*"); +auto GlobalSettingStation::GetLogFilesSize() const -> QString { + return p_->GetLogFilesSize(); } -void GpgFrontend::GlobalSettingStation::delete_all_files( - std::filesystem::path path, std::string filename_pattern) const { - auto dir = QDir(QString::fromStdString(path.u8string())); +auto GlobalSettingStation::GetDataObjectsFilesSize() const -> QString { + return p_->GetDataObjectsFilesSize(); +} - // 使用name filters来只选取以.log结尾的文件 - QStringList logFiles = dir.entryList( - QStringList() << QString::fromStdString(filename_pattern), QDir::Files); +void GlobalSettingStation::ClearAllLogFiles() const { p_->ClearAllLogFiles(); } - // 遍历并删除所有符合条件的文件 - for (const auto &file : logFiles) { - QFile::remove(dir.absoluteFilePath(file)); - } +void GlobalSettingStation::ClearAllDataObjects() const { + p_->ClearAllDataObjects(); } -GpgFrontend::GlobalSettingStation::~GlobalSettingStation() noexcept = default; +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/function/GlobalSettingStation.h b/src/core/function/GlobalSettingStation.h index 80780f4b..85ac57b4 100644 --- a/src/core/function/GlobalSettingStation.h +++ b/src/core/function/GlobalSettingStation.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,26 +20,24 @@ * 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_GLOBALSETTINGSTATION_H -#define GPGFRONTEND_GLOBALSETTINGSTATION_H +#pragma once -#include <filesystem> - -#include "GpgFrontendBuildInstallInfo.h" -#include "core/GpgFrontendCore.h" -#include "core/GpgFunctionObject.h" +#include "core/function/basic/GpgFunctionObject.h" namespace GpgFrontend { /** - * @brief + * @class GlobalSettingStation + * @brief Singleton class for managing global settings in the application. * + * This class handles reading and writing of global settings, as well as + * managing application directories and resource paths. */ class GPGFRONTEND_CORE_EXPORT GlobalSettingStation : public SingletonFunctionObject<GlobalSettingStation> { @@ -58,179 +56,60 @@ class GPGFRONTEND_CORE_EXPORT GlobalSettingStation ~GlobalSettingStation() noexcept override; /** - * @brief - * - * @return libconfig::Setting& - */ - libconfig::Setting &GetUISettings() noexcept; - - /** - * @brief + * @brief Get the Settings object * - * @return libconfig::Setting& + * @return QSettings */ - template <typename T> - T LookupSettings(std::string path, T default_value) noexcept { - T value = default_value; - try { - value = static_cast<T>(GetUISettings().lookup(path)); - } catch (...) { - SPDLOG_WARN("setting not found: {}", path); - } - return value; - } + [[nodiscard]] auto GetSettings() const -> QSettings; /** * @brief Get the App Dir object * - * @return std::filesystem::path + * @return QString */ - [[nodiscard]] std::filesystem::path GetAppDir() const { return app_path_; } - - [[nodiscard]] std::filesystem::path GetAppDataPath() const { - return app_data_path_; - } + [[nodiscard]] auto GetAppDir() const -> QString; /** - * @brief Get the Log Dir object - * - * @return std::filesystem::path + * @brief Gets the application data directory. + * @return Path to the application data directory. */ - [[nodiscard]] std::filesystem::path GetLogDir() const { - return app_log_path_; - } + [[nodiscard]] auto GetAppDataPath() const -> QString; /** - * @brief Get the Standalone Database Dir object - * - * @return std::filesystem::path - */ - [[nodiscard]] std::filesystem::path GetStandaloneDatabaseDir() const { - auto db_path = app_configure_path_ / "db"; - if (!std::filesystem::exists(db_path)) { - std::filesystem::create_directory(db_path); - } - return db_path; - } - - [[nodiscard]] std::filesystem::path GetAppConfigPath() const { - return app_configure_path_; - } - - /** - * @brief Get the Standalone Gpg Bin Dir object + * @brief Get the Log Dir object * - * @return std::filesystem::path + * @return QString */ - [[nodiscard]] std::filesystem::path GetStandaloneGpgBinDir() const { - return app_resource_path_ / "gpg1.4" / "gpg"; - } + [[nodiscard]] auto GetLogDir() const -> QString; /** - * @brief Get the Locale Dir object + * @brief Get the Log Files Size object * - * @return std::filesystem::path + * @return QString */ - [[nodiscard]] std::filesystem::path GetLocaleDir() const { - return app_locale_path_; - } + [[nodiscard]] auto GetLogFilesSize() const -> QString; /** - * @brief Get the Resource Dir object + * @brief Get the Data Objects Files Size object * - * @return std::filesystem::path + * @return QString */ - [[nodiscard]] std::filesystem::path GetResourceDir() const { - return app_resource_path_; - } + [[nodiscard]] auto GetDataObjectsFilesSize() const -> QString; /** - * @brief Get the Certs Dir object + * @brief clear all log files * - * @return std::filesystem::path */ - [[nodiscard]] std::filesystem::path GetCertsDir() const { - return app_resource_path_ / "certs"; - } - - [[nodiscard]] std::string GetLogFilesSize() const; - - [[nodiscard]] std::string GetDataObjectsFilesSize() const; - void ClearAllLogFiles() const; - void ClearAllDataObjects() const; - /** - * @brief sync the settings to the file + * @brief clear all data objects * */ - void SyncSettings() noexcept; + void ClearAllDataObjects() const; private: - std::filesystem::path app_path_ = QCoreApplication::applicationDirPath() - .toStdString(); ///< Program Location - std::filesystem::path app_data_path_ = - QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) - .toStdString(); ///< Program Data Location - std::filesystem::path app_log_path_ = - app_data_path_ / "logs"; ///< Program Data Location - std::filesystem::path app_data_objs_path_ = - app_data_path_ / "data_objs"; ///< Object storage path - -#ifdef LINUX_INSTALL_BUILD - std::filesystem::path app_resource_path_ = - std::filesystem::path(APP_LOCALSTATE_PATH) / - "gpgfrontend"; ///< Program Data Location -#else - std::filesystem::path app_resource_path_ = - RESOURCE_DIR_BOOST_PATH(app_path_); ///< Program Data Location -#endif - -#ifdef LINUX_INSTALL_BUILD - std::filesystem::path app_locale_path_ = - std::string(APP_LOCALE_PATH); ///< Program Data Location -#else - std::filesystem::path app_locale_path_ = - app_resource_path_ / "locales"; ///< Program Data Location -#endif - - std::filesystem::path app_configure_path_ = - QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation) - .toStdString(); ///< Program Configure Location - std::filesystem::path ui_config_dir_path_ = - app_configure_path_ / "conf"; ///< Configure File Directory Location - std::filesystem::path ui_config_path_ = - ui_config_dir_path_ / "main.cfg"; ///< Main Configure File Location - - libconfig::Config ui_cfg_; ///< UI Configure File - - /** - * @brief - * - */ - void init_app_secure_key(); - - /** - * @brief - * - */ - int64_t get_files_size_at_path(std::filesystem::path path, - std::string filename_pattern) const; - - /** - * @brief - * - */ - std::string get_human_readable_size(int64_t size) const; - - /** - * @brief - * - */ - void delete_all_files(std::filesystem::path path, - std::string filename_pattern) const; + class Impl; + SecureUniquePtr<Impl> p_; }; } // namespace GpgFrontend - -#endif // GPGFRONTEND_GLOBALSETTINGSTATION_H diff --git a/src/core/function/KeyPackageOperator.cpp b/src/core/function/KeyPackageOperator.cpp index 5c917ab8..d185b0ef 100644 --- a/src/core/function/KeyPackageOperator.cpp +++ b/src/core/function/KeyPackageOperator.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,92 +28,124 @@ #include "KeyPackageOperator.h" -#include "FileOperator.h" -#include "function/PassphraseGenerator.h" -#include "function/gpg/GpgKeyGetter.h" -#include "function/gpg/GpgKeyImportExporter.h" -#include "qt-aes/qaesencryption.h" +#include <qt-aes/qaesencryption.h> + +#include "core/function/KeyPackageOperator.h" +#include "core/function/PassphraseGenerator.h" +#include "core/function/gpg/GpgKeyImportExporter.h" +#include "core/model/GpgImportInformation.h" +#include "core/typedef/CoreTypedef.h" +#include "core/utils/AsyncUtils.h" +#include "core/utils/GpgUtils.h" +#include "core/utils/IOUtils.h" namespace GpgFrontend { -bool KeyPackageOperator::GeneratePassphrase( - const std::filesystem::path& phrase_path, std::string& phrase) { +auto KeyPackageOperator::GeneratePassphrase(const QString& phrase_path, + QString& phrase) -> bool { phrase = PassphraseGenerator::GetInstance().Generate(256); - SPDLOG_DEBUG("generated passphrase: {} bytes", phrase.size()); - return FileOperator::WriteFileStd(phrase_path, phrase); + GF_CORE_LOG_DEBUG("generated passphrase: {} bytes", phrase.size()); + return WriteFile(phrase_path, phrase.toUtf8()); } -bool KeyPackageOperator::GenerateKeyPackage( - const std::filesystem::path& key_package_path, - const std::string& key_package_name, KeyIdArgsListPtr& key_ids, - std::string& phrase, bool secret) { - SPDLOG_DEBUG("generating key package: {}", key_package_name); - - ByteArrayPtr key_export_data = nullptr; - if (!GpgKeyImportExporter::GetInstance().ExportAllKeys( - key_ids, key_export_data, secret)) { - SPDLOG_ERROR("failed to export keys"); - return false; - } - - auto key = QByteArray::fromStdString(phrase); - auto data = QString::fromStdString(*key_export_data).toLocal8Bit().toBase64(); - - auto hash_key = QCryptographicHash::hash(key, QCryptographicHash::Sha256); - QAESEncryption encryption(QAESEncryption::AES_256, QAESEncryption::ECB, - QAESEncryption::Padding::ISO); - auto encoded = encryption.encode(data, hash_key); - - SPDLOG_DEBUG("writing key package: {}", key_package_name); - return FileOperator::WriteFileStd(key_package_path, encoded.toStdString()); +void KeyPackageOperator::GenerateKeyPackage(const QString& key_package_path, + const QString& key_package_name, + const KeyArgsList& keys, + QString& phrase, bool secret, + const OperationCallback& cb) { + GF_CORE_LOG_DEBUG("generating key package: {}", key_package_name); + + GpgKeyImportExporter::GetInstance().ExportAllKeys( + keys, secret, true, [=](GpgError err, const DataObjectPtr& data_obj) { + if (CheckGpgError(err) != GPG_ERR_NO_ERROR) { + GF_LOG_ERROR("export keys error, reason: {}", + DescribeGpgErrCode(err).second); + cb(-1, data_obj); + return; + } + + if (CheckGpgError(err) == GPG_ERR_USER_1 || data_obj == nullptr || + !data_obj->Check<GFBuffer>()) { + cb(-1, data_obj); + return; + } + + auto gf_buffer = ExtractParams<GFBuffer>(data_obj, 0); + + auto data = gf_buffer.ConvertToQByteArray().toBase64(); + auto hash_key = QCryptographicHash::hash(phrase.toUtf8(), + QCryptographicHash::Sha256); + QAESEncryption encryption(QAESEncryption::AES_256, QAESEncryption::ECB, + QAESEncryption::Padding::ISO); + auto encoded_data = encryption.encode(data, hash_key); + GF_CORE_LOG_DEBUG("writing key package, name: {}", key_package_name); + + cb(WriteFile(key_package_path, encoded_data) ? 0 : -1, + TransferParams()); + return; + }); } -bool KeyPackageOperator::ImportKeyPackage( - const std::filesystem::path& key_package_path, - const std::filesystem::path& phrase_path, - GpgFrontend::GpgImportInformation& import_info) { - SPDLOG_DEBUG("importing key package: {]", key_package_path.u8string()); - - std::string encrypted_data; - FileOperator::ReadFileStd(key_package_path, encrypted_data); - - if (encrypted_data.empty()) { - SPDLOG_ERROR("failed to read key package: {}", key_package_path.u8string()); - return false; - }; - - std::string passphrase; - FileOperator::ReadFileStd(phrase_path, passphrase); - SPDLOG_DEBUG("passphrase: {} bytes", passphrase.size()); - if (passphrase.size() != 256) { - SPDLOG_ERROR("failed to read passphrase: {}", phrase_path.u8string()); - return false; - } - - auto hash_key = QCryptographicHash::hash( - QByteArray::fromStdString(passphrase), QCryptographicHash::Sha256); - auto encoded = QByteArray::fromStdString(encrypted_data); - - QAESEncryption encryption(QAESEncryption::AES_256, QAESEncryption::ECB, - QAESEncryption::Padding::ISO); - - auto decoded = encryption.removePadding(encryption.decode(encoded, hash_key)); - auto key_data = QByteArray::fromBase64(decoded); - - SPDLOG_DEBUG("key data size: {}", key_data.size()); - if (!key_data.startsWith(GpgConstants::PGP_PUBLIC_KEY_BEGIN) && - !key_data.startsWith(GpgConstants::PGP_PRIVATE_KEY_BEGIN)) { - return false; - } - - auto key_data_ptr = std::make_unique<ByteArray>(key_data.toStdString()); - import_info = - GpgKeyImportExporter::GetInstance().ImportKey(std::move(key_data_ptr)); - return true; +void KeyPackageOperator::ImportKeyPackage(const QString& key_package_path, + const QString& phrase_path, + const OperationCallback& cb) { + RunOperaAsync( + [=](const DataObjectPtr& data_object) -> GFError { + GF_CORE_LOG_DEBUG("importing key package: {}", key_package_path); + + QByteArray encrypted_data; + ReadFile(key_package_path, encrypted_data); + + if (encrypted_data.isEmpty()) { + GF_CORE_LOG_ERROR("failed to read key package: {}", key_package_path); + return -1; + }; + + QByteArray passphrase; + ReadFile(phrase_path, passphrase); + if (passphrase.size() != 256) { + GF_CORE_LOG_ERROR("passphrase size mismatch: {}", phrase_path); + return -1; + } + + auto hash_key = + QCryptographicHash::hash(passphrase, QCryptographicHash::Sha256); + auto encoded = encrypted_data; + + QAESEncryption encryption(QAESEncryption::AES_256, QAESEncryption::ECB, + QAESEncryption::Padding::ISO); + + auto decoded = + encryption.removePadding(encryption.decode(encoded, hash_key)); + auto key_data = QByteArray::fromBase64(decoded); + if (!key_data.startsWith(PGP_PUBLIC_KEY_BEGIN) && + !key_data.startsWith(PGP_PRIVATE_KEY_BEGIN)) { + return -1; + } + + auto import_info_ptr = + GpgKeyImportExporter::GetInstance().ImportKey(GFBuffer(key_data)); + if (import_info_ptr == nullptr) return GPG_ERR_NO_DATA; + + auto import_info = *import_info_ptr; + data_object->Swap({import_info}); + return 0; + }, + cb, "import_key_package"); } -std::string KeyPackageOperator::GenerateKeyPackageName() { +auto KeyPackageOperator::GenerateKeyPackageName() -> QString { return generate_key_package_name(); } +/** + * @brief generate key package name + * + * @return QString key package name + */ +auto KeyPackageOperator::generate_key_package_name() -> QString { + return QString("KeyPackage_%1") + .arg(QRandomGenerator::global()->bounded(999, 99999)); +} + } // namespace GpgFrontend diff --git a/src/core/function/KeyPackageOperator.h b/src/core/function/KeyPackageOperator.h index 00b0dbaa..252c7e00 100644 --- a/src/core/function/KeyPackageOperator.h +++ b/src/core/function/KeyPackageOperator.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_KEYPACKAGEOPERATOR_H -#define GPGFRONTEND_KEYPACKAGEOPERATOR_H +#pragma once -#include "core/GpgFrontendCore.h" #include "core/function/gpg/GpgKeyImportExporter.h" +#include "core/typedef/CoreTypedef.h" namespace GpgFrontend { @@ -48,15 +47,15 @@ class GPGFRONTEND_CORE_EXPORT KeyPackageOperator { * @return true if passphrase was generated and saved * @return false if passphrase was not generated and saved */ - static bool GeneratePassphrase(const std::filesystem::path &phrase_path, - std::string &phrase); + static auto GeneratePassphrase(const QString &phrase_path, QString &phrase) + -> bool; /** * @brief generate the name of the key package * - * @return std::string name of the key package + * @return QString name of the key package */ - static std::string GenerateKeyPackageName(); + static auto GenerateKeyPackageName() -> QString; /** * @brief generate key package @@ -69,10 +68,10 @@ class GPGFRONTEND_CORE_EXPORT KeyPackageOperator { * @return true if key package was generated * @return false if key package was not generated */ - static bool GenerateKeyPackage(const std::filesystem::path &key_package_path, - const std::string &key_package_name, - KeyIdArgsListPtr &key_ids, std::string &phrase, - bool secret); + static void GenerateKeyPackage(const QString &key_package_path, + const QString &key_package_name, + const KeyArgsList &keys, QString &phrase, + bool secret, const OperationCallback &cb); /** * @brief import key package @@ -83,25 +82,16 @@ class GPGFRONTEND_CORE_EXPORT KeyPackageOperator { * @return true if key package was imported * @return false if key package was not imported */ - static bool ImportKeyPackage(const std::filesystem::path &key_package_path, - const std::filesystem::path &phrase_path, - GpgFrontend::GpgImportInformation &import_info); + static void ImportKeyPackage(const QString &key_package_path, + const QString &phrase_path, + const OperationCallback &cb); private: /** * @brief generate key package name * - * @return std::string key package name + * @return QString key package name */ - static std::string generate_key_package_name() { - std::random_device rd_; ///< Random device - auto mt_ = std::mt19937(rd_()); ///< Mersenne twister - - std::uniform_int_distribution<int> dist(999, 99999); - auto file_string = boost::format("KeyPackage_%1%") % dist(mt_); - return file_string.str(); - } + static auto generate_key_package_name() -> QString; }; } // namespace GpgFrontend - -#endif // GPGFRONTEND_KEYPACKAGEOPERATOR_H diff --git a/src/core/function/LoggerManager.cpp b/src/core/function/LoggerManager.cpp new file mode 100644 index 00000000..c7088128 --- /dev/null +++ b/src/core/function/LoggerManager.cpp @@ -0,0 +1,155 @@ +/** + * 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 "LoggerManager.h" + +#include <spdlog/async.h> +#include <spdlog/common.h> +#include <spdlog/sinks/rotating_file_sink.h> +#include <spdlog/sinks/stdout_color_sinks.h> + +#include "core/function/GlobalSettingStation.h" + +namespace GpgFrontend { + +std::shared_ptr<spdlog::logger> LoggerManager::default_logger = nullptr; +spdlog::level::level_enum LoggerManager::default_log_level = + spdlog::level::debug; + +LoggerManager::LoggerManager(int channel) + : SingletonFunctionObject<LoggerManager>(channel) { + spdlog::init_thread_pool(1024, 2); + spdlog::flush_every(std::chrono::seconds(5)); +} + +LoggerManager::~LoggerManager() { +#ifdef WINDOWS + // Under VisualStudio, this must be called before main finishes to workaround + // a known VS issue + spdlog::drop_all(); + spdlog::shutdown(); +#endif + + if (default_logger) default_logger = nullptr; +} + +auto LoggerManager::GetLogger(const QString& id) + -> std::shared_ptr<spdlog::logger> { + auto m_it = logger_map_.find(id); + if (m_it == logger_map_.end()) return GetDefaultLogger(); + return m_it->second; +} + +auto LoggerManager::RegisterAsyncLogger(const QString& id, + spdlog::level::level_enum level) + -> std::shared_ptr<spdlog::logger> { + // get the log directory + auto log_file_path = + GlobalSettingStation::GetInstance().GetLogDir() + "/" + id + ".log"; + + // sinks + std::vector<spdlog::sink_ptr> sinks; + sinks.push_back(GpgFrontend::SecureCreateSharedObject< + spdlog::sinks::stderr_color_sink_mt>()); + sinks.push_back(GpgFrontend::SecureCreateSharedObject< + spdlog::sinks::rotating_file_sink_mt>( + log_file_path.toUtf8().constData(), 1048576 * 32, 8)); + + // logger + auto logger = GpgFrontend::SecureCreateSharedObject<spdlog::async_logger>( + id.toStdString(), begin(sinks), end(sinks), spdlog::thread_pool()); + logger->set_pattern( + "[%H:%M:%S.%e] [T:%t] [%=6n] %^[%=8l]%$ [%s:%#] [%!] -> %v (+%ius)"); + + // set the level of logger + logger->set_level(level); + + // flush policy +#ifdef DEBUG + logger->flush_on(spdlog::level::trace); +#else + logger->flush_on(spdlog::level::err); +#endif + + logger_map_[id] = logger; + return logger; +} + +auto LoggerManager::RegisterSyncLogger(const QString& id, + spdlog::level::level_enum level) + -> std::shared_ptr<spdlog::logger> { + // get the log directory + auto log_file_path = + GlobalSettingStation::GetInstance().GetLogDir() + "/" + id + ".log"; + + // sinks + std::vector<spdlog::sink_ptr> sinks; + sinks.push_back(GpgFrontend::SecureCreateSharedObject< + spdlog::sinks::stderr_color_sink_mt>()); + sinks.push_back(GpgFrontend::SecureCreateSharedObject< + spdlog::sinks::rotating_file_sink_mt>( + log_file_path.toUtf8().constData(), 1048576 * 32, 8)); + + // logger + auto logger = GpgFrontend::SecureCreateSharedObject<spdlog::logger>( + id.toStdString(), begin(sinks), end(sinks)); + logger->set_pattern( + "[%H:%M:%S.%e] [T:%t] [%=6n] %^[%=8l]%$ [%s:%#] [%!] -> %v (+%ius)"); + + // set the level of logger + logger->set_level(level); + + logger_map_[id] = logger; + return logger; +} + +auto LoggerManager::GetDefaultLogger() -> std::shared_ptr<spdlog::logger> { + if (default_logger == nullptr) { + // sinks + std::vector<spdlog::sink_ptr> sinks; + sinks.push_back(GpgFrontend::SecureCreateSharedObject< + spdlog::sinks::stderr_color_sink_mt>()); + + // logger + auto logger = GpgFrontend::SecureCreateSharedObject<spdlog::logger>( + "default", begin(sinks), end(sinks)); + logger->set_pattern( + "[%H:%M:%S.%e] [T:%t] [%=6n] %^[%=8l]%$ [%s:%#] [%!] -> %v (+%ius)"); + + // set the level of logger + logger->set_level(default_log_level); + spdlog::set_default_logger(logger); + default_logger = logger; + } + return default_logger; +} + +void LoggerManager::SetDefaultLogLevel(spdlog::level::level_enum level) { + default_log_level = level; +} +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/function/LoggerManager.h b/src/core/function/LoggerManager.h new file mode 100644 index 00000000..78fecc3c --- /dev/null +++ b/src/core/function/LoggerManager.h @@ -0,0 +1,65 @@ +/** + * 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/basic/GpgFunctionObject.h" + +namespace spdlog { +class logger; +} + +namespace GpgFrontend { + +class GPGFRONTEND_CORE_EXPORT LoggerManager + : public SingletonFunctionObject<LoggerManager> { + public: + explicit LoggerManager(int channel); + + ~LoggerManager() override; + + auto RegisterAsyncLogger(const QString& id, spdlog::level::level_enum) + -> std::shared_ptr<spdlog::logger>; + + auto RegisterSyncLogger(const QString& id, spdlog::level::level_enum) + -> std::shared_ptr<spdlog::logger>; + + auto GetLogger(const QString& id) -> std::shared_ptr<spdlog::logger>; + + static auto GetDefaultLogger() -> std::shared_ptr<spdlog::logger>; + + static void SetDefaultLogLevel(spdlog::level::level_enum); + + private: + static spdlog::level::level_enum default_log_level; + static std::shared_ptr<spdlog::logger> default_logger; + + std::map<QString, std::shared_ptr<spdlog::logger>> logger_map_; +}; + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/function/PassphraseGenerator.cpp b/src/core/function/PassphraseGenerator.cpp index de963fa1..b7f1e877 100644 --- a/src/core/function/PassphraseGenerator.cpp +++ b/src/core/function/PassphraseGenerator.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,10 +20,30 @@ * 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 "PassphraseGenerator.h" + +namespace GpgFrontend { + +auto PassphraseGenerator::Generate(int len) -> QString { + auto file_string = QString("KeyPackage_%1") + .arg(QRandomGenerator::global()->bounded(999, 99999)); + static const char kAlphanum[] = + "0123456789" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz"; + QString tmp_str; + tmp_str.reserve(len); + + for (int i = 0; i < len; ++i) { + tmp_str += kAlphanum[QRandomGenerator::global()->bounded( + static_cast<quint32>(sizeof(kAlphanum)))]; + } + return tmp_str; +} +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/function/PassphraseGenerator.h b/src/core/function/PassphraseGenerator.h index a61356fe..2e5925b6 100644 --- a/src/core/function/PassphraseGenerator.h +++ b/src/core/function/PassphraseGenerator.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,17 +20,15 @@ * 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_PASSPHRASEGENERATOR_H -#define GPGFRONTEND_PASSPHRASEGENERATOR_H +#pragma once -#include "core/GpgFrontendCore.h" -#include "core/GpgFunctionObject.h" +#include "core/function/basic/GpgFunctionObject.h" namespace GpgFrontend { @@ -55,29 +53,13 @@ class GPGFRONTEND_CORE_EXPORT PassphraseGenerator * @brief generate passphrase * * @param len length of the passphrase - * @return std::string passphrase + * @return QString passphrase */ - std::string Generate(int len) { - std::uniform_int_distribution<int> dist(999, 99999); - - auto file_string = boost::format("KeyPackage_%1%") % dist(mt_); - static const char alphanum[] = - "0123456789" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz"; - std::string tmp_str; - tmp_str.reserve(len); - - for (int i = 0; i < len; ++i) { - tmp_str += alphanum[dist(mt_) % (sizeof(alphanum) - 1)]; - } - return tmp_str; - } + auto Generate(int len) -> QString; + private: std::random_device rd_; ///< Random device std::mt19937 mt_ = std::mt19937(rd_()); ///< Mersenne twister }; } // namespace GpgFrontend - -#endif // GPGFRONTEND_PASSPHRASEGENERATOR_H diff --git a/src/core/function/SecureMemoryAllocator.cpp b/src/core/function/SecureMemoryAllocator.cpp new file mode 100644 index 00000000..692c36c5 --- /dev/null +++ b/src/core/function/SecureMemoryAllocator.cpp @@ -0,0 +1,63 @@ +/** + * 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 "SecureMemoryAllocator.h" + +#ifndef MACOS +#include <mimalloc.h> +#endif + +namespace GpgFrontend { + +auto SecureMemoryAllocator::Allocate(std::size_t size) -> void* { +#ifndef MACOS + auto* addr = mi_malloc(size); +#else + auto* addr = malloc(size); +#endif + return addr; +} + +auto SecureMemoryAllocator::Reallocate(void* ptr, std::size_t size) -> void* { +#ifndef MACOS + auto* addr = mi_realloc(ptr, size); +#else + auto* addr = realloc(ptr, size); +#endif + return addr; +} + +void SecureMemoryAllocator::Deallocate(void* p) { +#ifndef MACOS + mi_free(p); +#else + free(p); +#endif +} + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/function/SecureMemoryAllocator.h b/src/core/function/SecureMemoryAllocator.h new file mode 100644 index 00000000..e9f1c1c3 --- /dev/null +++ b/src/core/function/SecureMemoryAllocator.h @@ -0,0 +1,60 @@ +/** + * 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 <cstdint> +#include <memory> + +#include "core/utils/LogUtils.h" + +namespace GpgFrontend { + +class GPGFRONTEND_CORE_EXPORT SecureMemoryAllocator { + public: + static auto Allocate(std::size_t) -> void *; + + static auto Reallocate(void *, std::size_t) -> void *; + + static void Deallocate(void *); +}; + +template <typename T> +struct SecureObjectDeleter { + void operator()(T *ptr) { + if (ptr) { + ptr->~T(); + SecureMemoryAllocator::Deallocate(ptr); + } + } +}; + +template <typename T> +using SecureUniquePtr = std::unique_ptr<T, SecureObjectDeleter<T>>; + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/function/basic/ChannelObject.cpp b/src/core/function/basic/ChannelObject.cpp new file mode 100644 index 00000000..18449ddb --- /dev/null +++ b/src/core/function/basic/ChannelObject.cpp @@ -0,0 +1,59 @@ +/** + * 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 "ChannelObject.h" + +#include <iostream> + +namespace GpgFrontend { + +ChannelObject::ChannelObject() noexcept = default; + +ChannelObject::ChannelObject(int channel, QString type) + : channel_(channel), type_(std::move(type)) {} + +#ifdef DEBUG +ChannelObject::~ChannelObject() noexcept { + // using iostream instead of spdlog bacause at this time spdlog may have + // already been destroyed. + QTextStream(stdout) << "releasing channel object: " << this->type_ + << Qt::endl; +} +#else +ChannelObject::~ChannelObject() noexcept = default; +#endif + +void ChannelObject::SetChannel(int channel) { this->channel_ = channel; } + +auto ChannelObject::GetChannel() const -> int { return channel_; } + +auto ChannelObject::GetDefaultChannel() -> int { + return kGpgFrontendDefaultChannel; +} + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/function/basic/ChannelObject.h b/src/core/function/basic/ChannelObject.h new file mode 100644 index 00000000..27be55c4 --- /dev/null +++ b/src/core/function/basic/ChannelObject.h @@ -0,0 +1,98 @@ +/** + * 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/GpgConstants.h" +#include "core/function/SecureMemoryAllocator.h" +namespace GpgFrontend { + +/** + * @brief object which in channel system is called "channel" + * + */ +class GPGFRONTEND_CORE_EXPORT ChannelObject { + public: + /** + * @brief Construct a new Default Channel Object object + * + */ + ChannelObject() noexcept; + + /** + * @brief Destroy the Channel Object object + * + */ + virtual ~ChannelObject() noexcept; + + /** + * @brief Construct a new Channel Object object + * + * @param channel + */ + explicit ChannelObject(int channel, QString type); + + /** + * @brief Get the Default Channel object + * + * @return int + */ + static auto GetDefaultChannel() -> int; + + /** + * @brief Get the Channel object + * + * @return int + */ + [[nodiscard]] auto GetChannel() const -> int; + + /** + * @brief Set the Channel object + * + * @param channel + */ + void SetChannel(int channel); + + private: + int channel_ = kGpgFrontendDefaultChannel; ///< The channel id + QString type_; +}; + +template <typename Derived> +auto ConvertToChannelObjectPtr( + std::unique_ptr<Derived, SecureObjectDeleter<Derived>> derivedPtr) + -> std::unique_ptr<ChannelObject, SecureObjectDeleter<ChannelObject>> { + static_assert(std::is_base_of_v<ChannelObject, Derived>, + "Derived must be a subclass of ChannelObject"); + + ChannelObject* base_ptr = derivedPtr.release(); + return std::unique_ptr<ChannelObject, SecureObjectDeleter<ChannelObject>>( + base_ptr); +} + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/function/basic/GpgFunctionObject.cpp b/src/core/function/basic/GpgFunctionObject.cpp new file mode 100644 index 00000000..e9e444f1 --- /dev/null +++ b/src/core/function/basic/GpgFunctionObject.cpp @@ -0,0 +1,105 @@ +/** + * 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 "GpgFunctionObject.h" + +#include <map> +#include <mutex> +#include <typeinfo> + +#include "core/function/SecureMemoryAllocator.h" +#include "core/function/basic/ChannelObject.h" + +struct FunctionObjectTypeLockInfo { + std::map<int, std::mutex> channel_lock_map; + std::mutex type_lock; +}; + +std::mutex g_function_object_mutex_map_lock; +std::map<size_t, FunctionObjectTypeLockInfo> g_function_object_mutex_map; + +namespace GpgFrontend { +auto GetGlobalFunctionObjectChannelLock(const std::type_info& type, int channel) + -> std::mutex& { + std::lock_guard<std::mutex> lock_guard(g_function_object_mutex_map_lock); + auto& channel_map = g_function_object_mutex_map[type.hash_code()]; + return channel_map.channel_lock_map[channel]; +} + +auto GetGlobalFunctionObjectTypeLock(const std::type_info& type) + -> std::mutex& { + std::lock_guard<std::mutex> lock_guard(g_function_object_mutex_map_lock); + auto& channel_map = g_function_object_mutex_map[type.hash_code()]; + return channel_map.type_lock; +} + +/** + * @brief Get the Instance object + * + * @param channel + * @return T& + */ +auto GetChannelObjectInstance(const std::type_info& type, int channel) + -> ChannelObject* { + GF_DEFAULT_LOG_TRACE("try to get instance of type: {} at channel: {}", + type.name(), channel); + + // lock this channel + std::lock_guard<std::mutex> guard( + GetGlobalFunctionObjectChannelLock(type, channel)); + + auto* p_storage = + SingletonStorageCollection::GetInstance(false)->GetSingletonStorage(type); + GF_DEFAULT_LOG_TRACE("get singleton storage result, p_storage: {}", + static_cast<void*>(p_storage)); + + auto* p_pbj = + static_cast<ChannelObject*>(p_storage->FindObjectInChannel(channel)); + GF_DEFAULT_LOG_TRACE("find channel object result, channel {}, p_pbj: {}", + channel, static_cast<void*>(p_pbj)); + + return p_pbj; +} + +auto CreateChannelObjectInstance(const std::type_info& type, int channel, + SecureUniquePtr<ChannelObject> channel_object) + -> ChannelObject* { + // lock this channel + std::lock_guard<std::mutex> guard( + GetGlobalFunctionObjectChannelLock(type, channel)); + + auto* p_storage = + SingletonStorageCollection::GetInstance(false)->GetSingletonStorage(type); + GF_DEFAULT_LOG_TRACE("create channel object, channel {}, type: {}", channel, + type.name()); + + // do create object of this channel + return p_storage->SetObjectInChannel(channel, std::move(channel_object)); +} + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/function/basic/GpgFunctionObject.h b/src/core/function/basic/GpgFunctionObject.h new file mode 100644 index 00000000..1ea352b6 --- /dev/null +++ b/src/core/function/basic/GpgFunctionObject.h @@ -0,0 +1,194 @@ +/** + * 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 <mutex> +#include <stdexcept> + +#include "core/GpgFrontendCoreExport.h" +#include "core/function/basic/ChannelObject.h" +#include "core/function/basic/SingletonStorage.h" +#include "core/function/basic/SingletonStorageCollection.h" +#include "core/utils/MemoryUtils.h" + +namespace GpgFrontend { + +auto GPGFRONTEND_CORE_EXPORT GetChannelObjectInstance( + const std::type_info& type, int channel) -> ChannelObject*; + +auto GPGFRONTEND_CORE_EXPORT CreateChannelObjectInstance( + const std::type_info& type, int channel, + SecureUniquePtr<ChannelObject> channel_object) -> ChannelObject*; + +auto GPGFRONTEND_CORE_EXPORT +GetGlobalFunctionObjectTypeLock(const std::type_info& type) -> std::mutex&; + +/** + * @brief + * + * @tparam T + */ +template <typename T> +class SingletonFunctionObject : public ChannelObject { + public: + /** + * @brief prohibit copy + * + */ + SingletonFunctionObject(const SingletonFunctionObject<T>&) = delete; + + /** + * @brief prohibit copy + * + * @return SingletonFunctionObject& + */ + auto operator=(const SingletonFunctionObject<T>&) + -> SingletonFunctionObject& = delete; + + /** + * @brief Get the Instance object + * + * @param channel + * @return T& + */ + static auto GetInstance(int channel = GpgFrontend::kGpgFrontendDefaultChannel) + -> T& { + static_assert(std::is_base_of_v<SingletonFunctionObject<T>, T>, + "T not derived from SingletonFunctionObject<T>"); + + const auto& type = typeid(T); + std::lock_guard<std::mutex> guard(GetGlobalFunctionObjectTypeLock(type)); + auto* channel_object = GetChannelObjectInstance(type, channel); + if (channel_object == nullptr) { + channel_object = CreateChannelObjectInstance( + type, channel, + ConvertToChannelObjectPtr(SecureCreateUniqueObject<T>(channel))); + } + return *static_cast<T*>(channel_object); + } + + /** + * @brief Create a Instance object + * + * @param channel + * @param factory + * @return T& + */ + static auto CreateInstance( + int channel, const std::function<ChannelObjectPtr(void)>& factory) -> T& { + static_assert(std::is_base_of_v<SingletonFunctionObject<T>, T>, + "T not derived from SingletonFunctionObject<T>"); + + const auto& type = typeid(T); + std::lock_guard<std::mutex> guard(GetGlobalFunctionObjectTypeLock(type)); + return *static_cast<T*>( + CreateChannelObjectInstance(type, channel, factory())); + } + + /** + * @brief + * + * @param channel + * @return T& + */ + static void ReleaseChannel(int channel) { + SingletonStorageCollection::GetInstance(false) + ->GetSingletonStorage(typeid(T)) + ->ReleaseChannel(channel); + } + + /** + * @brief Get the Default Channel object + * + * @return int + */ + static auto GetDefaultChannel() -> int { + return ChannelObject::GetDefaultChannel(); + } + + /** + * @brief Get the Channel object + * + * @return int + */ + [[nodiscard]] auto GetChannel() const -> int { + return ChannelObject::GetChannel(); + } + + /** + * @brief Get all the channel ids + * + * @return std::vector<int> + */ + static auto GetAllChannelId() -> std::vector<int> { + return SingletonStorageCollection::GetInstance(false) + ->GetSingletonStorage(typeid(T)) + ->GetAllChannelId(); + } + + /** + * @brief Construct a new Singleton Function Object object + * + */ + SingletonFunctionObject(T&&) = delete; + + /** + * @brief Construct a new Singleton Function Object object + * + */ + SingletonFunctionObject(const T&) = delete; + + /** + * @brief + * + */ + void operator=(const T&) = delete; + + protected: + /** + * @brief Construct a new Singleton Function Object object + * + */ + SingletonFunctionObject() = default; + + /** + * @brief Construct a new Singleton Function Object object + * + * @param channel + */ + explicit SingletonFunctionObject(int channel) + : ChannelObject(channel, typeid(T).name()) {} + + /** + * @brief Destroy the Singleton Function Object object + * + */ + virtual ~SingletonFunctionObject() = default; +}; +} // namespace GpgFrontend diff --git a/src/core/function/basic/SingletonStorage.cpp b/src/core/function/basic/SingletonStorage.cpp new file mode 100644 index 00000000..eab71e0f --- /dev/null +++ b/src/core/function/basic/SingletonStorage.cpp @@ -0,0 +1,133 @@ +/** + * 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 "SingletonStorage.h" + +#include <shared_mutex> + +#include "core/function/basic/ChannelObject.h" +#include "utils/MemoryUtils.h" + +namespace GpgFrontend { + +class SingletonStorage::Impl { + public: + void ReleaseChannel(int channel) { + decltype(instances_map_.end()) ins_it; + { + std::shared_lock<std::shared_mutex> lock(instances_mutex_); + ins_it = instances_map_.find(channel); + } + if (ins_it != instances_map_.end()) instances_map_.erase(ins_it); + } + + auto FindObjectInChannel(int channel) -> GpgFrontend::ChannelObject* { + // read instances_map_ + decltype(instances_map_.end()) ins_it; + { + std::shared_lock<std::shared_mutex> lock(instances_mutex_); + ins_it = instances_map_.find(channel); + if (ins_it == instances_map_.end()) { + GF_DEFAULT_LOG_TRACE("cannot find channel object, channel: {}", + channel); + return nullptr; + } + return ins_it->second.get(); + } + } + + auto GetAllChannelId() -> std::vector<int> { + std::vector<int> channels; + channels.reserve(instances_map_.size()); + for (const auto& [key, value] : instances_map_) { + channels.push_back(key); + } + return channels; + } + + auto SetObjectInChannel(int channel, ChannelObjectPtr p_obj) + -> GpgFrontend::ChannelObject* { + GF_DEFAULT_LOG_TRACE( + "set channel object, type: {} in channel: {}, address: {}", + typeid(p_obj.get()).name(), channel, static_cast<void*>(p_obj.get())); + + assert(p_obj != nullptr); + if (p_obj == nullptr) { + GF_DEFAULT_LOG_ERROR( + "cannot set a nullptr as a channel obejct of channel: {}", channel); + return nullptr; + } + + p_obj->SetChannel(channel); + auto* raw_obj = p_obj.get(); + + { + GF_DEFAULT_LOG_TRACE( + "register channel object to instances map, " + "channel: {}, address: {}", + channel, static_cast<void*>(p_obj.get())); + std::unique_lock<std::shared_mutex> lock(instances_mutex_); + instances_map_[channel] = std::move(p_obj); + } + + GF_DEFAULT_LOG_TRACE( + "set channel: {} success, current channel object address: {}", channel, + static_cast<void*>(raw_obj)); + return raw_obj; + } + + private: + std::shared_mutex instances_mutex_; ///< mutex for _instances_map + std::map<int, ChannelObjectPtr> + instances_map_; ///< map of singleton instances +}; + +SingletonStorage::SingletonStorage() noexcept + : p_(SecureCreateUniqueObject<Impl>()) {} + +SingletonStorage::~SingletonStorage() = default; + +void SingletonStorage::ReleaseChannel(int channel) { + p_->ReleaseChannel(channel); +} + +auto SingletonStorage::FindObjectInChannel(int channel) + -> GpgFrontend::ChannelObject* { + return p_->FindObjectInChannel(channel); +} + +auto SingletonStorage::GetAllChannelId() -> std::vector<int> { + return p_->GetAllChannelId(); +} + +auto SingletonStorage::SetObjectInChannel(int channel, ChannelObjectPtr p_obj) + -> GpgFrontend::ChannelObject* { + return p_->SetObjectInChannel(channel, std::move(p_obj)); +} + +}; // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/function/basic/SingletonStorage.h b/src/core/function/basic/SingletonStorage.h new file mode 100644 index 00000000..0ef47443 --- /dev/null +++ b/src/core/function/basic/SingletonStorage.h @@ -0,0 +1,90 @@ +/** + * 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" + +namespace GpgFrontend { + +class ChannelObject; + +using ChannelObjectPtr = SecureUniquePtr<ChannelObject>; + +class GPGFRONTEND_CORE_EXPORT SingletonStorage { + public: + /** + * @brief + * + */ + SingletonStorage() noexcept; + + /** + * @brief + * + */ + ~SingletonStorage(); + + /** + * @brief + * + * @param channel + */ + void ReleaseChannel(int channel); + + /** + * @brief + * + * @param channel + * @return T* + */ + auto FindObjectInChannel(int channel) -> ChannelObject*; + + /** + * @brief Get all the channel ids + * + * @return std::vector<int> + */ + auto GetAllChannelId() -> std::vector<int>; + + /** + * @brief Set a new object in channel object + * + * @param channel + * @param p_obj + * @return T* + */ + auto SetObjectInChannel(int channel, ChannelObjectPtr p_obj) + -> ChannelObject*; + + private: + class Impl; + SecureUniquePtr<Impl> p_; +}; + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/function/basic/SingletonStorageCollection.cpp b/src/core/function/basic/SingletonStorageCollection.cpp new file mode 100644 index 00000000..c22b5242 --- /dev/null +++ b/src/core/function/basic/SingletonStorageCollection.cpp @@ -0,0 +1,124 @@ +/** + * 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 "SingletonStorageCollection.h" + +#include <memory> +#include <shared_mutex> + +#include "core/function/SecureMemoryAllocator.h" +#include "core/function/basic/SingletonStorage.h" +#include "core/utils/MemoryUtils.h" + +namespace GpgFrontend { + +SecureUniquePtr<SingletonStorageCollection> global_instance = nullptr; + +class SingletonStorageCollection::Impl { + public: + /** + * @brief Get the Instance object + * + * @return SingletonStorageCollection* + */ + static auto GetInstance(bool force_refresh) -> SingletonStorageCollection* { + if (force_refresh || global_instance == nullptr) { + global_instance = SecureCreateUniqueObject<SingletonStorageCollection>(); + GF_DEFAULT_LOG_TRACE( + "a new global singleton storage collection created, address: {}", + static_cast<void*>(global_instance.get())); + } + return global_instance.get(); + } + + /** + * @brief Get the Instance object + * + * @return SingletonStorageCollection* + */ + static void Destroy() { global_instance = nullptr; } + + /** + * @brief Get the Singleton Storage object + * + * @param singleton_function_object + * @return SingletonStorage* + */ + auto GetSingletonStorage(const std::type_info& type_id) -> SingletonStorage* { + const auto hash = type_id.hash_code(); + + while (true) { + decltype(storages_map_.end()) ins_it; + { + std::shared_lock<std::shared_mutex> lock(storages_mutex_); + ins_it = storages_map_.find(hash); + } + if (ins_it == storages_map_.end()) { + auto storage = SecureCreateUniqueObject<SingletonStorage>(); + GF_DEFAULT_LOG_TRACE( + "hash: {} created, singleton storage address: {} type_name: {}", + hash, static_cast<void*>(storage.get()), type_id.name()); + + { + std::unique_lock<std::shared_mutex> lock(storages_mutex_); + storages_map_.insert({hash, std::move(storage)}); + } + continue; + } + return ins_it->second.get(); + } + } + + private: + std::shared_mutex storages_mutex_; ///< mutex for storages_map_ + std::map<size_t, SingletonStoragePtr> storages_map_; +}; + +SingletonStorageCollection::SingletonStorageCollection() noexcept + : p_(SecureCreateUniqueObject<Impl>()) {} + +SingletonStorageCollection::~SingletonStorageCollection() = default; + +auto GpgFrontend::SingletonStorageCollection::GetInstance(bool force_refresh) + -> GpgFrontend::SingletonStorageCollection* { + return Impl::GetInstance(force_refresh); +} + +void SingletonStorageCollection::Destroy() { + GF_DEFAULT_LOG_TRACE( + "global singleton storage collection is about to destroy, address: {}", + static_cast<void*>(global_instance.get())); + return SingletonStorageCollection::Impl::Destroy(); +} + +auto SingletonStorageCollection::GetSingletonStorage( + const std::type_info& type_id) -> GpgFrontend::SingletonStorage* { + return p_->GetSingletonStorage(type_id); +} + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/function/basic/SingletonStorageCollection.h b/src/core/function/basic/SingletonStorageCollection.h new file mode 100644 index 00000000..38ced83b --- /dev/null +++ b/src/core/function/basic/SingletonStorageCollection.h @@ -0,0 +1,79 @@ +/** + * 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" + +namespace GpgFrontend { +class SingletonStorage; + +using SingletonStoragePtr = + std::unique_ptr<SingletonStorage, SecureObjectDeleter<SingletonStorage>>; + +class GPGFRONTEND_CORE_EXPORT SingletonStorageCollection { + public: + /** + * @brief + * + */ + SingletonStorageCollection() noexcept; + + /** + * @brief + * + */ + ~SingletonStorageCollection(); + + /** + * @brief Get the Instance object + * + * @return SingletonStorageCollection* + */ + static auto GetInstance(bool force_refresh) -> SingletonStorageCollection*; + + /** + * @brief + * + */ + static void Destroy(); + + /** + * @brief Get the Singleton Storage object + * + * @param singleton_function_object + * @return SingletonStorage* + */ + auto GetSingletonStorage(const std::type_info&) -> SingletonStorage*; + + private: + class Impl; + SecureUniquePtr<Impl> p_; +}; + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/function/gpg/GpgAdvancedOperator.cpp b/src/core/function/gpg/GpgAdvancedOperator.cpp index 2a3bba42..3fc831ed 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,182 @@ #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, QStringList{"--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, QStringList{"--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, QStringList{"--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, QStringList{"--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, QStringList{"--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, QStringList{"--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, QStringList{"--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..8b62aad0 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,389 @@ #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) +namespace 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]; +void GpgBasicOperator::Encrypt(const KeyArgsList& keys, + const GFBuffer& in_buffer, bool ascii, + const GpgOperationCallback& cb) { + RunGpgOperaAsync( + [=](const DataObjectPtr& data_object) -> GpgError { + if (keys.empty()) return GPG_ERR_CANCELED; - int index = 0; - for (const auto& key : *keys) recipients[index++] = gpgme_key_t(key); + std::vector<gpgme_key_t> recipients(keys.begin(), keys.end()); - // Last entry data_in array has to be nullptr - recipients[keys->size()] = nullptr; + // Last entry data_in array has to be nullptr + recipients.emplace_back(nullptr); - GpgData data_in(in_buffer.data(), in_buffer.size()), data_out; + GpgData data_in(in_buffer); + GpgData data_out; - gpgme_error_t err = check_gpg_error(gpgme_op_encrypt( - ctx_, recipients, GPGME_ENCRYPT_ALWAYS_TRUST, data_in, data_out)); + 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()}); - auto temp_data_out = data_out.Read2Buffer(); - std::swap(temp_data_out, out_buffer); + return err; + }, + cb, "gpgme_op_encrypt", "2.1.0"); +} - auto temp_result = _new_result(gpgme_op_encrypt_result(ctx_)); - std::swap(result, temp_result); +auto GpgBasicOperator::EncryptSync(const KeyArgsList& keys, + const GFBuffer& in_buffer, bool ascii) + -> std::tuple<GpgError, DataObjectPtr> { + return RunGpgOperaSync( + [=](const DataObjectPtr& data_object) -> GpgError { + if (keys.empty()) return GPG_ERR_CANCELED; - return err; -} + std::vector<gpgme_key_t> recipients(keys.begin(), keys.end()); -GpgFrontend::GpgError GpgFrontend::GpgBasicOperator::Decrypt( - BypeArrayRef in_buffer, GpgFrontend::ByteArrayPtr& out_buffer, - GpgFrontend::GpgDecrResult& result) { - gpgme_error_t err; + // Last entry data_in array has to be nullptr + recipients.emplace_back(nullptr); - GpgData data_in(in_buffer.data(), in_buffer.size()), data_out; - err = check_gpg_error(gpgme_op_decrypt(ctx_, data_in, data_out)); + GpgData data_in(in_buffer); + GpgData data_out; - auto temp_data_out = data_out.Read2Buffer(); - std::swap(temp_data_out, out_buffer); + 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()}); - auto temp_result = _new_result(gpgme_op_decrypt_result(ctx_)); - std::swap(result, temp_result); + return err; + }, + "gpgme_op_encrypt", "2.1.0"); +} - return err; +void GpgBasicOperator::EncryptSymmetric(const 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"); } -GpgFrontend::GpgError GpgFrontend::GpgBasicOperator::Verify( - BypeArrayRef& in_buffer, ByteArrayPtr& sig_buffer, - GpgVerifyResult& result) const { - gpgme_error_t err; +auto GpgBasicOperator::EncryptSymmetricSync(const GFBuffer& in_buffer, + bool ascii) + -> std::tuple<GpgError, DataObjectPtr> { + return RunGpgOperaSync( + [=](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; + }, + "gpgme_op_encrypt_symmetric", "2.1.0"); +} - GpgData data_in(in_buffer.data(), in_buffer.size()); - GpgData data_out; +void GpgBasicOperator::Decrypt(const 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"); +} - 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 GpgBasicOperator::DecryptSync(const GFBuffer& in_buffer) + -> std::tuple<GpgError, DataObjectPtr> { + return RunGpgOperaSync( + [=](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; + }, + "gpgme_op_decrypt", "2.1.0"); +} - auto temp_result = _new_result(gpgme_op_verify_result(ctx_)); - std::swap(result, temp_result); +void GpgBasicOperator::Verify(const GFBuffer& in_buffer, + const 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"); +} - return err; +auto GpgBasicOperator::VerifySync(const GFBuffer& in_buffer, + const GFBuffer& sig_buffer) + -> std::tuple<GpgError, DataObjectPtr> { + return RunGpgOperaSync( + [=](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; + }, + "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; +void GpgBasicOperator::Sign(const KeyArgsList& signers, + const GFBuffer& in_buffer, GpgSignMode mode, + bool ascii, const GpgOperationCallback& cb) { + RunGpgOperaAsync( + [=](const DataObjectPtr& data_object) -> GpgError { + if (signers.empty()) return GPG_ERR_CANCELED; - // Set Singers of this opera - SetSigners(*signers); + GpgError err; - GpgData data_in(in_buffer.data(), in_buffer.size()), data_out; + // Set Singers of this opera + SetSigners(signers, ascii); - err = check_gpg_error(gpgme_op_sign(ctx_, data_in, data_out, mode)); + GpgData data_in(in_buffer); + GpgData data_out; - auto temp_data_out = data_out.Read2Buffer(); - std::swap(temp_data_out, out_buffer); + auto* ctx = ascii ? ctx_.DefaultContext() : ctx_.BinaryContext(); + err = CheckGpgError(gpgme_op_sign(ctx, data_in, data_out, mode)); - auto temp_result = _new_result(gpgme_op_sign_result(ctx_)); + data_object->Swap({GpgSignResult(gpgme_op_sign_result(ctx)), + data_out.Read2GFBuffer()}); + return err; + }, + cb, "gpgme_op_sign", "2.1.0"); +} - std::swap(result, temp_result); +auto GpgBasicOperator::SignSync(const KeyArgsList& signers, + const GFBuffer& in_buffer, GpgSignMode mode, + bool ascii) + -> std::tuple<GpgError, DataObjectPtr> { + return RunGpgOperaSync( + [=](const DataObjectPtr& data_object) -> GpgError { + if (signers.empty()) return GPG_ERR_CANCELED; - return err; + GpgError err; + + // Set Singers of this opera + SetSigners(signers, ascii); + + GpgData data_in(in_buffer); + GpgData data_out; + + auto* ctx = ascii ? ctx_.DefaultContext() : ctx_.BinaryContext(); + err = CheckGpgError(gpgme_op_sign(ctx, data_in, data_out, mode)); + + data_object->Swap({GpgSignResult(gpgme_op_sign_result(ctx)), + data_out.Read2GFBuffer()}); + return err; + }, + "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; +void GpgBasicOperator::DecryptVerify(const GFBuffer& in_buffer, + const GpgOperationCallback& cb) { + RunGpgOperaAsync( + [=](const DataObjectPtr& data_object) -> GpgError { + GpgError err; - GpgData data_in(in_buffer.data(), in_buffer.size()), data_out; + GpgData data_in(in_buffer); + GpgData data_out; + + 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())), + data_out.Read2GFBuffer()}); + + return err; + }, + cb, "gpgme_op_decrypt_verify", "2.1.0"); +} - err = check_gpg_error(gpgme_op_decrypt_verify(ctx_, data_in, data_out)); +auto GpgBasicOperator::DecryptVerifySync(const GFBuffer& in_buffer) + -> std::tuple<GpgError, DataObjectPtr> { + return RunGpgOperaSync( + [=](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; + }, + "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(const KeyArgsList& keys, + const KeyArgsList& signers, + const 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 GpgBasicOperator::EncryptSignSync(const KeyArgsList& keys, + const KeyArgsList& signers, + const GFBuffer& in_buffer, bool ascii) + -> std::tuple<GpgError, DataObjectPtr> { + return RunGpgOperaSync( + [=](const DataObjectPtr& data_object) -> GpgError { + if (keys.empty() || signers.empty()) return GPG_ERR_CANCELED; + + 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); - 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); + SetSigners(signers, ascii); - return err; + GpgData data_in(in_buffer); + GpgData 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)); + + data_object->Swap({GpgEncryptResult(gpgme_op_encrypt_result(ctx)), + GpgSignResult(gpgme_op_sign_result(ctx)), + data_out.Read2GFBuffer()}); + return err; + }, + "gpgme_op_encrypt_sign", "2.1.0"); } -void GpgFrontend::GpgBasicOperator::SetSigners(KeyArgsList& signers) { - gpgme_signers_clear(ctx_); +void GpgBasicOperator::SetSigners(const KeyArgsList& signers, bool ascii) { + auto* ctx = ascii ? ctx_.DefaultContext() : ctx_.BinaryContext(); + + 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; -} +} // namespace GpgFrontend diff --git a/src/core/function/gpg/GpgBasicOperator.h b/src/core/function/gpg/GpgBasicOperator.h index 696ac9dc..37defb45 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,18 @@ 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 + */ + void Encrypt(const KeyArgsList&, const GFBuffer&, bool, + const GpgOperationCallback&); + + /** + * @brief * - * @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); + auto EncryptSync(const KeyArgsList&, const GFBuffer&, bool) + -> std::tuple<GpgError, DataObjectPtr>; /** * @brief Call the interface provided by GPGME to symmetrical encryption @@ -72,10 +72,21 @@ 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 + */ + void EncryptSymmetric(const GFBuffer& in_buffer, bool ascii, + const GpgOperationCallback& cb); + + /** + * @brief + * + * @param in_buffer + * @param ascii + * @param cb + * @return std::tuple<GpgError, DataObjectPtr> */ - gpg_error_t EncryptSymmetric(BypeArrayRef in_buffer, ByteArrayPtr& out_buffer, - GpgEncrResult& result); + auto EncryptSymmetricSync(const GFBuffer& in_buffer, bool ascii) + -> std::tuple<GpgError, DataObjectPtr>; /** * @@ -85,15 +96,25 @@ class GPGFRONTEND_CORE_EXPORT GpgBasicOperator * @param keys List of public keys * @param signers Private key for signatures * @param in_buffer Data for operation - * @param out_buffer Encrypted data - * @param encr_result Encrypted results - * @param sign_result Signature result + * @param ascii ascii mode * @return */ - gpgme_error_t EncryptSign(KeyListPtr keys, KeyListPtr signers, - BypeArrayRef in_buffer, ByteArrayPtr& out_buffer, - GpgEncrResult& encr_result, - GpgSignResult& sign_result); + void EncryptSign(const KeyArgsList& keys, const KeyArgsList& signers, + const GFBuffer& in_buffer, bool ascii, + const GpgOperationCallback& cb); + + /** + * @brief + * + * @param keys + * @param signers + * @param in_buffer + * @param ascii + * @param cb + */ + auto EncryptSignSync(const KeyArgsList& keys, const KeyArgsList& signers, + const GFBuffer& in_buffer, bool ascii) + -> std::tuple<GpgError, DataObjectPtr>; /** * @brief Call the interface provided by gpgme for decryption operation @@ -103,8 +124,15 @@ 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(const GFBuffer& in_buffer, const GpgOperationCallback& cb); + + /** + * @brief + * + * @param in_buffer + */ + auto DecryptSync(const GFBuffer& in_buffer) + -> std::tuple<GpgError, DataObjectPtr>; /** * @brief Call the interface provided by gpgme to perform decryption and @@ -116,9 +144,15 @@ 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(const GFBuffer& in_buffer, const GpgOperationCallback& cb); + + /** + * @brief + * + * @param in_buffer + */ + auto DecryptVerifySync(const GFBuffer& in_buffer) + -> std::tuple<GpgError, DataObjectPtr>; /** * @brief Call the interface provided by gpgme for verification operation @@ -128,8 +162,19 @@ 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(const GFBuffer& in_buffer, const GFBuffer& sig_buffer, + const GpgOperationCallback& cb); + + /** + * @brief + * + * @param in_buffer + * @param sig_buffer + * @param cb + * @return std::tuple<GpgError, DataObjectPtr> + */ + auto VerifySync(const GFBuffer& in_buffer, const GFBuffer& sig_buffer) + -> std::tuple<GpgError, DataObjectPtr>; /** * @brief Call the interface provided by gpgme for signing operation @@ -151,9 +196,22 @@ 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(const KeyArgsList& signers, const GFBuffer& in_buffer, + GpgSignMode mode, bool ascii, const GpgOperationCallback& cb); + + /** + * @brief + * + * @param signers + * @param in_buffer + * @param mode + * @param ascii + * @param cb + * @return std::tuple<GpgError, DataObjectPtr> + */ + auto SignSync(const KeyArgsList& signers, const GFBuffer& in_buffer, + GpgSignMode mode, bool ascii) + -> std::tuple<GpgError, DataObjectPtr>; /** * @brief Set the private key for signatures, this operation is a global @@ -161,19 +219,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..6d24f9bd 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)); +} + +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; - }; +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); + } + } +} - // 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})); +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(); +} - auto *process_task = new GpgFrontend::Thread::Task( - std::move(runner), fmt::format("ExecuteConcurrently/{}", cmd), - data_object, std::move(result_callback), false); +GpgCommandExecutor::ExecuteContext::ExecuteContext( + QString cmd, QStringList 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)) {} - GpgFrontend::Thread::TaskRunnerGetter::GetInstance() - .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_External_Process) - ->PostTask(process_task); -} +} // 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..ac52b295 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 GPGFRONTEND_CORE_EXPORT 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..6523386c --- /dev/null +++ b/src/core/function/gpg/GpgContext.cpp @@ -0,0 +1,339 @@ +/** + * 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 passpahrase_size = pass.size(); + + size_t off = 0; + + do { + res = gpgme_io_write(fd, &pass[off], passpahrase_size - off); + if (res > 0) off += res; + } while (res > 0 && off != passpahrase_size); + + res += gpgme_io_write(fd, "\n", 1); + return res == passpahrase_size + 1 + ? 0 + : gpgme_error_from_errno(GPG_ERR_CANCELED); + } + + 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..94a08c76 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,553 @@ * 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; -} - -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; -} - -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; -} - -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; -} - -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; -} - -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; -} -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::EncryptFile(const KeyArgsList& 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"); } + +auto GpgFileOpera::EncryptFileSync(const KeyArgsList& keys, + const QString& in_path, bool ascii, + const QString& out_path) + -> std::tuple<GpgError, DataObjectPtr> { + return RunGpgOperaSync( + [=](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; + }, + "gpgme_op_encrypt", "2.1.0"); +} + +void GpgFileOpera::EncryptDirectory(const KeyArgsList& 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"); +} + +auto GpgFileOpera::DecryptFileSync(const QString& in_path, + const QString& out_path) + -> std::tuple<GpgError, DataObjectPtr> { + return RunGpgOperaSync( + [=](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; + }, + "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"); +} + +void GpgFileOpera::SignFile(const 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"); +} + +auto GpgFileOpera::SignFileSync(const KeyArgsList& keys, const QString& in_path, + bool ascii, const QString& out_path) + -> std::tuple<GpgError, DataObjectPtr> { + return RunGpgOperaSync( + [=](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; + }, + "gpgme_op_sign", "2.1.0"); +} + +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"); +} + +auto GpgFileOpera::VerifyFileSync(const QString& data_path, + const QString& sign_path) + -> std::tuple<GpgError, DataObjectPtr> { + return RunGpgOperaSync( + [=](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; + }, + "gpgme_op_verify", "2.1.0"); +} + +void GpgFileOpera::EncryptSignFile(const KeyArgsList& keys, + const 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"); +} + +auto GpgFileOpera::EncryptSignFileSync(const KeyArgsList& keys, + const KeyArgsList& signer_keys, + const QString& in_path, bool ascii, + const QString& out_path) + -> std::tuple<GpgError, DataObjectPtr> { + return RunGpgOperaSync( + [=](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; + }, + "gpgme_op_encrypt_sign", "2.1.0"); +} + +void GpgFileOpera::EncryptSignDirectory(const KeyArgsList& keys, + const 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); + }); +} + +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"); +} + +auto GpgFileOpera::DecryptVerifyFileSync(const QString& in_path, + const QString& out_path) + -> std::tuple<GpgError, DataObjectPtr> { + return RunGpgOperaSync( + [=](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; + }, + "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"); +} + +auto GpgFileOpera::EncryptFileSymmetricSync(const QString& in_path, bool ascii, + const QString& out_path) + -> std::tuple<GpgError, DataObjectPtr> { + return RunGpgOperaSync( + [=](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; + }, + "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); + }); +} + +auto GpgFileOpera::EncryptDerectorySymmetricSync(const QString& in_path, + bool ascii, + const QString& out_path) + -> std::tuple<GpgError, DataObjectPtr> { + auto ex = std::make_shared<GFDataExchanger>(kDataExchangerSize); + + ArchiveFileOperator::NewArchive2DataExchanger( + in_path, ex, [=](GFError err, const DataObjectPtr&) { + GF_CORE_LOG_DEBUG("new archive 2 fd operation, err: {}", err); + }); + + return RunGpgOperaSync( + [=](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; + }, + "gpgme_op_encrypt_symmetric", "2.1.0"); +} + +} // 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..d7c2d44c 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,123 @@ * 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(const 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 + * @return std::tuple<GpgError, DataObjectPtr> + */ + auto EncryptFileSync(const KeyArgsList& keys, const QString& in_path, + bool ascii, const QString& out_path) + -> std::tuple<GpgError, DataObjectPtr>; + + /** + * @brief + * + * @param keys + * @param in_path + * @param ascii + * @param out_path + * @param cb + */ + void EncryptDirectory(const 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 + */ + auto EncryptFileSymmetricSync(const QString& in_path, bool ascii, + const QString& out_path) + -> std::tuple<GpgError, DataObjectPtr>; + + /** + * @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 + * + * @param in_path + * @param ascii + * @param out_path + */ + auto EncryptDerectorySymmetricSync(const QString& in_path, bool ascii, + const QString& out_path) + -> std::tuple<GpgError, DataObjectPtr>; /** * @brief @@ -82,37 +146,77 @@ 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 + * @return std::tuple<GpgError, DataObjectPtr> + */ + auto DecryptFileSync(const QString& in_path, const QString& out_path) + -> std::tuple<GpgError, DataObjectPtr>; + + /** + * @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 + */ + void SignFile(const 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 + * @return std::tuple<GpgError, DataObjectPtr> + */ + auto SignFileSync(const KeyArgsList& keys, const QString& in_path, bool ascii, + const QString& out_path) + -> std::tuple<GpgError, DataObjectPtr>; + + /** + * @brief Verify file with public key + * + * @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 SignFile(KeyListPtr keys, const std::string& in_path, - const std::string& out_path, GpgSignResult& result, - int _channel = GPGFRONTEND_DEFAULT_CHANNEL); + void VerifyFile(const QString& data_path, const QString& sign_path, + const GpgOperationCallback& cb); /** * @brief * * @param data_path * @param sign_path - * @param result - * @param _channel - * @return GpgError + * @return std::tuple<GpgError, DataObjectPtr> */ - static GpgError VerifyFile(const std::string& data_path, - const std::string& sign_path, - GpgVerifyResult& result, - int _channel = GPGFRONTEND_DEFAULT_CHANNEL); + auto VerifyFileSync(const QString& data_path, const QString& sign_path) + -> std::tuple<GpgError, DataObjectPtr>; /** * @brief @@ -120,18 +224,44 @@ class GPGFRONTEND_CORE_EXPORT GpgFileOpera * @param keys * @param signer_keys * @param in_path + * @param ascii + * @param out_path + * @param cb + */ + void EncryptSignFile(const KeyArgsList& keys, const 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 encr_res - * @param sign_res - * @param _channel - * @return GpgError */ - 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); + auto EncryptSignFileSync(const KeyArgsList& keys, + const KeyArgsList& signer_keys, + const QString& in_path, bool ascii, + const QString& out_path) + -> std::tuple<GpgError, DataObjectPtr>; + + /** + * @brief + * + * @param keys + * @param signer_keys + * @param in_path + * @param ascii + * @param out_path + * @param cb + */ + void EncryptSignDirectory(const KeyArgsList& keys, + const KeyArgsList& signer_keys, + const QString& in_path, bool ascii, + const QString& out_path, + const GpgOperationCallback& cb); /** * @brief @@ -142,12 +272,31 @@ 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 + */ + auto DecryptVerifyFileSync(const QString& in_path, const QString& out_path) + -> std::tuple<GpgError, DataObjectPtr>; + + /** + * @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..4a35d3cd 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,220 @@ #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_search_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 : keys_cache_) { + keys_list->push_back(key); + } + } + 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(); + keys_search_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_.push_back(gpg_key); + keys_search_cache_.insert(gpg_key.GetId(), gpg_key); + keys_search_cache_.insert(gpg_key.GetFingerprint(), gpg_key); } + } + + GF_CORE_LOG_DEBUG("flush key channel cache address: {} object address: {}", + static_cast<void*>(&keys_search_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 + * + */ + QMap<QString, GpgKey> keys_search_cache_; + + /** + * @brief + * + */ + QList<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_search_cache_.find(key_id) != keys_search_cache_.end()) { + std::lock_guard<std::mutex> lock(ctx_mutex_); + // return a copy of the key in cache + return keys_search_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..ef8cb112 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,75 @@ #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 +105,87 @@ 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 + * Export keys + * @param keys keys used * @param outBuffer output byte array - * @return if successful + * @return if success */ -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; +void GpgKeyImportExporter::ExportAllKeys(const KeyArgsList& keys, bool secret, + bool ascii, + const GpgOperationCallback& cb) const { + RunGpgOperaAsync( + [=](const DataObjectPtr& data_object) -> GpgError { + if (keys.empty()) return GPG_ERR_CANCELED; + + int mode = 0; + 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)); + auto buffer = data_out.Read2GFBuffer(); + + if (secret) { + int mode = 0; + mode |= GPGME_EXPORT_MODE_SECRET; + + GpgData data_out_secret; + auto err = gpgme_op_export_keys(ctx, keys_array.data(), mode, + data_out_secret); + if (gpgme_err_code(err) != GPG_ERR_NO_ERROR) return {}; + + GF_CORE_LOG_DEBUG( + "operation of exporting secret keys finished, " + "ascii: {}, read_bytes: {}", + ascii, gpgme_data_seek(data_out_secret, 0, SEEK_END)); + buffer.Append(data_out_secret.Read2GFBuffer()); + } + + data_object->Swap({buffer}); + return err; + }, + cb, "gpgme_op_export_keys", "2.1.0"); } -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..d0724f7b 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,19 +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 key * @param secret - * @return true - * @return false + * @param ascii + * @return std::tuple<GpgError, GFBuffer> */ - bool ExportKeys(KeyIdArgsListPtr& uid_list, ByteArrayPtr& out_buffer, - 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 @@ -126,67 +81,23 @@ class GPGFRONTEND_CORE_EXPORT GpgKeyImportExporter * @return true * @return false */ - bool ExportKeys(const KeyArgsList& keys, ByteArrayPtr& outBuffer, - bool secret = false) const; + void ExportKeys(const KeyArgsList& keys, bool secret, bool ascii, + bool shortest, bool ssh_mode, + const GpgOperationCallback& cb) const; /** * @brief * * @param keys - * @param outBuffer * @param secret - * @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 + * @param ascii + * @param cb */ - 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 ExportAllKeys(const KeyArgsList& keys, bool secret, bool ascii, + 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..b5efe141 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,44 @@ 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, + static_cast<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 +224,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..118f4784 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, + QStringList{"--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,366 @@ 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 = params->GetUserid(); + auto algo = params->GetAlgo() + params->GetKeySizeStr(); + + GF_CORE_LOG_DEBUG("params: {} {}", params->GetAlgo(), + params->GetKeySizeStr()); + + 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.toUtf8(), + algo.toUtf8(), 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); +auto GpgKeyOpera::GenerateKeySync(const std::shared_ptr<GenKeyInfo>& params) + -> std::tuple<GpgError, DataObjectPtr> { + return RunGpgOperaSync( + [=, &ctx = ctx_](const DataObjectPtr& data_object) -> GpgError { + auto userid = params->GetUserid(); + auto algo = params->GetAlgo() + params->GetKeySizeStr(); + + GF_CORE_LOG_DEBUG("params: {} {}", params->GetAlgo(), + params->GetKeySizeStr()); + + 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.toUtf8(), + algo.toUtf8(), 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{}}); + } - if (ctx_.GetInfo(false).GnupgVersion >= "2.1.0") { - unsigned int flags = 0; + return CheckGpgError(err); + }, + "gpgme_op_createkey", "2.1.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; +void GpgKeyOpera::GenerateSubkey(const GpgKey& key, + const std::shared_ptr<GenKeyInfo>& params, + const GpgOperationCallback& callback) { + RunGpgOperaAsync( + [key, &ctx = ctx_, params](const DataObjectPtr& data_object) -> 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(); + 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("subkey generation args: {} {} {} {}", key.GetId(), + algo, expires, flags); + auto err = gpgme_op_createsubkey(ctx.DefaultContext(), + static_cast<gpgme_key_t>(key), + algo.toUtf8(), 0, expires, flags); + if (CheckGpgError(err) != GPG_ERR_NO_ERROR) { + data_object->Swap({GpgGenerateKeyResult{}}); + return err; + } - SPDLOG_DEBUG("args: {}", userid, algo, expires, flags); + data_object->Swap({GpgGenerateKeyResult{ + gpgme_op_genkey_result(ctx.DefaultContext())}}); + return CheckGpgError(err); + }, + callback, "gpgme_op_createsubkey", "2.1.13"); +} - err = gpgme_op_createkey(ctx_, userid, algo, 0, expires, nullptr, flags); +auto GpgKeyOpera::GenerateSubkeySync(const GpgKey& key, + const std::shared_ptr<GenKeyInfo>& params) + -> std::tuple<GpgError, DataObjectPtr> { + return RunGpgOperaSync( + [key, &ctx = ctx_, params](const DataObjectPtr& data_object) -> 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(); + 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.toUtf8(), 0, expires, flags); + + if (CheckGpgError(err) != GPG_ERR_NO_ERROR) { + data_object->Swap({GpgGenerateKeyResult{}}); + 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); - } + data_object->Swap({GpgGenerateKeyResult{ + gpgme_op_genkey_result(ctx.DefaultContext())}}); + return CheckGpgError(err); + }, + "gpgme_op_createsubkey", "2.1.13"); +} - 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); - } +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 = + 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; + } + + auto genkey_result = + GpgGenerateKeyResult{gpgme_op_genkey_result(ctx.DefaultContext())}; + + if (subkey_params == nullptr || !subkey_params->IsSubKey()) { + data_object->Swap({genkey_result}); + return err; + } + + 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; + } + + GF_CORE_LOG_DEBUG( + "try to generate subkey of key: {}, algo {} key size {}", + key.GetId(), subkey_params->GetAlgo(), + subkey_params->GetKeySizeStr()); + + algo = (subkey_params->GetAlgo() + subkey_params->GetKeySizeStr()) + .toUtf8(); + expires = + QDateTime::currentDateTime().secsTo(subkey_params->GetExpireTime()); + + 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; + + GF_CORE_LOG_DEBUG("subkey generation args: {} {} {} {}", key.GetId(), + algo, expires, flags); + + err = gpgme_op_createsubkey(ctx.DefaultContext(), + static_cast<gpgme_key_t>(key), algo, 0, + 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{}}); + } - return check_gpg_error(err); + return CheckGpgError(err); + }, + callback, "gpgme_op_createkey&gpgme_op_createsubkey", "2.1.0"); } -/** - * 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; +auto GpgKeyOpera::GenerateKeyWithSubkeySync( + const std::shared_ptr<GenKeyInfo>& params, + const std::shared_ptr<GenKeyInfo>& subkey_params) + -> std::tuple<GpgError, DataObjectPtr> { + return RunGpgOperaSync( + [&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 = + 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; + } + + auto genkey_result = + GpgGenerateKeyResult{gpgme_op_genkey_result(ctx.DefaultContext())}; - 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; + if (subkey_params == nullptr || !subkey_params->IsSubKey()) { + data_object->Swap({genkey_result}); + return err; + } - SPDLOG_DEBUG("args: {} {} {} {}", key.GetId(), 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; + } + + GF_CORE_LOG_DEBUG( + "try to generate subkey of key: {}, algo {} key size {}", + key.GetId(), subkey_params->GetAlgo(), + subkey_params->GetKeySizeStr()); + + algo = (subkey_params->GetAlgo() + subkey_params->GetKeySizeStr()) + .toUtf8(); + expires = + QDateTime::currentDateTime().secsTo(subkey_params->GetExpireTime()); + + 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; + + GF_CORE_LOG_DEBUG("subkey generation args: {} {} {} {}", key.GetId(), + algo, expires, flags); + + err = gpgme_op_createsubkey(ctx.DefaultContext(), + static_cast<gpgme_key_t>(key), algo, 0, + 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); + }, + "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..6ffe437c 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,16 @@ 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 + * + * @param params + */ + auto GenerateKeySync(const std::shared_ptr<GenKeyInfo>& params) + -> std::tuple<GpgError, DataObjectPtr>; /** * @brief @@ -123,13 +130,45 @@ 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 key + * @param params + */ + auto GenerateSubkeySync(const GpgKey& key, + const std::shared_ptr<GenKeyInfo>& params) + -> std::tuple<GpgError, DataObjectPtr>; + + /** + * @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); + + /** + * @brief + * + * @param params + * @param subkey_params + * @param callback + */ + auto GenerateKeyWithSubkeySync( + const std::shared_ptr<GenKeyInfo>& params, + const std::shared_ptr<GenKeyInfo>& subkey_params) + -> std::tuple<GpgError, DataObjectPtr>; 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 diff --git a/src/core/function/result_analyse/GpgDecryptResultAnalyse.cpp b/src/core/function/result_analyse/GpgDecryptResultAnalyse.cpp index d3ec8d6e..5d0ce920 100644 --- a/src/core/function/result_analyse/GpgDecryptResultAnalyse.cpp +++ b/src/core/function/result_analyse/GpgDecryptResultAnalyse.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,70 +28,103 @@ #include "GpgDecryptResultAnalyse.h" -#include "function/gpg/GpgKeyGetter.h" +#include "core/GpgModel.h" +#include "core/function/gpg/GpgKeyGetter.h" GpgFrontend::GpgDecryptResultAnalyse::GpgDecryptResultAnalyse( - GpgError m_error, GpgDecrResult m_result) - : error_(m_error), result_(std::move(m_result)) {} + GpgError m_error, GpgDecryptResult m_result) + : error_(m_error), result_(m_result) {} -void GpgFrontend::GpgDecryptResultAnalyse::do_analyse() { - stream_ << "[#] " << _("Decrypt Operation"); +void GpgFrontend::GpgDecryptResultAnalyse::doAnalyse() { + auto *result = result_.GetRaw(); + + stream_ << "# " << tr("Decrypt Operation") << " "; if (gpgme_err_code(error_) == GPG_ERR_NO_ERROR) { - stream_ << "[" << _("Success") << "]" << std::endl; + stream_ << "- " << tr("Success") << " " << Qt::endl; } else { - stream_ << "[" << _("Failed") << "] " << gpgme_strerror(error_) - << std::endl; - set_status(-1); - if (result_ != nullptr && result_->unsupported_algorithm != nullptr) { - stream_ << "------------>" << std::endl; - stream_ << _("Unsupported Algo") << ": " << result_->unsupported_algorithm - << std::endl; + stream_ << "- " << tr("Failed") << ": " << gpgme_strerror(error_) + << Qt::endl; + setStatus(-1); + if (result != nullptr && result->unsupported_algorithm != nullptr) { + stream_ << Qt::endl; + stream_ << "## " << tr("Unsupported Algo") << ": " + << result->unsupported_algorithm << Qt::endl; } } - if (result_ != nullptr && result_->recipients != nullptr) { - stream_ << "------------>" << std::endl; - if (result_->file_name != nullptr) { - stream_ << _("File Name") << ": " << result_->file_name << std::endl; - stream_ << std::endl; + if (result != nullptr && result->recipients != nullptr) { + stream_ << Qt::endl; + + stream_ << "## " << tr("Gernal State") << ": " << Qt::endl; + + if (result->file_name != nullptr) { + stream_ << "- " << tr("File Name") << ": " << result->file_name + << Qt::endl; + } + stream_ << "- " << tr("MIME") << ": " + << (result->is_mime == 0 ? tr("false") : tr("true")) << Qt::endl; + + stream_ << "- " << tr("Message Integrity Protection") << ": " + << (result->legacy_cipher_nomdc == 0 ? tr("true") : tr("false")) + << Qt::endl; + if (result->legacy_cipher_nomdc == 1) setStatus(0); /// < unsafe situation + + if (result->symkey_algo != nullptr) { + stream_ << "- " << tr("Symmetric Encryption Algorithm") << ": " + << result->symkey_algo << Qt::endl; + } + + if (result->session_key != nullptr) { + stream_ << "- " << tr("Session Key") << ": " << result->session_key + << Qt::endl; } - if (result_->is_mime) { - stream_ << _("MIME") << ": " << _("true") << std::endl; + + stream_ << "- " << tr("German Encryption Standards") << ": " + << (result->is_de_vs == 0 ? tr("false") : tr("true")) << Qt::endl; + + stream_ << Qt::endl << Qt::endl; + + auto *recipient = result->recipients; + auto index = 0; + if (recipient != nullptr) { + stream_ << "## " << tr("Recipient(s)") << ": " << Qt::endl << Qt::endl; } - auto recipient = result_->recipients; - if (recipient != nullptr) stream_ << _("Recipient(s)") << ": " << std::endl; while (recipient != nullptr) { + // check + if (recipient->keyid == nullptr) return; + stream_ << "### " << tr("Recipient") << " [" << ++index << "]: "; print_recipient(stream_, recipient); + stream_ << Qt::endl + << "---------------------------------------" << Qt::endl + << Qt::endl; recipient = recipient->next; } - stream_ << "<------------" << std::endl; + + stream_ << Qt::endl; } - stream_ << std::endl; + stream_ << Qt::endl; } void GpgFrontend::GpgDecryptResultAnalyse::print_recipient( - std::stringstream &stream, gpgme_recipient_t recipient) { - // check - if (recipient->keyid == nullptr) return; - - stream << " {>} " << _("Recipient") << ": "; + QTextStream &stream, gpgme_recipient_t recipient) { auto key = GpgFrontend::GpgKeyGetter::GetInstance().GetKey(recipient->keyid); if (key.IsGood()) { - stream << key.GetName().c_str(); - if (!key.GetEmail().empty()) { - stream << "<" << key.GetEmail().c_str() << ">"; - } + stream << key.GetName(); + if (!key.GetComment().isEmpty()) stream << "(" << key.GetComment() << ")"; + if (!key.GetEmail().isEmpty()) stream << "<" << key.GetEmail() << ">"; } else { - stream << "<" << _("Unknown") << ">"; - set_status(0); + stream << "<" << tr("unknown") << ">"; + setStatus(0); } - stream << std::endl; + stream << Qt::endl; - stream << " " << _("Key ID") << ": " << recipient->keyid << std::endl; - stream << " " << _("Public Key Algo") << ": " - << gpgme_pubkey_algo_name(recipient->pubkey_algo) << std::endl; + stream << "- " << tr("Key ID") << ": " << recipient->keyid << Qt::endl; + stream << "- " << tr("Public Key Algo") << ": " + << gpgme_pubkey_algo_name(recipient->pubkey_algo) << Qt::endl; + stream << "- " << tr("Status") << ": " << gpgme_strerror(recipient->status) + << Qt::endl; } diff --git a/src/core/function/result_analyse/GpgDecryptResultAnalyse.h b/src/core/function/result_analyse/GpgDecryptResultAnalyse.h index 1fc08d1f..c795e025 100644 --- a/src/core/function/result_analyse/GpgDecryptResultAnalyse.h +++ b/src/core/function/result_analyse/GpgDecryptResultAnalyse.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_GPGDECRYPTRESULTANALYSE_H -#define GPGFRONTEND_GPGDECRYPTRESULTANALYSE_H +#pragma once #include "GpgResultAnalyse.h" -#include "core/GpgConstants.h" +#include "core/model/GpgDecryptResult.h" namespace GpgFrontend { @@ -40,6 +39,7 @@ namespace GpgFrontend { */ class GPGFRONTEND_CORE_EXPORT GpgDecryptResultAnalyse : public GpgResultAnalyse { + Q_OBJECT public: /** * @brief Construct a new Decrypt Result Analyse object @@ -47,14 +47,14 @@ class GPGFRONTEND_CORE_EXPORT GpgDecryptResultAnalyse * @param m_error * @param m_result */ - explicit GpgDecryptResultAnalyse(GpgError m_error, GpgDecrResult m_result); + explicit GpgDecryptResultAnalyse(GpgError m_error, GpgDecryptResult m_result); protected: /** * @brief * */ - void do_analyse() final; + void doAnalyse() final; private: /** @@ -63,12 +63,10 @@ class GPGFRONTEND_CORE_EXPORT GpgDecryptResultAnalyse * @param stream * @param recipient */ - void print_recipient(std::stringstream &stream, gpgme_recipient_t recipient); + void print_recipient(QTextStream &stream, gpgme_recipient_t recipient); - GpgError error_; ///< - GpgDecrResult result_; ///< + GpgError error_; ///< + GpgDecryptResult result_; ///< }; } // namespace GpgFrontend - -#endif // GPGFRONTEND_GPGDECRYPTRESULTANALYSE_H diff --git a/src/core/function/result_analyse/GpgEncryptResultAnalyse.cpp b/src/core/function/result_analyse/GpgEncryptResultAnalyse.cpp index 21d37eab..a6b18b0a 100644 --- a/src/core/function/result_analyse/GpgEncryptResultAnalyse.cpp +++ b/src/core/function/result_analyse/GpgEncryptResultAnalyse.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,39 +28,53 @@ #include "GpgEncryptResultAnalyse.h" -GpgFrontend::GpgEncryptResultAnalyse::GpgEncryptResultAnalyse( - GpgError error, GpgEncrResult result) - : error_(error), result_(std::move(result)) {} +#include "core/model/GpgEncryptResult.h" -void GpgFrontend::GpgEncryptResultAnalyse::do_analyse() { - SPDLOG_DEBUG("start encrypt result analyse"); +namespace GpgFrontend { - stream_ << "[#] " << _("Encrypt Operation") << " "; +GpgEncryptResultAnalyse::GpgEncryptResultAnalyse(GpgError error, + GpgEncryptResult result) + : error_(error), result_(result) {} - if (gpgme_err_code(error_) == GPG_ERR_NO_ERROR) - stream_ << "[" << _("Success") << "]" << std::endl; - else { - stream_ << "[" << _("Failed") << "] " << gpgme_strerror(error_) - << std::endl; - set_status(-1); +void GpgEncryptResultAnalyse::doAnalyse() { + stream_ << "# " << tr("Encrypt Operation") << " "; + + if (gpgme_err_code(error_) == GPG_ERR_NO_ERROR) { + stream_ << "- " << tr("Success") << " " << Qt::endl; + } else { + stream_ << "- " << tr("Failed") << ": " << gpgme_strerror(error_) + << Qt::endl; + setStatus(-1); } - if (!~status_) { - stream_ << "------------>" << std::endl; - if (result_ != nullptr) { - stream_ << _("Invalid Recipients") << ": " << std::endl; - auto inv_reci = result_->invalid_recipients; + if ((~status_) == 0) { + stream_ << Qt::endl; + + const auto *result = result_.GetRaw(); + + if (result != nullptr) { + stream_ << "## " << tr("Invalid Recipients") << ": " << Qt::endl + << Qt::endl; + + auto *inv_reci = result->invalid_recipients; + auto index = 0; + while (inv_reci != nullptr) { - stream_ << _("Fingerprint") << ": " << inv_reci->fpr << std::endl; - stream_ << _("Reason") << ": " << gpgme_strerror(inv_reci->reason) - << std::endl; - stream_ << std::endl; + stream_ << "### " << tr("Recipients") << " " << ++index << ": " + << Qt::endl; + stream_ << "- " << tr("Fingerprint") << ": " << inv_reci->fpr + << Qt::endl; + stream_ << "- " << tr("Reason") << ": " + << gpgme_strerror(inv_reci->reason) << Qt::endl; + stream_ << Qt::endl << Qt::endl; inv_reci = inv_reci->next; } } - stream_ << "<------------" << std::endl; + stream_ << Qt::endl; } - stream_ << std::endl; + stream_ << Qt::endl; } + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/function/result_analyse/GpgEncryptResultAnalyse.h b/src/core/function/result_analyse/GpgEncryptResultAnalyse.h index 6811ef06..e9594628 100644 --- a/src/core/function/result_analyse/GpgEncryptResultAnalyse.h +++ b/src/core/function/result_analyse/GpgEncryptResultAnalyse.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_GPGENCRYPTRESULTANALYSE_H -#define GPGFRONTEND_GPGENCRYPTRESULTANALYSE_H +#pragma once #include "GpgResultAnalyse.h" -#include "core/GpgConstants.h" +#include "core/model/GpgEncryptResult.h" namespace GpgFrontend { /** @@ -39,6 +38,7 @@ namespace GpgFrontend { */ class GPGFRONTEND_CORE_EXPORT GpgEncryptResultAnalyse : public GpgResultAnalyse { + Q_OBJECT public: /** * @brief Construct a new Encrypt Result Analyse object @@ -46,19 +46,17 @@ class GPGFRONTEND_CORE_EXPORT GpgEncryptResultAnalyse * @param error * @param result */ - explicit GpgEncryptResultAnalyse(GpgError error, GpgEncrResult result); + explicit GpgEncryptResultAnalyse(GpgError error, GpgEncryptResult result); protected: /** * @brief * */ - void do_analyse() final; + void doAnalyse() final; private: - GpgError error_; ///< - GpgEncrResult result_; ///< + GpgError error_; ///< + GpgEncryptResult result_; ///< }; } // namespace GpgFrontend - -#endif // GPGFRONTEND_GPGENCRYPTRESULTANALYSE_H diff --git a/src/core/function/result_analyse/GpgResultAnalyse.cpp b/src/core/function/result_analyse/GpgResultAnalyse.cpp index 40ba4c3e..4c1f44e7 100644 --- a/src/core/function/result_analyse/GpgResultAnalyse.cpp +++ b/src/core/function/result_analyse/GpgResultAnalyse.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,19 +28,19 @@ #include "GpgResultAnalyse.h" -const std::string GpgFrontend::GpgResultAnalyse::GetResultReport() const { - return stream_.str(); +auto GpgFrontend::GpgResultAnalyse::GetResultReport() const -> const QString { + return *stream_.string(); } -int GpgFrontend::GpgResultAnalyse::GetStatus() const { return status_; } +auto GpgFrontend::GpgResultAnalyse::GetStatus() const -> int { return status_; } -void GpgFrontend::GpgResultAnalyse::set_status(int m_status) { +void GpgFrontend::GpgResultAnalyse::setStatus(int m_status) { if (m_status < status_) status_ = m_status; } void GpgFrontend::GpgResultAnalyse::Analyse() { if (!analysed_) { - do_analyse(); + doAnalyse(); analysed_ = true; } } diff --git a/src/core/function/result_analyse/GpgResultAnalyse.h b/src/core/function/result_analyse/GpgResultAnalyse.h index e609505f..9958b6a2 100644 --- a/src/core/function/result_analyse/GpgResultAnalyse.h +++ b/src/core/function/result_analyse/GpgResultAnalyse.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,21 +20,21 @@ * 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_GPGRESULTANALYSE_H -#define GPGFRONTEND_GPGRESULTANALYSE_H +#pragma once #include <sstream> -#include <string> -#include "core/GpgConstants.h" +#include "core/typedef/GpgTypedef.h" + namespace GpgFrontend { -class GPGFRONTEND_CORE_EXPORT GpgResultAnalyse { +class GPGFRONTEND_CORE_EXPORT GpgResultAnalyse : public QObject { + Q_OBJECT public: /** * @brief Construct a new Result Analyse object @@ -45,16 +45,16 @@ class GPGFRONTEND_CORE_EXPORT GpgResultAnalyse { /** * @brief Get the Result Report object * - * @return const std::string + * @return const QString */ - [[nodiscard]] const std::string GetResultReport() const; + [[nodiscard]] auto GetResultReport() const -> const QString; /** * @brief Get the Status object * * @return int */ - [[nodiscard]] int GetStatus() const; + [[nodiscard]] auto GetStatus() const -> int; /** * @brief @@ -67,20 +67,19 @@ class GPGFRONTEND_CORE_EXPORT GpgResultAnalyse { * @brief * */ - virtual void do_analyse() = 0; + virtual void doAnalyse() = 0; /** * @brief Set the status object * * @param m_status */ - void set_status(int m_status); + void setStatus(int m_status); - std::stringstream stream_; ///< - int status_ = 1; ///< - bool analysed_ = false; ///< + QString buffer_; + QTextStream stream_ = QTextStream(&buffer_); ///< + int status_ = 1; ///< + bool analysed_ = false; ///< }; } // namespace GpgFrontend - -#endif // GPGFRONTEND_GPGRESULTANALYSE_H diff --git a/src/core/function/result_analyse/GpgSignResultAnalyse.cpp b/src/core/function/result_analyse/GpgSignResultAnalyse.cpp index e4d1354f..bf429f38 100644 --- a/src/core/function/result_analyse/GpgSignResultAnalyse.cpp +++ b/src/core/function/result_analyse/GpgSignResultAnalyse.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,88 +28,98 @@ #include "GpgSignResultAnalyse.h" -#include "function/gpg/GpgKeyGetter.h" +#include "core/GpgModel.h" +#include "core/function/gpg/GpgKeyGetter.h" +#include "core/utils/LocalizedUtils.h" -GpgFrontend::GpgSignResultAnalyse::GpgSignResultAnalyse(GpgError error, - GpgSignResult result) +namespace GpgFrontend { + +GpgSignResultAnalyse::GpgSignResultAnalyse(GpgError error, GpgSignResult result) : error_(error), result_(std::move(result)) {} -void GpgFrontend::GpgSignResultAnalyse::do_analyse() { - SPDLOG_DEBUG("start sign result analyse"); +void GpgSignResultAnalyse::doAnalyse() { + auto *result = this->result_.GetRaw(); - stream_ << "[#] " << _("Sign Operation") << " "; + stream_ << "# " << tr("Sign Operation") << " "; - if (gpgme_err_code(error_) == GPG_ERR_NO_ERROR) - stream_ << "[" << _("Success") << "]" << std::endl; - else { - stream_ << "[" << _("Failed") << "] " << gpgme_strerror(error_) - << std::endl; - set_status(-1); + if (gpgme_err_code(error_) == GPG_ERR_NO_ERROR) { + stream_ << "- " << tr("Success") << " " << Qt::endl; + } else { + stream_ << "- " << tr("Failed") << " " << gpgme_strerror(error_) + << Qt::endl; + setStatus(-1); } - if (result_ != nullptr && - (result_->signatures != nullptr || result_->invalid_signers != nullptr)) { - SPDLOG_DEBUG("sign result analyse getting result"); - stream_ << "------------>" << std::endl; - auto new_sign = result_->signatures; + if (result != nullptr && + (result->signatures != nullptr || result->invalid_signers != nullptr)) { + stream_ << Qt::endl; + auto *new_sign = result->signatures; + auto index = 0; while (new_sign != nullptr) { - stream_ << "[>]" << _("New Signature") << ": " << std::endl; - - SPDLOG_DEBUG("signers fingerprint: ", new_sign->fpr); - - stream_ << " " << _("Sign Mode") << ": "; - if (new_sign->type == GPGME_SIG_MODE_NORMAL) - stream_ << _("Normal"); - else if (new_sign->type == GPGME_SIG_MODE_CLEAR) - stream_ << _("Clear"); - else if (new_sign->type == GPGME_SIG_MODE_DETACH) - stream_ << _("Detach"); + stream_ << "## " << tr("New Signature") << " [" << ++index + << "]: " << Qt::endl; + + stream_ << "- " << tr("Sign Mode") << ": "; + if (new_sign->type == GPGME_SIG_MODE_NORMAL) { + stream_ << tr("Normal"); + } else if (new_sign->type == GPGME_SIG_MODE_CLEAR) { + stream_ << tr("Clear"); + } else if (new_sign->type == GPGME_SIG_MODE_DETACH) { + stream_ << tr("Detach"); + } - stream_ << std::endl; + stream_ << Qt::endl; - auto singerKey = - GpgFrontend::GpgKeyGetter::GetInstance().GetKey(new_sign->fpr); - if (singerKey.IsGood()) { - stream_ << " " << _("Signer") << ": " - << singerKey.GetUIDs()->front().GetUID() << std::endl; + auto singer_key = GpgKeyGetter::GetInstance().GetKey(new_sign->fpr); + if (singer_key.IsGood()) { + stream_ << "- " << tr("Signer") << ": " + << singer_key.GetUIDs()->front().GetUID() << Qt::endl; } else { - stream_ << " " << _("Signer") << ": " - << "<unknown>" << std::endl; + stream_ << "- " << tr("Signer") << ": " + << "<unknown>" << Qt::endl; } - stream_ << " " << _("Public Key Algo") << ": " - << gpgme_pubkey_algo_name(new_sign->pubkey_algo) << std::endl; - stream_ << " " << _("Hash Algo") << ": " - << gpgme_hash_algo_name(new_sign->hash_algo) << std::endl; - stream_ << " " << _("Date") << "(" << _("UTC") << ")" + stream_ << "- " << tr("Public Key Algo") << ": " + << gpgme_pubkey_algo_name(new_sign->pubkey_algo) << Qt::endl; + stream_ << "- " << tr("Hash Algo") << ": " + << gpgme_hash_algo_name(new_sign->hash_algo) << Qt::endl; + stream_ << "- " << tr("Date") << "(" << tr("UTC") << ")" << ": " - << boost::posix_time::to_iso_extended_string( - boost::posix_time::from_time_t(new_sign->timestamp)) - << std::endl; + << QDateTime::fromSecsSinceEpoch(new_sign->timestamp).toString() + << Qt::endl; + stream_ << "- " << tr("Date") << "(" << tr("Localized") << ")" + << ": " << GetFormatedDateByTimestamp(new_sign->timestamp) + << Qt::endl; - stream_ << std::endl; + stream_ << Qt::endl + << "---------------------------------------" << Qt::endl + << Qt::endl; new_sign = new_sign->next; } - SPDLOG_DEBUG("sign result analyse getting invalid signer"); + auto *invalid_signer = result->invalid_signers; + stream_ << Qt::endl; - auto invalid_signer = result_->invalid_signers; - - if (invalid_signer != nullptr) - stream_ << _("Invalid Signers") << ": " << std::endl; + if (invalid_signer != nullptr) { + stream_ << "## " << tr("Invalid Signers") << ": " << Qt::endl; + } + index = 0; while (invalid_signer != nullptr) { - set_status(0); - stream_ << "[>] " << _("Signer") << ": " << std::endl; - stream_ << " " << _("Fingerprint") << ": " << invalid_signer->fpr - << std::endl; - stream_ << " " << _("Reason") << ": " - << gpgme_strerror(invalid_signer->reason) << std::endl; - stream_ << std::endl; + setStatus(0); + stream_ << "### " << tr("Signer") << " [" << ++index << "]: " << Qt::endl + << Qt::endl; + stream_ << "- " << tr("Fingerprint") << ": " << invalid_signer->fpr + << Qt::endl; + stream_ << "- " << tr("Reason") << ": " + << gpgme_strerror(invalid_signer->reason) << Qt::endl; + stream_ << "---------------------------------------" << Qt::endl; invalid_signer = invalid_signer->next; } - stream_ << "<------------" << std::endl; + stream_ << Qt::endl; } -}
\ No newline at end of file +} + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/function/result_analyse/GpgSignResultAnalyse.h b/src/core/function/result_analyse/GpgSignResultAnalyse.h index 43a78942..58a20417 100644 --- a/src/core/function/result_analyse/GpgSignResultAnalyse.h +++ b/src/core/function/result_analyse/GpgSignResultAnalyse.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,16 +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_GPGSIGNRESULTANALYSE_H -#define GPGFRONTEND_GPGSIGNRESULTANALYSE_H +#pragma once #include "GpgResultAnalyse.h" +#include "core/model/GpgSignResult.h" namespace GpgFrontend { @@ -38,6 +38,7 @@ namespace GpgFrontend { * */ class GPGFRONTEND_CORE_EXPORT GpgSignResultAnalyse : public GpgResultAnalyse { + Q_OBJECT public: /** * @brief Construct a new Sign Result Analyse object @@ -52,7 +53,7 @@ class GPGFRONTEND_CORE_EXPORT GpgSignResultAnalyse : public GpgResultAnalyse { * @brief * */ - void do_analyse(); + void doAnalyse() override; private: GpgError error_; ///< @@ -61,5 +62,3 @@ class GPGFRONTEND_CORE_EXPORT GpgSignResultAnalyse : public GpgResultAnalyse { }; } // namespace GpgFrontend - -#endif // GPGFRONTEND_GPGSIGNRESULTANALYSE_H diff --git a/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp b/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp index b19db5b2..618275f9 100644 --- a/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp +++ b/src/core/function/result_analyse/GpgVerifyResultAnalyse.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,188 +28,200 @@ #include "GpgVerifyResultAnalyse.h" -#include <boost/format.hpp> - #include "GpgFrontend.h" -#include "core/GpgConstants.h" -#include "function/gpg/GpgKeyGetter.h" +#include "core/GpgModel.h" +#include "core/function/gpg/GpgKeyGetter.h" +#include "core/utils/CommonUtils.h" +#include "core/utils/LocalizedUtils.h" GpgFrontend::GpgVerifyResultAnalyse::GpgVerifyResultAnalyse( GpgError error, GpgVerifyResult result) - : error_(error), result_(std::move(result)) {} + : error_(error), result_(result) {} -void GpgFrontend::GpgVerifyResultAnalyse::do_analyse() { - SPDLOG_DEBUG("started"); +void GpgFrontend::GpgVerifyResultAnalyse::doAnalyse() { + auto *result = this->result_.GetRaw(); - stream_ << "[#] " << _("Verify Operation") << " "; + stream_ << "# " << tr("Verify Operation") << " "; - if (gpgme_err_code(error_) == GPG_ERR_NO_ERROR) - stream_ << "[" << _("Success") << "]" << std::endl; - else { - stream_ << "[" << _("Failed") << "] " << gpgme_strerror(error_) - << std::endl; - set_status(-1); + if (gpgme_err_code(error_) == GPG_ERR_NO_ERROR) { + stream_ << " - " << tr("Success") << " " << Qt::endl; + } else { + stream_ << " - " << tr("Failed") << ": " << gpgme_strerror(error_) + << Qt::endl; + setStatus(-1); } - if (result_ != nullptr && result_->signatures != nullptr) { - stream_ << "------------>" << std::endl; - auto sign = result_->signatures; + if (result != nullptr && result->signatures != nullptr) { + stream_ << Qt::endl; + auto *sign = result->signatures; + + stream_ << "-> " << tr("Signed On") << "(" << tr("UTC") << ")" + << ": " << QDateTime::fromSecsSinceEpoch(sign->timestamp).toString() + << Qt::endl; - stream_ << "[>] " << _("Signed On") << "(" << _("UTC") << ")" - << " " - << boost::posix_time::to_iso_extended_string( - boost::posix_time::from_time_t(sign->timestamp)) - << std::endl; + stream_ << "-> " << tr("Signed On") << "(" << tr("Localized") << ")" + << ": " << GetFormatedDateByTimestamp(sign->timestamp) << Qt::endl; - stream_ << std::endl << "[>] " << _("Signatures List") << ":" << std::endl; + stream_ << Qt::endl << "## " << tr("Signatures List") << ":" << Qt::endl; + stream_ << Qt::endl; - bool canContinue = true; + bool can_continue = true; int count = 1; - while (sign && canContinue) { - stream_ << boost::format(_("Signature [%1%]:")) % count++ << std::endl; + while ((sign != nullptr) && can_continue) { + stream_ << "### " << tr("Signature [%1]:").arg(count++) << Qt::endl; + stream_ << "- " << tr("Status") << ": "; switch (gpg_err_code(sign->status)) { case GPG_ERR_BAD_SIGNATURE: - stream_ << _("A Bad Signature.") << std::endl; + stream_ << tr("A Bad Signature.") << Qt::endl; print_signer(stream_, sign); - stream_ << _("This Signature is invalid.") << std::endl; - canContinue = false; - set_status(-1); + stream_ << tr("This Signature is invalid.") << Qt::endl; + can_continue = false; + setStatus(-1); break; case GPG_ERR_NO_ERROR: - stream_ << _("A") << " "; - if (sign->summary & GPGME_SIGSUM_GREEN) { - stream_ << _("Good") << " "; + stream_ << tr("A") << " "; + if ((sign->summary & GPGME_SIGSUM_GREEN) != 0) { + stream_ << tr("Good") << " "; } - if (sign->summary & GPGME_SIGSUM_RED) { - stream_ << _("Bad") << " "; + if ((sign->summary & GPGME_SIGSUM_RED) != 0) { + stream_ << tr("Bad") << " "; } - if (sign->summary & GPGME_SIGSUM_SIG_EXPIRED) { - stream_ << _("Expired") << " "; + if ((sign->summary & GPGME_SIGSUM_SIG_EXPIRED) != 0) { + stream_ << tr("Expired") << " "; } - if (sign->summary & GPGME_SIGSUM_KEY_MISSING) { - stream_ << _("Missing Key's") << " "; + if ((sign->summary & GPGME_SIGSUM_KEY_MISSING) != 0) { + stream_ << tr("Missing Key's") << " "; } - if (sign->summary & GPGME_SIGSUM_KEY_REVOKED) { - stream_ << _("Revoked Key's") << " "; + if ((sign->summary & GPGME_SIGSUM_KEY_REVOKED) != 0) { + stream_ << tr("Revoked Key's") << " "; } - if (sign->summary & GPGME_SIGSUM_KEY_EXPIRED) { - stream_ << _("Expired Key's") << " "; + if ((sign->summary & GPGME_SIGSUM_KEY_EXPIRED) != 0) { + stream_ << tr("Expired Key's") << " "; } - if (sign->summary & GPGME_SIGSUM_CRL_MISSING) { - stream_ << _("Missing CRL's") << " "; + if ((sign->summary & GPGME_SIGSUM_CRL_MISSING) != 0) { + stream_ << tr("Missing CRL's") << " "; } - if (sign->summary & GPGME_SIGSUM_VALID) { - stream_ << _("Signature Fully Valid.") << std::endl; + if ((sign->summary & GPGME_SIGSUM_VALID) != 0) { + stream_ << tr("Signature Fully Valid.") << Qt::endl; } else { - stream_ << _("Signature Not Fully Valid.") << std::endl; - stream_ << _("(May used a subkey to sign)") << std::endl; + stream_ << tr("Signature Not Fully Valid.") << Qt::endl; + stream_ << tr("(Adjust Trust Level to make it Fully Vaild)") + << Qt::endl; } - if (!(sign->status & GPGME_SIGSUM_KEY_MISSING)) { - if (!print_signer(stream_, sign)) set_status(0); + if ((sign->status & GPGME_SIGSUM_KEY_MISSING) == 0U) { + if (!print_signer(stream_, sign)) setStatus(0); } else { - stream_ << _("Key is NOT present with ID 0x") << sign->fpr - << std::endl; + stream_ << tr("Key is NOT present with ID 0x") << sign->fpr + << Qt::endl; } - set_status(1); + setStatus(1); break; case GPG_ERR_NO_PUBKEY: - stream_ << _("A signature could NOT be verified due to a Missing Key") - << std::endl; - set_status(-2); + stream_ + << tr("A signature could NOT be verified due to a Missing Key") + << Qt::endl; + setStatus(-2); break; case GPG_ERR_CERT_REVOKED: - stream_ << _("A signature is valid but the key used to verify the " - "signature has been revoked") - << std::endl; + stream_ << tr("A signature is valid but the key used to verify the " + "signature has been revoked") + << Qt::endl; if (!print_signer(stream_, sign)) { - set_status(0); + setStatus(0); } - set_status(-1); + setStatus(-1); break; case GPG_ERR_SIG_EXPIRED: - stream_ << _("A signature is valid but expired") << std::endl; + stream_ << tr("A signature is valid but expired") << Qt::endl; if (!print_signer(stream_, sign)) { - set_status(0); + setStatus(0); } - set_status(-1); + setStatus(-1); break; case GPG_ERR_KEY_EXPIRED: - stream_ << _("A signature is valid but the key used to " - "verify the signature has expired.") - << std::endl; + stream_ << tr("A signature is valid but the key used to " + "verify the signature has expired.") + << Qt::endl; if (!print_signer(stream_, sign)) { - set_status(0); + setStatus(0); } break; case GPG_ERR_GENERAL: - stream_ << _("There was some other error which prevented " - "the signature verification.") - << std::endl; + stream_ << tr("There was some other error which prevented " + "the signature verification.") + << Qt::endl; status_ = -1; - canContinue = false; + can_continue = false; break; default: - auto fpr = std::string(sign->fpr); - stream_ << _("Error for key with fingerprint") << " " - << GpgFrontend::beautify_fingerprint(fpr); - set_status(-1); + auto fpr = QString(sign->fpr); + stream_ << tr("Error for key with fingerprint") << " " + << GpgFrontend::BeautifyFingerprint(fpr); + setStatus(-1); } - stream_ << std::endl; + stream_ << Qt::endl; sign = sign->next; } - stream_ << "<------------" << std::endl; + stream_ << Qt::endl; } else { stream_ - << "[>] " - << _("Could not find information that can be used for verification.") - << std::endl; - set_status(0); + << "-> " + << tr("Could not find information that can be used for verification.") + << Qt::endl; + setStatus(0); return; } } -bool GpgFrontend::GpgVerifyResultAnalyse::print_signer( - std::stringstream &stream, gpgme_signature_t sign) { - bool keyFound = true; +auto GpgFrontend::GpgVerifyResultAnalyse::print_signer(QTextStream &stream, + gpgme_signature_t sign) + -> bool { + bool key_found = true; auto key = GpgFrontend::GpgKeyGetter::GetInstance().GetKey(sign->fpr); if (!key.IsGood()) { - stream << " " << _("Signed By") << ": " - << "<" << _("Unknown") << ">" << std::endl; - set_status(0); - keyFound = false; + stream << "- " << tr("Signed By") << ": " + << "<" << tr("Unknown") << ">" << Qt::endl; + setStatus(0); + key_found = false; } else { - stream << " " << _("Signed By") << ": " - << key.GetUIDs()->front().GetUID() << std::endl; + stream << "- " << tr("Signed By") << ": " << key.GetUIDs()->front().GetUID() + << Qt::endl; + } + if (sign->pubkey_algo != 0U) { + stream << "- " << tr("Public Key Algo") << ": " + << gpgme_pubkey_algo_name(sign->pubkey_algo) << Qt::endl; + } + if (sign->hash_algo != 0U) { + stream << "- " << tr("Hash Algo") << ": " + << gpgme_hash_algo_name(sign->hash_algo) << Qt::endl; } - if (sign->pubkey_algo) - stream << " " << _("Public Key Algo") << ": " - << gpgme_pubkey_algo_name(sign->pubkey_algo) << std::endl; - if (sign->hash_algo) - stream << " " << _("Hash Algo") << ": " - << gpgme_hash_algo_name(sign->hash_algo) << std::endl; - if (sign->timestamp) - stream << " " << _("Date") << "(" << _("UTC") << ")" - << ": " - << boost::posix_time::to_iso_extended_string( - boost::posix_time::from_time_t(sign->timestamp)) - << std::endl; - stream << std::endl; - return keyFound; + if (sign->timestamp != 0U) { + stream << "- " << tr("Date") << "(" << tr("UTC") << ")" + << ": " << QDateTime::fromSecsSinceEpoch(sign->timestamp).toString() + << Qt::endl; + + stream << "- " << tr("Date") << "(" << tr("Localized") << ")" + << ": " << GetFormatedDateByTimestamp(sign->timestamp) << Qt::endl; + } + stream << Qt::endl; + return key_found; } -gpgme_signature_t GpgFrontend::GpgVerifyResultAnalyse::GetSignatures() const { - if (result_) - return result_->signatures; - else - return nullptr; +auto GpgFrontend::GpgVerifyResultAnalyse::GetSignatures() const + -> gpgme_signature_t { + if (result_.IsGood()) { + return result_.GetRaw()->signatures; + } + return nullptr; } -GpgFrontend::GpgVerifyResult -GpgFrontend::GpgVerifyResultAnalyse::TakeChargeOfResult() { - return std::move(result_); + +auto GpgFrontend::GpgVerifyResultAnalyse::TakeChargeOfResult() + -> GpgFrontend::GpgVerifyResult { + return result_; } diff --git a/src/core/function/result_analyse/GpgVerifyResultAnalyse.h b/src/core/function/result_analyse/GpgVerifyResultAnalyse.h index ce8e03ad..8aa2e41f 100644 --- a/src/core/function/result_analyse/GpgVerifyResultAnalyse.h +++ b/src/core/function/result_analyse/GpgVerifyResultAnalyse.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_GPGVERIFYRESULTANALYSE_H -#define GPGFRONTEND_GPGVERIFYRESULTANALYSE_H +#pragma once #include "GpgResultAnalyse.h" -#include "core/model/GpgKeySignature.h" +#include "core/model/GpgVerifyResult.h" namespace GpgFrontend { /** @@ -38,6 +37,7 @@ namespace GpgFrontend { * */ class GPGFRONTEND_CORE_EXPORT GpgVerifyResultAnalyse : public GpgResultAnalyse { + Q_OBJECT public: /** * @brief Construct a new Verify Result Analyse object @@ -52,21 +52,21 @@ class GPGFRONTEND_CORE_EXPORT GpgVerifyResultAnalyse : public GpgResultAnalyse { * * @return gpgme_signature_t */ - gpgme_signature_t GetSignatures() const; + auto GetSignatures() const -> gpgme_signature_t; /** * @brief * * @return GpgVerifyResult */ - GpgVerifyResult TakeChargeOfResult(); + auto TakeChargeOfResult() -> GpgVerifyResult; - private: + protected: /** * @brief * */ - void do_analyse(); + void doAnalyse() final; private: /** @@ -77,12 +77,10 @@ class GPGFRONTEND_CORE_EXPORT GpgVerifyResultAnalyse : public GpgResultAnalyse { * @return true * @return false */ - bool print_signer(std::stringstream &stream, gpgme_signature_t sign); + auto print_signer(QTextStream &stream, gpgme_signature_t sign) -> bool; GpgError error_; ///< GpgVerifyResult result_; ///< }; } // namespace GpgFrontend - -#endif // GPGFRONTEND_GPGVERIFYRESULTANALYSE_H diff --git a/src/core/log/QtLoggerFmt.h b/src/core/log/QtLoggerFmt.h new file mode 100644 index 00000000..e7ac2c82 --- /dev/null +++ b/src/core/log/QtLoggerFmt.h @@ -0,0 +1,64 @@ +/** + * 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 + +template <> +struct fmt::formatter<QString> { + // Parses format specifications. + constexpr auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) { + return ctx.begin(); + } + + // Formats the QString qstr and writes it to the output. + template <typename FormatContext> + auto format(const QString& qstr, FormatContext& ctx) const + -> decltype(ctx.out()) { + // Convert QString to UTF-8 QString (to handle Unicode characters + // correctly) + QByteArray utf8_array = qstr.toUtf8(); + return fmt::format_to(ctx.out(), "{}", utf8_array.constData()); + } +}; + +template <> +struct fmt::formatter<QByteArray> { + // Parses format specifications. + constexpr auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) { + return ctx.begin(); + } + + // Formats the QString qstr and writes it to the output. + template <typename FormatContext> + auto format(const QByteArray& qarray, FormatContext& ctx) const + -> decltype(ctx.out()) { + // Convert QString to UTF-8 QString (to handle Unicode characters + // correctly) + return fmt::format_to(ctx.out(), "{}", qarray.constData()); + } +}; diff --git a/src/core/thread/CtxCheckTask.h b/src/core/model/CommonStruct.h index 06ddfd82..d7d09602 100644 --- a/src/core/thread/CtxCheckTask.h +++ b/src/core/model/CommonStruct.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -19,45 +19,28 @@ * The initial version of the source code is inherited from * the gpg4usb project, which is under GPL-3.0-or-later. * - * The source code version of this software was modified and released - * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021. + * 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 * */ -#ifndef GPGFRONTEND_CTXCHECKTRHEAD_H -#define GPGFRONTEND_CTXCHECKTRHEAD_H +#pragma once -#include "core/GpgFrontendCore.h" -#include "core/thread/Task.h" +namespace GpgFrontend { -namespace GpgFrontend::Thread { /** * @brief * */ -class GPGFRONTEND_CORE_EXPORT CtxCheckTask : public Task { - Q_OBJECT - public: - /** - * @brief Construct a new Ctx Check Thread object - * - */ - CtxCheckTask(); - - signals: - /** - * @brief - * - */ - void SignalGnupgNotInstall(); - - protected: - /** - * @brief - * - */ - void Run() override; +template <typename T> +struct GPGFRONTEND_CORE_EXPORT RefDeleter { + void operator()(T* _key) { + gpgme_unre + } }; -} // namespace GpgFrontend::Thread -#endif // GPGFRONTEND_CTXCHECKTRHEAD_H +template <typename T> +using KeyRefHandler = std::unique_ptr<T, RefDeleter<T>>; ///< +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/model/DataObject.cpp b/src/core/model/DataObject.cpp new file mode 100644 index 00000000..d0e9d141 --- /dev/null +++ b/src/core/model/DataObject.cpp @@ -0,0 +1,83 @@ +/** + * 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 "DataObject.h" + +#include <stack> + +namespace GpgFrontend { + +class DataObject::Impl { + public: + Impl() = default; + + Impl(std::initializer_list<std::any> init_list) : params_(init_list) {} + + void AppendObject(const std::any& obj) { params_.push_back(obj); } + + auto GetParameter(size_t index) -> std::any { + if (index >= params_.size()) { + throw std::out_of_range("index out of range"); + } + return params_[index]; + } + + auto GetObjectSize() -> size_t { return params_.size(); } + + private: + std::vector<std::any> params_; +}; + +DataObject::DataObject() : p_(SecureCreateUniqueObject<Impl>()) {} + +DataObject::DataObject(std::initializer_list<std::any> i) + : p_(SecureCreateUniqueObject<Impl>(i)) {} + +DataObject::~DataObject() = default; + +DataObject::DataObject(DataObject&&) noexcept = default; + +auto DataObject::operator[](size_t index) const -> std::any { + return p_->GetParameter(index); +} + +auto DataObject::GetParameter(size_t index) const -> std::any { + return p_->GetParameter(index); +} + +void DataObject::AppendObject(std::any obj) { return p_->AppendObject(obj); } + +auto DataObject::GetObjectSize() const -> size_t { return p_->GetObjectSize(); } + +void DataObject::Swap(DataObject& other) noexcept { std::swap(p_, other.p_); } + +void DataObject::Swap(DataObject&& other) noexcept { p_ = std::move(other.p_); } + +void swap(DataObject& a, DataObject& b) noexcept { a.Swap(b); } + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/model/DataObject.h b/src/core/model/DataObject.h new file mode 100644 index 00000000..6b41a051 --- /dev/null +++ b/src/core/model/DataObject.h @@ -0,0 +1,104 @@ +/** + * 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 <any> +#include <typeindex> +#include <typeinfo> + +#include "core/GpgFrontendCoreExport.h" +#include "core/utils/MemoryUtils.h" + +namespace GpgFrontend { + +class DataObject; +using DataObjectPtr = std::shared_ptr<DataObject>; ///< + +class GPGFRONTEND_CORE_EXPORT DataObject { + public: + DataObject(); + + DataObject(std::initializer_list<std::any>); + + ~DataObject(); + + DataObject(DataObject&&) noexcept; + + auto operator[](size_t index) const -> std::any; + + void AppendObject(std::any); + + [[nodiscard]] auto GetParameter(size_t index) const -> std::any; + + [[nodiscard]] auto GetObjectSize() const -> size_t; + + void Swap(DataObject& other) noexcept; + + void Swap(DataObject&& other) noexcept; + + template <typename... Args> + auto Check() -> bool { + if (sizeof...(Args) != GetObjectSize()) return false; + + std::vector<std::type_info const*> type_list = {&typeid(Args)...}; + for (size_t i = 0; i < type_list.size(); ++i) { + if (std::type_index(*type_list[i]) != + std::type_index((*this)[i].type())) { + GF_CORE_LOG_ERROR( + "value of index {} in data object is type: {}, " + "not expected type: {}", + i, ((*this)[i]).type().name(), type_list[i]->name()); + return false; + } + } + return true; + } + + private: + class Impl; + SecureUniquePtr<Impl> p_; +}; + +template <typename... Args> +auto TransferParams(Args&&... args) -> std::shared_ptr<DataObject> { + return GpgFrontend::SecureCreateSharedObject<DataObject>( + DataObject{std::forward<Args>(args)...}); +} + +template <typename T> +auto ExtractParams(const std::shared_ptr<DataObject>& d_o, int index) -> T { + if (!d_o) { + throw std::invalid_argument("nullptr provided for DataObjectPtr"); + } + return std::any_cast<T>(d_o->GetParameter(index)); +} + +void swap(DataObject& a, DataObject& b) noexcept; + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/model/GFBuffer.cpp b/src/core/model/GFBuffer.cpp new file mode 100644 index 00000000..411a5725 --- /dev/null +++ b/src/core/model/GFBuffer.cpp @@ -0,0 +1,59 @@ +/** + * 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 "GFBuffer.h" + +namespace GpgFrontend { + +GFBuffer::GFBuffer() = default; + +GFBuffer::GFBuffer(QByteArray buffer) : buffer_(std::move(buffer)) {} + +GFBuffer::GFBuffer(const QString& str) : buffer_(str.toUtf8()) {} + +auto GFBuffer::operator==(const GFBuffer& o) const -> bool { + return buffer_ == o.buffer_; +} + +auto GFBuffer::Data() const -> const char* { return buffer_.constData(); } + +void GFBuffer::Resize(ssize_t size) { buffer_.resize(size); } + +auto GFBuffer::Size() const -> size_t { return buffer_.size(); } + +auto GFBuffer::ConvertToQByteArray() const -> QByteArray { return buffer_; } + +auto GFBuffer::Empty() const -> bool { return this->Size() == 0; } + +void GFBuffer::Append(const GFBuffer& o) { buffer_.append(o.buffer_); } + +void GFBuffer::Append(const char* buffer, ssize_t size) { + buffer_.append(buffer, size); +} + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/model/GFBuffer.h b/src/core/model/GFBuffer.h new file mode 100644 index 00000000..46189195 --- /dev/null +++ b/src/core/model/GFBuffer.h @@ -0,0 +1,64 @@ +/** + * 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/GpgFrontendCoreExport.h" +#include "core/utils/MemoryUtils.h" + +namespace GpgFrontend { + +class GPGFRONTEND_CORE_EXPORT GFBuffer { + public: + GFBuffer(); + + explicit GFBuffer(QByteArray buffer); + + explicit GFBuffer(const QString& str); + + auto operator==(const GFBuffer& o) const -> bool; + + [[nodiscard]] auto Data() const -> const char*; + + void Resize(ssize_t size); + + [[nodiscard]] auto Size() const -> size_t; + + [[nodiscard]] auto Empty() const -> bool; + + void Append(const GFBuffer&); + + void Append(const char*, ssize_t); + + [[nodiscard]] auto ConvertToQByteArray() const -> QByteArray; + + private: + QByteArray buffer_; +}; + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/model/GFDataExchanger.cpp b/src/core/model/GFDataExchanger.cpp new file mode 100644 index 00000000..abf79c6b --- /dev/null +++ b/src/core/model/GFDataExchanger.cpp @@ -0,0 +1,89 @@ +/** + * 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 "GFDataExchanger.h" + +#include "core/utils/LogUtils.h" + +namespace GpgFrontend { + +auto GFDataExchanger::Write(const std::byte* buffer, size_t size) -> ssize_t { + if (close_) return -1; + if (size == 0) return 0; + + std::atomic<ssize_t> write_bytes = 0; + std::unique_lock<std::mutex> lock(mutex_); + try { + for (size_t i = 0; i < size; i++) { + if (queue_.size() == queue_max_size_) not_empty_.notify_all(); + not_full_.wait(lock, + [=] { return queue_.size() < queue_max_size_ || close_; }); + if (close_) return -1; + + queue_.push(buffer[i]); + write_bytes++; + } + } catch (...) { + GF_CORE_LOG_ERROR( + "gf data exchanger caught exception when it writes to queue, abort..."); + } + + if (!queue_.empty()) not_empty_.notify_all(); + return write_bytes; +} + +auto GFDataExchanger::Read(std::byte* buffer, size_t size) -> ssize_t { + std::unique_lock<std::mutex> lock(mutex_); + if (size == 0 || (close_ && queue_.empty())) return 0; + + std::atomic<ssize_t> read_bytes = 0; + for (size_t i = 0; i < size; ++i) { + if (queue_.empty()) not_full_.notify_all(); + not_empty_.wait(lock, [=] { return !queue_.empty() || close_; }); + + if (close_ && queue_.empty()) return 0; + buffer[i] = queue_.front(); + queue_.pop(); + read_bytes++; + } + + if (queue_.size() < queue_max_size_) not_full_.notify_all(); + return read_bytes; +} + +void GFDataExchanger::CloseWrite() { + std::unique_lock<std::mutex> const lock(mutex_); + + close_ = true; + not_full_.notify_all(); + not_empty_.notify_all(); +} + +GFDataExchanger::GFDataExchanger(ssize_t size) : queue_max_size_(size) {} + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/model/GFDataExchanger.h b/src/core/model/GFDataExchanger.h new file mode 100644 index 00000000..7d4ab050 --- /dev/null +++ b/src/core/model/GFDataExchanger.h @@ -0,0 +1,53 @@ +/** + * 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 <queue> + +namespace GpgFrontend { + +class GFDataExchanger { + public: + explicit GFDataExchanger(ssize_t size); + + auto Write(const std::byte* buffer, size_t size) -> ssize_t; + + auto Read(std::byte* buffer, size_t size) -> ssize_t; + + void CloseWrite(); + + private: + std::condition_variable not_full_, not_empty_; + std::queue<std::byte> queue_; + std::mutex mutex_; + const ssize_t queue_max_size_; + std::atomic_bool close_ = false; +}; + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/model/GpgData.cpp b/src/core/model/GpgData.cpp index 05f61a46..8b2be895 100644 --- a/src/core/model/GpgData.cpp +++ b/src/core/model/GpgData.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,52 +28,128 @@ #include "core/model/GpgData.h" -GpgFrontend::GpgData::GpgData() { +#include <unistd.h> + +#include "core/model/GFDataExchanger.h" +#include "core/typedef/GpgTypedef.h" + +namespace GpgFrontend { + +constexpr size_t kBufferSize = 32 * 1024; + +auto GFReadExCb(void* handle, void* buffer, size_t size) -> ssize_t { + auto* ex = static_cast<GFDataExchanger*>(handle); + return ex->Read(static_cast<std::byte*>(buffer), size); +} + +auto GFWriteExCb(void* handle, const void* buffer, size_t size) -> ssize_t { + auto* ex = static_cast<GFDataExchanger*>(handle); + return ex->Write(static_cast<const std::byte*>(buffer), size); +} + +void GFReleaseExCb(void* handle) { + auto* ex = static_cast<GFDataExchanger*>(handle); + ex->CloseWrite(); +} + +GpgData::GpgData() { gpgme_data_t data; auto err = gpgme_data_new(&data); assert(gpgme_err_code(err) == GPG_ERR_NO_ERROR); - data_ref_ = std::unique_ptr<struct gpgme_data, _data_ref_deleter>(data); + data_ref_ = std::unique_ptr<struct gpgme_data, DataRefDeleter>(data); +} + +GpgData::GpgData(GFBuffer buffer) : cached_buffer_(buffer) { + gpgme_data_t data; + + auto err = gpgme_data_new_from_mem( + &data, reinterpret_cast<const char*>(buffer.Data()), buffer.Size(), 0); + assert(gpgme_err_code(err) == GPG_ERR_NO_ERROR); + + data_ref_ = std::unique_ptr<struct gpgme_data, DataRefDeleter>(data); } -GpgFrontend::GpgData::GpgData(void* buffer, size_t size, bool copy) { +GpgData::GpgData(const void* buffer, size_t size, bool copy) { gpgme_data_t data; auto err = gpgme_data_new_from_mem(&data, static_cast<const char*>(buffer), size, copy); assert(gpgme_err_code(err) == GPG_ERR_NO_ERROR); - data_ref_ = std::unique_ptr<struct gpgme_data, _data_ref_deleter>(data); + data_ref_ = std::unique_ptr<struct gpgme_data, DataRefDeleter>(data); } -/** - * Read gpgme-Data to QByteArray - * mainly from http://basket.kde.org/ (kgpgme.cpp) - */ -#define BUF_SIZE (32 * 1024) +GpgData::GpgData(int fd) : fd_(fd), data_cbs_() { + gpgme_data_t data; -GpgFrontend::ByteArrayPtr GpgFrontend::GpgData::Read2Buffer() { + auto err = gpgme_data_new_from_fd(&data, fd_); + assert(gpgme_err_code(err) == GPG_ERR_NO_ERROR); + + data_ref_ = std::unique_ptr<struct gpgme_data, DataRefDeleter>(data); +} + +GpgData::GpgData(const QString& path, bool read) { + gpgme_data_t data; + + // support unicode path + QFile file(path); + file.open(read ? QIODevice::ReadOnly : QIODevice::WriteOnly); + fp_ = fdopen(dup(file.handle()), read ? "rb" : "wb"); + + auto err = gpgme_data_new_from_stream(&data, fp_); + assert(gpgme_err_code(err) == GPG_ERR_NO_ERROR); + + data_ref_ = std::unique_ptr<struct gpgme_data, DataRefDeleter>(data); +} + +GpgData::GpgData(std::shared_ptr<GFDataExchanger> ex) + : data_cbs_(), data_ex_(std::move(ex)) { + gpgme_data_t data; + + data_cbs_.read = GFReadExCb; + data_cbs_.write = GFWriteExCb; + data_cbs_.seek = nullptr; + data_cbs_.release = GFReleaseExCb; + + auto err = gpgme_data_new_from_cbs(&data, &data_cbs_, data_ex_.get()); + assert(gpgme_err_code(err) == GPG_ERR_NO_ERROR); + + data_ref_ = std::unique_ptr<struct gpgme_data, DataRefDeleter>(data); +} + +GpgData::~GpgData() { + if (fp_ != nullptr) { + fclose(fp_); + } + + if (fd_ >= 0) { + close(fd_); + } +} + +auto GpgData::Read2GFBuffer() -> GFBuffer { gpgme_off_t ret = gpgme_data_seek(*this, 0, SEEK_SET); - ByteArrayPtr out_buffer = std::make_unique<std::string>(); + GFBuffer out_buffer; - if (ret) { - gpgme_error_t err = gpgme_err_code_from_errno(errno); + if (ret != 0) { + const GpgError err = gpgme_err_code_from_errno(errno); assert(gpgme_err_code(err) == GPG_ERR_NO_ERROR); } else { - char buf[BUF_SIZE + 2]; + std::array<char, kBufferSize + 2> buf; - while ((ret = gpgme_data_read(*this, buf, BUF_SIZE)) > 0) { - const size_t size = out_buffer->size(); - out_buffer->resize(static_cast<int>(size + ret)); - memcpy(out_buffer->data() + size, buf, ret); + while ((ret = gpgme_data_read(*this, buf.data(), kBufferSize)) > 0) { + out_buffer.Append(buf.data(), ret); } + if (ret < 0) { - gpgme_error_t err = gpgme_err_code_from_errno(errno); + const GpgError err = gpgme_err_code_from_errno(errno); assert(gpgme_err_code(err) == GPG_ERR_NO_ERROR); } } return out_buffer; } -GpgFrontend::GpgData::operator gpgme_data_t() { return data_ref_.get(); }
\ No newline at end of file +GpgData::operator gpgme_data_t() { return data_ref_.get(); } +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/model/GpgData.h b/src/core/model/GpgData.h index 816465d3..358ebd19 100644 --- a/src/core/model/GpgData.h +++ b/src/core/model/GpgData.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,23 +20,27 @@ * 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 _GPGDATA_H -#define _GPGDATA_H +#pragma once -#include "core/GpgConstants.h" +#include "core/GpgFrontendCoreExport.h" +#include "core/model/GFBuffer.h" +#include "core/typedef/CoreTypedef.h" namespace GpgFrontend { + +class GFDataExchanger; + /** * @brief * */ -class GpgData { +class GPGFRONTEND_CORE_EXPORT GpgData { public: /** * @brief Construct a new Gpg Data object @@ -51,7 +55,40 @@ class GpgData { * @param size * @param copy */ - GpgData(void* buffer, size_t size, bool copy = true); + GpgData(const void* buffer, size_t size, bool copy = true); + + /** + * @brief Construct a new Gpg Data object + * + * @param fd + */ + explicit GpgData(int fd); + + /** + * @brief Construct a new Gpg Data object + * + * @param fd + */ + explicit GpgData(std::shared_ptr<GFDataExchanger>); + + /** + * @brief Construct a new Gpg Data object + * + * @param path + */ + explicit GpgData(const QString& path, bool read); + + /** + * @brief Construct a new Gpg Data object + * + */ + explicit GpgData(GFBuffer); + + /** + * @brief Destroy the Gpg Data object + * + */ + ~GpgData(); /** * @brief @@ -65,23 +102,27 @@ class GpgData { * * @return ByteArrayPtr */ - ByteArrayPtr Read2Buffer(); + auto Read2GFBuffer() -> GFBuffer; private: /** * @brief * */ - struct _data_ref_deleter { + struct DataRefDeleter { void operator()(gpgme_data_t _data) { if (_data != nullptr) gpgme_data_release(_data); } }; - std::unique_ptr<struct gpgme_data, _data_ref_deleter> data_ref_ = - nullptr; ///< + GFBuffer cached_buffer_; + + std::unique_ptr<struct gpgme_data, DataRefDeleter> data_ref_ = nullptr; ///< + FILE* fp_ = nullptr; + int fd_ = -1; + + struct gpgme_data_cbs data_cbs_; + std::shared_ptr<GFDataExchanger> data_ex_; }; } // namespace GpgFrontend - -#endif // _GPGDATA_H
\ No newline at end of file diff --git a/src/core/model/GpgDecryptResult.cpp b/src/core/model/GpgDecryptResult.cpp new file mode 100644 index 00000000..3568bfd9 --- /dev/null +++ b/src/core/model/GpgDecryptResult.cpp @@ -0,0 +1,65 @@ +/** + * 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 "GpgDecryptResult.h" + +namespace GpgFrontend { + +GpgDecryptResult::GpgDecryptResult(gpgme_decrypt_result_t r) + : result_ref_(std::shared_ptr<struct _gpgme_op_decrypt_result>( + (gpgme_result_ref(r), r), [](gpgme_decrypt_result_t p) { + if (p != nullptr) { + gpgme_result_unref(p); + } + })) {} + +GpgDecryptResult::GpgDecryptResult() = default; + +GpgDecryptResult::~GpgDecryptResult() = default; + +auto GpgDecryptResult::IsGood() -> bool { return result_ref_ != nullptr; } + +auto GpgDecryptResult::GetRaw() -> gpgme_decrypt_result_t { + return result_ref_.get(); +} + +auto GpgDecryptResult::Recipients() -> std::vector<GpgRecipient> { + std::vector<GpgRecipient> result; + for (auto* reci = result_ref_->recipients; reci != nullptr; + reci = reci->next) { + try { + result.emplace_back(reci); + } catch (...) { + GF_CORE_LOG_ERROR( + "caught exception when processing invalid_recipients, " + "maybe nullptr of fpr"); + } + } + return result; +} +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/model/GpgDecryptResult.h b/src/core/model/GpgDecryptResult.h new file mode 100644 index 00000000..8289d97d --- /dev/null +++ b/src/core/model/GpgDecryptResult.h @@ -0,0 +1,54 @@ +/** + * 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/model/GpgRecipient.h" +#include "core/typedef/GpgTypedef.h" + +namespace GpgFrontend { + +class GPGFRONTEND_CORE_EXPORT GpgDecryptResult { + public: + auto IsGood() -> bool; + + auto GetRaw() -> gpgme_decrypt_result_t; + + auto Recipients() -> std::vector<GpgRecipient>; + + explicit GpgDecryptResult(gpgme_decrypt_result_t); + + GpgDecryptResult(); + + virtual ~GpgDecryptResult(); + + private: + std::shared_ptr<struct _gpgme_op_decrypt_result> result_ref_ = nullptr; ///< +}; + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/model/GpgEncryptResult.cpp b/src/core/model/GpgEncryptResult.cpp new file mode 100644 index 00000000..843cf7eb --- /dev/null +++ b/src/core/model/GpgEncryptResult.cpp @@ -0,0 +1,66 @@ +/** + * 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 "GpgEncryptResult.h" + +namespace GpgFrontend { +GpgEncryptResult::GpgEncryptResult(gpgme_encrypt_result_t r) + : result_ref_(std::shared_ptr<struct _gpgme_op_encrypt_result>( + (gpgme_result_ref(r), r), [](gpgme_encrypt_result_t p) { + if (p != nullptr) { + gpgme_result_unref(p); + } + })) {} + +GpgEncryptResult::GpgEncryptResult() = default; + +GpgEncryptResult::~GpgEncryptResult() = default; + +auto GpgEncryptResult::IsGood() -> bool { return result_ref_ != nullptr; } + +auto GpgEncryptResult::GetRaw() -> gpgme_encrypt_result_t { + return result_ref_.get(); +} + +auto GpgEncryptResult::InvalidRecipients() + -> std::vector<std::tuple<QString, GpgError>> { + std::vector<std::tuple<QString, GpgError>> result; + for (auto* invalid_key = result_ref_->invalid_recipients; + invalid_key != nullptr; invalid_key = invalid_key->next) { + try { + result.emplace_back(QString{invalid_key->fpr}, invalid_key->reason); + } catch (...) { + GF_CORE_LOG_ERROR( + "caught exception when processing invalid_recipients, " + "maybe nullptr of fpr"); + } + } + return result; +} + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/model/GpgEncryptResult.h b/src/core/model/GpgEncryptResult.h new file mode 100644 index 00000000..61fca710 --- /dev/null +++ b/src/core/model/GpgEncryptResult.h @@ -0,0 +1,53 @@ +/** + * 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/typedef/GpgTypedef.h" + +namespace GpgFrontend { + +class GPGFRONTEND_CORE_EXPORT GpgEncryptResult { + public: + auto IsGood() -> bool; + + auto GetRaw() -> gpgme_encrypt_result_t; + + auto InvalidRecipients() -> std::vector<std::tuple<QString, GpgError>>; + + explicit GpgEncryptResult(gpgme_encrypt_result_t); + + GpgEncryptResult(); + + virtual ~GpgEncryptResult(); + + private: + std::shared_ptr<struct _gpgme_op_encrypt_result> result_ref_ = nullptr; ///< +}; + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/model/GpgGenKeyInfo.cpp b/src/core/model/GpgGenKeyInfo.cpp new file mode 100644 index 00000000..d7daa852 --- /dev/null +++ b/src/core/model/GpgGenKeyInfo.cpp @@ -0,0 +1,485 @@ +/** + * 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 "GpgGenKeyInfo.h" + +#include <cassert> + +#include "core/utils/LogUtils.h" + +namespace GpgFrontend { + +void GenKeyInfo::SetAlgo(const QString &t_algo_args) { + auto algo_args = t_algo_args.toLower(); + GF_CORE_LOG_DEBUG("set algo args: {}", algo_args); + + // reset all options + reset_options(); + + if (!this->subkey_) { + this->SetAllowCertification(true); + } else { + this->SetAllowCertification(false); + } + + this->allow_change_certification_ = false; + + if (algo_args == "rsa") { + /** + * RSA is the world’s premier asymmetric cryptographic algorithm, + * and is built on the difficulty of factoring extremely large composites. + * GnuPG supports RSA with key sizes of between 1024 and 4096 bits. + */ + suggest_min_key_size_ = 1024; + suggest_max_key_size_ = 4096; + suggest_size_addition_step_ = 1024; + SetKeyLength(2048); + + } else if (algo_args == "dsa") { + /** + * Algorithm (DSA) as a government standard for digital signatures. + * Originally, it supported key lengths between 512 and 1024 bits. + * Recently, NIST has declared 512-bit keys obsolete: + * now, DSA is available in 1024, 2048 and 3072-bit lengths. + */ + SetAllowEncryption(false); + allow_change_encryption_ = false; + + suggest_min_key_size_ = 1024; + suggest_max_key_size_ = 3072; + suggest_size_addition_step_ = 1024; + SetKeyLength(2048); + + } else if (algo_args == "ed25519") { + /** + * GnuPG supports the Elgamal asymmetric encryption algorithm in key lengths + * ranging from 1024 to 4096 bits. + */ + SetAllowEncryption(false); + allow_change_encryption_ = false; + + suggest_min_key_size_ = -1; + suggest_max_key_size_ = -1; + suggest_size_addition_step_ = -1; + SetKeyLength(-1); + } else if (algo_args == "cv25519" || algo_args == "nistp256" || + algo_args == "nistp384" || algo_args == "nistp521" || + algo_args == "brainpoolp256r1" || algo_args == "brainpoolp384r1" || + algo_args == "brainpoolp512r1") { + SetAllowAuthentication(false); + allow_change_authentication_ = false; + + SetAllowSigning(false); + allow_change_signing_ = false; + + SetAllowCertification(false); + allow_change_certification_ = false; + + suggest_min_key_size_ = -1; + suggest_max_key_size_ = -1; + suggest_size_addition_step_ = -1; + SetKeyLength(-1); + } else { + SPDLOG_ERROR("unsupported genkey algo arguments: {}", algo_args); + return; + } + + this->algo_ = algo_args; +} + +void GenKeyInfo::reset_options() { + allow_change_encryption_ = true; + SetAllowEncryption(true); + + allow_change_certification_ = true; + SetAllowCertification(true); + + allow_change_signing_ = true; + SetAllowSigning(true); + + allow_change_authentication_ = true; + SetAllowAuthentication(true); + + passphrase_.clear(); +} + +auto GenKeyInfo::GetKeySizeStr() const -> QString { + if (key_size_ > 0) { + return QString::number(key_size_); + } + return {}; +} + +void GenKeyInfo::SetKeyLength(int m_key_size) { + if (m_key_size < suggest_min_key_size_ || + m_key_size > suggest_max_key_size_) { + return; + } + GenKeyInfo::key_size_ = m_key_size; +} + +void GenKeyInfo::SetExpireTime(const QDateTime &m_expired) { + if (!IsNonExpired()) { + GenKeyInfo::expired_ = m_expired; + } +} + +void GenKeyInfo::SetNonExpired(bool m_non_expired) { + if (!m_non_expired) this->expired_ = QDateTime::fromSecsSinceEpoch(0); + GenKeyInfo::non_expired_ = m_non_expired; +} + +void GenKeyInfo::SetAllowEncryption(bool m_allow_encryption) { + if (allow_change_encryption_) { + GenKeyInfo::allow_encryption_ = m_allow_encryption; + } +} + +void GenKeyInfo::SetAllowCertification(bool m_allow_certification) { + if (allow_change_certification_) { + GenKeyInfo::allow_certification_ = m_allow_certification; + } +} + +GenKeyInfo::GenKeyInfo(bool m_is_sub_key) : subkey_(m_is_sub_key) { + assert(!GetSupportedKeyAlgo().empty()); + SetAlgo(std::get<0>(GetSupportedKeyAlgo()[0])); +} + +auto GenKeyInfo::GetSupportedKeyAlgo() + -> const std::vector<GenKeyInfo::KeyGenAlgo> & { + static const std::vector<GenKeyInfo::KeyGenAlgo> kSupportKeyAlgo = { + {"RSA", "RSA", ""}, + {"DSA", "DSA", ""}, + {"ECDSA", "ED25519", ""}, + {"ECDSA + ECDH", "ED25519", "CV25519"}, + {"ECDSA + ECDH NIST P-256", "ED25519", "NISTP256"}, + {"ECDSA + ECDH BrainPooL P-256", "ED25519", "BRAINPOOLP256R1"}, + }; + return kSupportKeyAlgo; +} + +auto GenKeyInfo::GetSupportedSubkeyAlgo() + -> const std::vector<GenKeyInfo::KeyGenAlgo> & { + static const std::vector<GenKeyInfo::KeyGenAlgo> kSupportSubkeyAlgo = { + {"RSA", "", "RSA"}, + {"DSA", "", "DSA"}, + {"ECDSA", "", "ED25519"}, + {"ECDH", "", "CV25519"}, + {"ECDH NIST P-256", "", "NISTP256"}, + {"ECDH NIST P-384", "", "NISTP384"}, + {"ECDH NIST P-521", "", "NISTP521"}, + {"ECDH BrainPooL P-256", "", "BRAINPOOLP256R1"}, + {"ECDH BrainPooL P-384", "", "BRAINPOOLP384R1"}, + {"ECDH BrainPooL P-512", "", "BRAINPOOLP512R1"}}; + + return kSupportSubkeyAlgo; +} + +/** + * @brief + * + * @return true + * @return false + */ +[[nodiscard]] auto GenKeyInfo::IsSubKey() const -> bool { return subkey_; } + +/** + * @brief Set the Is Sub Key object + * + * @param m_sub_key + */ +void GenKeyInfo::SetIsSubKey(bool m_sub_key) { + GenKeyInfo::subkey_ = m_sub_key; +} + +/** + * @brief Get the Userid object + * + * @return QString + */ +[[nodiscard]] auto GenKeyInfo::GetUserid() const -> QString { + return QString("%1(%2)<%3>").arg(name_).arg(comment_).arg(email_); +} + +/** + * @brief Set the Name object + * + * @param m_name + */ +void GenKeyInfo::SetName(const QString &m_name) { this->name_ = m_name; } + +/** + * @brief Set the Email object + * + * @param m_email + */ +void GenKeyInfo::SetEmail(const QString &m_email) { this->email_ = m_email; } + +/** + * @brief Set the Comment object + * + * @param m_comment + */ +void GenKeyInfo::SetComment(const QString &m_comment) { + this->comment_ = m_comment; +} + +/** + * @brief Get the Name object + * + * @return QString + */ +[[nodiscard]] auto GenKeyInfo::GetName() const -> QString { return name_; } + +/** + * @brief Get the Email object + * + * @return QString + */ +[[nodiscard]] auto GenKeyInfo::GetEmail() const -> QString { return email_; } + +/** + * @brief Get the Comment object + * + * @return QString + */ +[[nodiscard]] auto GenKeyInfo::GetComment() const -> QString { + return comment_; +} + +/** + * @brief Get the Algo object + * + * @return const QString& + */ +[[nodiscard]] auto GenKeyInfo::GetAlgo() const -> const QString & { + return algo_; +} + +/** + * @brief Get the Key Size object + * + * @return int + */ +[[nodiscard]] auto GenKeyInfo::GetKeyLength() const -> int { return key_size_; } + +/** + * @brief Get the Expired object + * + * @return const QDateTime& + */ +[[nodiscard]] auto GenKeyInfo::GetExpireTime() const -> const QDateTime & { + return expired_; +} + +/** + * @brief + * + * @return true + * @return false + */ +[[nodiscard]] auto GenKeyInfo::IsNonExpired() const -> bool { + return non_expired_; +} + +/** + * @brief + * + * @return true + * @return false + */ +[[nodiscard]] auto GenKeyInfo::IsNoPassPhrase() const -> bool { + return this->no_passphrase_; +} + +/** + * @brief Set the Non Pass Phrase object + * + * @param m_non_pass_phrase + */ +void GenKeyInfo::SetNonPassPhrase(bool m_non_pass_phrase) { + GenKeyInfo::no_passphrase_ = m_non_pass_phrase; +} + +/** + * @brief + * + * @return true + * @return false + */ +[[nodiscard]] auto GenKeyInfo::IsAllowSigning() const -> bool { + return allow_signing_; +} + +/** + * @brief + * + * @return true + * @return false + */ +[[nodiscard]] auto GenKeyInfo::IsAllowNoPassPhrase() const -> bool { + return allow_no_pass_phrase_; +} + +/** + * @brief Set the Allow Signing object + * + * @param m_allow_signing + */ +void GenKeyInfo::SetAllowSigning(bool m_allow_signing) { + if (allow_change_signing_) GenKeyInfo::allow_signing_ = m_allow_signing; +} + +/** + * @brief + * + * @return true + * @return false + */ +[[nodiscard]] auto GenKeyInfo::IsAllowEncryption() const -> bool { + return allow_encryption_; +} + +/** + * @brief + * + * @return true + * @return false + */ +[[nodiscard]] auto GenKeyInfo::IsAllowCertification() const -> bool { + return allow_certification_; +} + +/** + * @brief + * + * @return true + * @return false + */ +[[nodiscard]] auto GenKeyInfo::IsAllowAuthentication() const -> bool { + return allow_authentication_; +} + +/** + * @brief Set the Allow Authentication object + * + * @param m_allow_authentication + */ +void GenKeyInfo::SetAllowAuthentication(bool m_allow_authentication) { + if (allow_change_authentication_) { + GenKeyInfo::allow_authentication_ = m_allow_authentication; + } +} + +/** + * @brief Get the Pass Phrase object + * + * @return const QString& + */ +[[nodiscard]] auto GenKeyInfo::GetPassPhrase() const -> const QString & { + return passphrase_; +} + +/** + * @brief Set the Pass Phrase object + * + * @param m_pass_phrase + */ +void GenKeyInfo::SetPassPhrase(const QString &m_pass_phrase) { + GenKeyInfo::passphrase_ = m_pass_phrase; +} + +/** + * @brief + * + * @return true + * @return false + */ +[[nodiscard]] auto GenKeyInfo::IsAllowChangeSigning() const -> bool { + return allow_change_signing_; +} + +/** + * @brief + * + * @return true + * @return false + */ +[[nodiscard]] auto GenKeyInfo::IsAllowChangeEncryption() const -> bool { + return allow_change_encryption_; +} + +/** + * @brief + * + * @return true + * @return false + */ +[[nodiscard]] auto GenKeyInfo::IsAllowChangeCertification() const -> bool { + return allow_change_certification_; +} + +/** + * @brief + * + * @return true + * @return false + */ +[[nodiscard]] auto GenKeyInfo::IsAllowChangeAuthentication() const -> bool { + return allow_change_authentication_; +} + +/** + * @brief Get the Suggest Max Key Size object + * + * @return int + */ +[[nodiscard]] auto GenKeyInfo::GetSuggestMaxKeySize() const -> int { + return suggest_max_key_size_; +} + +/** + * @brief Get the Suggest Min Key Size object + * + * @return int + */ +[[nodiscard]] auto GenKeyInfo::GetSuggestMinKeySize() const -> int { + return suggest_min_key_size_; +} + +/** + * @brief Get the Size Change Step object + * + * @return int + */ +[[nodiscard]] auto GenKeyInfo::GetSizeChangeStep() const -> int { + return suggest_size_addition_step_; +} + +} // namespace GpgFrontend diff --git a/src/core/GpgGenKeyInfo.h b/src/core/model/GpgGenKeyInfo.h index d47b803e..166c6b0f 100644 --- a/src/core/GpgGenKeyInfo.h +++ b/src/core/model/GpgGenKeyInfo.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,78 +20,41 @@ * 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_GPGGENKEYINFO_H -#define GPGFRONTEND_GPGGENKEYINFO_H - -#include <boost/date_time.hpp> -#include <boost/date_time/gregorian/greg_duration_types.hpp> -#include <boost/format.hpp> -#include <string> -#include <vector> - -#include "GpgFrontend.h" +#pragma once namespace GpgFrontend { class GPGFRONTEND_CORE_EXPORT GenKeyInfo { - bool standalone_ = false; ///< - bool subkey_ = false; ///< - std::string name_; ///< - std::string email_; ///< - std::string comment_; ///< - - std::string algo_; ///< - int key_size_ = 2048; - boost::posix_time::ptime expired_ = - boost::posix_time::second_clock::local_time() + - boost::gregorian::years(2); ///< - bool non_expired_ = false; ///< - - bool no_passphrase_ = false; ///< - bool allow_no_pass_phrase_ = true; ///< - - int suggest_max_key_size_ = 4096; ///< - int suggest_size_addition_step_ = 1024; ///< - int suggest_min_key_size_ = 1024; ///< - - std::string passphrase_; ///< - - using KeyGenAlgo = std::pair<std::string, std::string>; - public: - /** - * @brief Get the Supported Key Algo object - * - * @return const std::vector<std::string>& - */ - static const std::vector<KeyGenAlgo> &GetSupportedKeyAlgo(); + using KeyGenAlgo = std::tuple<QString, QString, QString>; /** - * @brief Get the Supported Subkey Algo object + * @brief Construct a new Gen Key Info object * - * @return const std::vector<std::string>& + * @param m_is_sub_key + * @param m_standalone */ - static const std::vector<KeyGenAlgo> &GetSupportedSubkeyAlgo(); + explicit GenKeyInfo(bool m_is_sub_key = false); /** - * @brief Get the Supported Key Algo Standalone object + * @brief Get the Supported Key Algo object * - * @return const std::vector<std::string>& + * @return const std::vector<QString>& */ - static const std::vector<KeyGenAlgo> &GetSupportedKeyAlgoStandalone(); + static auto GetSupportedKeyAlgo() -> const std::vector<KeyGenAlgo> &; /** - * @brief Get the Supported Subkey Algo Standalone object + * @brief Get the Supported Subkey Algo object * - * @return const std::vector<std::string>& + * @return const std::vector<QString>& */ - static const std::vector<KeyGenAlgo> &GetSupportedSubkeyAlgoStandalone(); + static auto GetSupportedSubkeyAlgo() -> const std::vector<KeyGenAlgo> &; /** * @brief @@ -99,95 +62,91 @@ class GPGFRONTEND_CORE_EXPORT GenKeyInfo { * @return true * @return false */ - [[nodiscard]] bool IsSubKey() const { return subkey_; } + [[nodiscard]] auto IsSubKey() const -> bool; /** * @brief Set the Is Sub Key object * * @param m_sub_key */ - void SetIsSubKey(bool m_sub_key) { GenKeyInfo::subkey_ = m_sub_key; } + void SetIsSubKey(bool m_sub_key); /** * @brief Get the Userid object * - * @return std::string + * @return QString */ - [[nodiscard]] std::string GetUserid() const { - auto uid_format = boost::format("%1%(%2%)<%3%>") % this->name_ % - this->comment_ % this->email_; - return uid_format.str(); - } + [[nodiscard]] auto GetUserid() const -> QString; /** * @brief Set the Name object * * @param m_name */ - void SetName(const std::string &m_name) { this->name_ = m_name; } + void SetName(const QString &m_name); /** * @brief Set the Email object * * @param m_email */ - void SetEmail(const std::string &m_email) { this->email_ = m_email; } + void SetEmail(const QString &m_email); /** * @brief Set the Comment object * * @param m_comment */ - void SetComment(const std::string &m_comment) { this->comment_ = m_comment; } + void SetComment(const QString &m_comment); /** * @brief Get the Name object * - * @return std::string + * @return QString */ - [[nodiscard]] std::string GetName() const { return name_; } + [[nodiscard]] auto GetName() const -> QString; /** * @brief Get the Email object * - * @return std::string + * @return QString */ - [[nodiscard]] std::string GetEmail() const { return email_; } + [[nodiscard]] auto GetEmail() const -> QString; /** * @brief Get the Comment object * - * @return std::string + * @return QString */ - [[nodiscard]] std::string GetComment() const { return comment_; } + [[nodiscard]] auto GetComment() const -> QString; /** * @brief Get the Algo object * - * @return const std::string& + * @return const QString& */ - [[nodiscard]] const std::string &GetAlgo() const { return algo_; } + [[nodiscard]] auto GetAlgo() const -> const QString &; /** * @brief Set the Algo object * * @param m_algo */ - void SetAlgo(const GpgFrontend::GenKeyInfo::KeyGenAlgo &m_algo); + void SetAlgo(const QString &); /** * @brief Get the Key Size Str object * - * @return std::string + * @return QString */ - [[nodiscard]] std::string GetKeySizeStr() const; + [[nodiscard]] auto GetKeySizeStr() const -> QString; /** * @brief Get the Key Size object * * @return int */ - [[nodiscard]] int GetKeyLength() const { return key_size_; } + [[nodiscard]] auto GetKeyLength() const -> int; /** * @brief Set the Key Size object @@ -199,18 +158,16 @@ class GPGFRONTEND_CORE_EXPORT GenKeyInfo { /** * @brief Get the Expired object * - * @return const boost::posix_time::ptime& + * @return const QDateTime& */ - [[nodiscard]] const boost::posix_time::ptime &GetExpireTime() const { - return expired_; - } + [[nodiscard]] auto GetExpireTime() const -> const QDateTime &; /** * @brief Set the Expired object * * @param m_expired */ - void SetExpireTime(const boost::posix_time::ptime &m_expired); + void SetExpireTime(const QDateTime &m_expired); /** * @brief @@ -218,7 +175,7 @@ class GPGFRONTEND_CORE_EXPORT GenKeyInfo { * @return true * @return false */ - [[nodiscard]] bool IsNonExpired() const { return non_expired_; } + [[nodiscard]] auto IsNonExpired() const -> bool; /** * @brief Set the Non Expired object @@ -233,16 +190,14 @@ class GPGFRONTEND_CORE_EXPORT GenKeyInfo { * @return true * @return false */ - [[nodiscard]] bool IsNoPassPhrase() const { return this->no_passphrase_; } + [[nodiscard]] auto IsNoPassPhrase() const -> bool; /** * @brief Set the Non Pass Phrase object * * @param m_non_pass_phrase */ - void SetNonPassPhrase(bool m_non_pass_phrase) { - GenKeyInfo::no_passphrase_ = m_non_pass_phrase; - } + void SetNonPassPhrase(bool m_non_pass_phrase); /** * @brief @@ -250,7 +205,7 @@ class GPGFRONTEND_CORE_EXPORT GenKeyInfo { * @return true * @return false */ - [[nodiscard]] bool IsAllowSigning() const { return allow_signing_; } + [[nodiscard]] auto IsAllowSigning() const -> bool; /** * @brief @@ -258,18 +213,14 @@ class GPGFRONTEND_CORE_EXPORT GenKeyInfo { * @return true * @return false */ - [[nodiscard]] bool IsAllowNoPassPhrase() const { - return allow_no_pass_phrase_; - } + [[nodiscard]] auto IsAllowNoPassPhrase() const -> bool; /** * @brief Set the Allow Signing object * * @param m_allow_signing */ - void SetAllowSigning(bool m_allow_signing) { - if (allow_change_signing_) GenKeyInfo::allow_signing_ = m_allow_signing; - } + void SetAllowSigning(bool m_allow_signing); /** * @brief @@ -277,7 +228,7 @@ class GPGFRONTEND_CORE_EXPORT GenKeyInfo { * @return true * @return false */ - [[nodiscard]] bool IsAllowEncryption() const { return allow_encryption_; } + [[nodiscard]] auto IsAllowEncryption() const -> bool; /** * @brief Set the Allow Encryption object @@ -292,9 +243,7 @@ class GPGFRONTEND_CORE_EXPORT GenKeyInfo { * @return true * @return false */ - [[nodiscard]] bool IsAllowCertification() const { - return allow_certification_; - } + [[nodiscard]] auto IsAllowCertification() const -> bool; /** * @brief Set the Allow Certification object @@ -309,35 +258,28 @@ class GPGFRONTEND_CORE_EXPORT GenKeyInfo { * @return true * @return false */ - [[nodiscard]] bool IsAllowAuthentication() const { - return allow_authentication_; - } + [[nodiscard]] auto IsAllowAuthentication() const -> bool; /** * @brief Set the Allow Authentication object * * @param m_allow_authentication */ - void SetAllowAuthentication(bool m_allow_authentication) { - if (allow_change_authentication_) - GenKeyInfo::allow_authentication_ = m_allow_authentication; - } + void SetAllowAuthentication(bool m_allow_authentication); /** * @brief Get the Pass Phrase object * - * @return const std::string& + * @return const QString& */ - [[nodiscard]] const std::string &GetPassPhrase() const { return passphrase_; } + [[nodiscard]] auto GetPassPhrase() const -> const QString &; /** * @brief Set the Pass Phrase object * * @param m_pass_phrase */ - void SetPassPhrase(const std::string &m_pass_phrase) { - GenKeyInfo::passphrase_ = m_pass_phrase; - } + void SetPassPhrase(const QString &m_pass_phrase); /** * @brief @@ -345,9 +287,7 @@ class GPGFRONTEND_CORE_EXPORT GenKeyInfo { * @return true * @return false */ - [[nodiscard]] bool IsAllowChangeSigning() const { - return allow_change_signing_; - } + [[nodiscard]] auto IsAllowChangeSigning() const -> bool; /** * @brief @@ -355,9 +295,7 @@ class GPGFRONTEND_CORE_EXPORT GenKeyInfo { * @return true * @return false */ - [[nodiscard]] bool IsAllowChangeEncryption() const { - return allow_change_encryption_; - } + [[nodiscard]] auto IsAllowChangeEncryption() const -> bool; /** * @brief @@ -365,9 +303,7 @@ class GPGFRONTEND_CORE_EXPORT GenKeyInfo { * @return true * @return false */ - [[nodiscard]] bool IsAllowChangeCertification() const { - return allow_change_certification_; - } + [[nodiscard]] auto IsAllowChangeCertification() const -> bool; /** * @brief @@ -375,38 +311,49 @@ class GPGFRONTEND_CORE_EXPORT GenKeyInfo { * @return true * @return false */ - [[nodiscard]] bool IsAllowChangeAuthentication() const { - return allow_change_authentication_; - } + [[nodiscard]] auto IsAllowChangeAuthentication() const -> bool; /** * @brief Get the Suggest Max Key Size object * * @return int */ - [[nodiscard]] int GetSuggestMaxKeySize() const { - return suggest_max_key_size_; - } + [[nodiscard]] auto GetSuggestMaxKeySize() const -> int; /** * @brief Get the Suggest Min Key Size object * * @return int */ - [[nodiscard]] int GetSuggestMinKeySize() const { - return suggest_min_key_size_; - } + [[nodiscard]] auto GetSuggestMinKeySize() const -> int; /** * @brief Get the Size Change Step object * * @return int */ - [[nodiscard]] int GetSizeChangeStep() const { - return suggest_size_addition_step_; - } + [[nodiscard]] auto GetSizeChangeStep() const -> int; private: + bool subkey_ = false; ///< + QString name_; ///< + QString email_; ///< + QString comment_; ///< + + QString algo_; ///< + int key_size_ = 2048; + QDateTime expired_ = QDateTime::currentDateTime().addYears(2); + bool non_expired_ = false; ///< + + bool no_passphrase_ = false; ///< + bool allow_no_pass_phrase_ = true; ///< + + int suggest_max_key_size_ = 4096; ///< + int suggest_size_addition_step_ = 1024; ///< + int suggest_min_key_size_ = 1024; ///< + + QString passphrase_; ///< + bool allow_encryption_ = true; ///< bool allow_change_encryption_ = true; ///< bool allow_certification_ = true; ///< @@ -421,17 +368,6 @@ class GPGFRONTEND_CORE_EXPORT GenKeyInfo { * */ void reset_options(); - - public: - /** - * @brief Construct a new Gen Key Info object - * - * @param m_is_sub_key - * @param m_standalone - */ - explicit GenKeyInfo(bool m_is_sub_key = false, bool m_standalone = false); }; } // namespace GpgFrontend - -#endif // GPGFRONTEND_GPGGENKEYINFO_H diff --git a/src/core/model/GpgGenerateKeyResult.cpp b/src/core/model/GpgGenerateKeyResult.cpp new file mode 100644 index 00000000..f7ebf14e --- /dev/null +++ b/src/core/model/GpgGenerateKeyResult.cpp @@ -0,0 +1,59 @@ +/** + * 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 "GpgGenerateKeyResult.h" + +#include <gpgme.h> + +namespace GpgFrontend { + +GpgGenerateKeyResult::GpgGenerateKeyResult(gpgme_genkey_result_t r) + : result_ref_(std::shared_ptr<struct _gpgme_op_genkey_result>( + (gpgme_result_ref(r), r), [](gpgme_genkey_result_t p) { + if (p != nullptr) { + gpgme_result_unref(p); + } + })) {} + +auto GpgGenerateKeyResult::IsGood() -> bool { return result_ref_ != nullptr; } + +auto GpgGenerateKeyResult::GetFingerprint() -> QString const { + return result_ref_->fpr; +} + +GpgGenerateKeyResult::GpgGenerateKeyResult() = default; + +GpgGenerateKeyResult::GpgGenerateKeyResult(const GpgGenerateKeyResult &) = + default; + +auto GpgGenerateKeyResult::operator=(const GpgGenerateKeyResult &) + -> GpgGenerateKeyResult & = default; + +GpgGenerateKeyResult::~GpgGenerateKeyResult() = default; + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/model/GpgGenerateKeyResult.h b/src/core/model/GpgGenerateKeyResult.h new file mode 100644 index 00000000..f312d415 --- /dev/null +++ b/src/core/model/GpgGenerateKeyResult.h @@ -0,0 +1,59 @@ +/** + * 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/GpgFrontendCore.h" +#include "core/GpgFrontendCoreExport.h" + +namespace GpgFrontend { + +class GPGFRONTEND_CORE_EXPORT GpgGenerateKeyResult { + public: + auto IsGood() -> bool; + + auto GetFingerprint() -> QString const; + + explicit GpgGenerateKeyResult(gpgme_genkey_result_t); + + GpgGenerateKeyResult(); + + GpgGenerateKeyResult(const GpgGenerateKeyResult &); + + auto operator=(const GpgGenerateKeyResult &) -> GpgGenerateKeyResult &; + + virtual ~GpgGenerateKeyResult(); + + private: + using ResultRefHandler = + std::shared_ptr<struct _gpgme_op_genkey_result>; ///< + + ResultRefHandler result_ref_ = nullptr; ///< +}; + +} // namespace GpgFrontend diff --git a/src/core/model/GpgImportInformation.cpp b/src/core/model/GpgImportInformation.cpp new file mode 100644 index 00000000..cda146de --- /dev/null +++ b/src/core/model/GpgImportInformation.cpp @@ -0,0 +1,54 @@ +/** + * 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 "GpgImportInformation.h" + +namespace GpgFrontend { + +GpgImportInformation::GpgImportInformation() = default; + +GpgImportInformation::GpgImportInformation(gpgme_import_result_t result) { + if (result->unchanged != 0) unchanged = result->unchanged; + if (result->considered != 0) considered = result->considered; + if (result->no_user_id != 0) no_user_id = result->no_user_id; + if (result->imported != 0) imported = result->imported; + if (result->imported_rsa != 0) imported_rsa = result->imported_rsa; + if (result->unchanged != 0) unchanged = result->unchanged; + if (result->new_user_ids != 0) new_user_ids = result->new_user_ids; + if (result->new_sub_keys != 0) new_sub_keys = result->new_sub_keys; + if (result->new_signatures != 0) new_signatures = result->new_signatures; + if (result->new_revocations != 0) new_revocations = result->new_revocations; + if (result->secret_read != 0) secret_read = result->secret_read; + if (result->secret_imported != 0) secret_imported = result->secret_imported; + if (result->secret_unchanged != 0) { + secret_unchanged = result->secret_unchanged; + } + if (result->not_imported != 0) not_imported = result->not_imported; +} + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/model/GpgImportInformation.h b/src/core/model/GpgImportInformation.h new file mode 100644 index 00000000..5f85a338 --- /dev/null +++ b/src/core/model/GpgImportInformation.h @@ -0,0 +1,80 @@ +/** + * 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 + +namespace GpgFrontend { + +/** + * @brief + * + */ +class GPGFRONTEND_CORE_EXPORT GpgImportInformation { + public: + /** + * @brief + * + */ + class GpgImportedKey { + public: + QString fpr; ///< + int import_status; ///< + }; + + using GpgImportedKeyList = std::list<GpgImportedKey>; ///< + + /** + * @brief Construct a new Gpg Import Information object + * + */ + 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 imported_keys; ///< +}; +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/model/GpgKey.cpp b/src/core/model/GpgKey.cpp index 3a167b81..53842249 100644 --- a/src/core/model/GpgKey.cpp +++ b/src/core/model/GpgKey.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 * @@ -30,70 +30,80 @@ #include <mutex> -GpgFrontend::GpgKey::GpgKey(gpgme_key_t &&key) : key_ref_(std::move(key)) {} +namespace GpgFrontend { -GpgFrontend::GpgKey::GpgKey(GpgKey &&k) noexcept { swap(key_ref_, k.key_ref_); } +GpgKey::GpgKey(gpgme_key_t &&key) : key_ref_(key) {} -GpgFrontend::GpgKey &GpgFrontend::GpgKey::operator=(GpgKey &&k) noexcept { +GpgKey::GpgKey(GpgKey &&k) noexcept { swap(key_ref_, k.key_ref_); } + +auto GpgKey::operator=(GpgKey &&k) noexcept -> GpgKey & { swap(key_ref_, k.key_ref_); return *this; } -bool GpgFrontend::GpgKey::operator==(const GpgKey &o) const { +GpgKey::GpgKey(const GpgKey &key) { + auto *key_ref = key.key_ref_.get(); + gpgme_key_ref(key_ref); + this->key_ref_ = KeyRefHandler(key_ref); +} + +auto GpgKey::operator=(const GpgKey &key) -> GpgKey & { + if (this == &key) { + return *this; + } + + auto *key_ref = key.key_ref_.get(); + gpgme_key_ref(key_ref); + + this->key_ref_ = KeyRefHandler(key_ref); + return *this; +} + +auto GpgKey::operator==(const GpgKey &o) const -> bool { return o.GetId() == this->GetId(); } -bool GpgFrontend::GpgKey::operator<=(const GpgKey &o) const { +auto GpgKey::operator<=(const GpgKey &o) const -> bool { return this->GetId() < o.GetId(); } -GpgFrontend::GpgKey::operator gpgme_key_t() const { return key_ref_.get(); } +GpgKey::operator gpgme_key_t() const { return key_ref_.get(); } -bool GpgFrontend::GpgKey::IsGood() const { return key_ref_ != nullptr; } +auto GpgKey::IsGood() const -> bool { return key_ref_ != nullptr; } -std::string GpgFrontend::GpgKey::GetId() const { - return key_ref_->subkeys->keyid; -} +auto GpgKey::GetId() const -> QString { return key_ref_->subkeys->keyid; } -std::string GpgFrontend::GpgKey::GetName() const { - return key_ref_->uids->name; -}; +auto GpgKey::GetName() const -> QString { return key_ref_->uids->name; }; -std::string GpgFrontend::GpgKey::GetEmail() const { - return key_ref_->uids->email; -} +auto GpgKey::GetEmail() const -> QString { return key_ref_->uids->email; } -std::string GpgFrontend::GpgKey::GetComment() const { - return key_ref_->uids->comment; -} +auto GpgKey::GetComment() const -> QString { return key_ref_->uids->comment; } -std::string GpgFrontend::GpgKey::GetFingerprint() const { - return key_ref_->fpr; -} +auto GpgKey::GetFingerprint() const -> QString { return key_ref_->fpr; } -std::string GpgFrontend::GpgKey::GetProtocol() const { +auto GpgKey::GetProtocol() const -> QString { return gpgme_get_protocol_name(key_ref_->protocol); } -std::string GpgFrontend::GpgKey::GetOwnerTrust() const { +auto GpgKey::GetOwnerTrust() const -> QString { switch (key_ref_->owner_trust) { case GPGME_VALIDITY_UNKNOWN: - return _("Unknown"); + return tr("Unknown"); case GPGME_VALIDITY_UNDEFINED: - return _("Undefined"); + return tr("Undefined"); case GPGME_VALIDITY_NEVER: - return _("Never"); + return tr("Never"); case GPGME_VALIDITY_MARGINAL: - return _("Marginal"); + return tr("Marginal"); case GPGME_VALIDITY_FULL: - return _("Full"); + return tr("Full"); case GPGME_VALIDITY_ULTIMATE: - return _("Ultimate"); + return tr("Ultimate"); } return "Invalid"; } -int GpgFrontend::GpgKey::GetOwnerTrustLevel() const { +auto GpgKey::GetOwnerTrustLevel() const -> int { switch (key_ref_->owner_trust) { case GPGME_VALIDITY_UNKNOWN: return 0; @@ -111,66 +121,72 @@ int GpgFrontend::GpgKey::GetOwnerTrustLevel() const { return 0; } -std::string GpgFrontend::GpgKey::GetPublicKeyAlgo() const { +auto GpgKey::GetPublicKeyAlgo() const -> QString { return gpgme_pubkey_algo_name(key_ref_->subkeys->pubkey_algo); } -boost::posix_time::ptime GpgFrontend::GpgKey::GetLastUpdateTime() const { - return boost::posix_time::from_time_t( +auto GpgKey::GetKeyAlgo() const -> QString { + auto *buffer = gpgme_pubkey_algo_string(key_ref_->subkeys); + auto algo = QString(buffer); + gpgme_free(buffer); + return algo.toUpper(); +} + +auto GpgKey::GetLastUpdateTime() const -> QDateTime { + return QDateTime::fromSecsSinceEpoch( static_cast<time_t>(key_ref_->last_update)); } -boost::posix_time::ptime GpgFrontend::GpgKey::GetExpireTime() const { - return boost::posix_time::from_time_t(key_ref_->subkeys->expires); +auto GpgKey::GetExpireTime() const -> QDateTime { + return QDateTime::fromSecsSinceEpoch(key_ref_->subkeys->expires); }; -boost::posix_time::ptime GpgFrontend::GpgKey::GetCreateTime() const { - return boost::posix_time::from_time_t(key_ref_->subkeys->timestamp); +auto GpgKey::GetCreateTime() const -> QDateTime { + return QDateTime::fromSecsSinceEpoch(key_ref_->subkeys->timestamp); }; -unsigned int GpgFrontend::GpgKey::GetPrimaryKeyLength() const { +auto GpgKey::GetPrimaryKeyLength() const -> unsigned int { return key_ref_->subkeys->length; } -bool GpgFrontend::GpgKey::IsHasEncryptionCapability() const { +auto GpgKey::IsHasEncryptionCapability() const -> bool { return key_ref_->can_encrypt; } -bool GpgFrontend::GpgKey::IsHasSigningCapability() const { +auto GpgKey::IsHasSigningCapability() const -> bool { return key_ref_->can_sign; } -bool GpgFrontend::GpgKey::IsHasCertificationCapability() const { +auto GpgKey::IsHasCertificationCapability() const -> bool { return key_ref_->can_certify; } -bool GpgFrontend::GpgKey::IsHasAuthenticationCapability() const { +auto GpgKey::IsHasAuthenticationCapability() const -> bool { return key_ref_->can_authenticate; } -bool GpgFrontend::GpgKey::IsHasCardKey() const { +auto GpgKey::IsHasCardKey() const -> bool { auto subkeys = GetSubKeys(); return std::any_of( subkeys->begin(), subkeys->end(), [](const GpgSubKey &subkey) -> bool { return subkey.IsCardKey(); }); } -bool GpgFrontend::GpgKey::IsPrivateKey() const { return key_ref_->secret; } +auto GpgKey::IsPrivateKey() const -> bool { return key_ref_->secret; } -bool GpgFrontend::GpgKey::IsExpired() const { return key_ref_->expired; } +auto GpgKey::IsExpired() const -> bool { return key_ref_->expired; } -bool GpgFrontend::GpgKey::IsRevoked() const { return key_ref_->revoked; } +auto GpgKey::IsRevoked() const -> bool { return key_ref_->revoked; } -bool GpgFrontend::GpgKey::IsDisabled() const { return key_ref_->disabled; } +auto GpgKey::IsDisabled() const -> bool { return key_ref_->disabled; } -bool GpgFrontend::GpgKey::IsHasMasterKey() const { +auto GpgKey::IsHasMasterKey() const -> bool { return key_ref_->subkeys->secret; } -std::unique_ptr<std::vector<GpgFrontend::GpgSubKey>> -GpgFrontend::GpgKey::GetSubKeys() const { +auto GpgKey::GetSubKeys() const -> std::unique_ptr<std::vector<GpgSubKey>> { auto p_keys = std::make_unique<std::vector<GpgSubKey>>(); - auto next = key_ref_->subkeys; + auto *next = key_ref_->subkeys; while (next != nullptr) { p_keys->push_back(GpgSubKey(next)); next = next->next; @@ -178,10 +194,9 @@ GpgFrontend::GpgKey::GetSubKeys() const { return p_keys; } -std::unique_ptr<std::vector<GpgFrontend::GpgUID>> GpgFrontend::GpgKey::GetUIDs() - const { +auto GpgKey::GetUIDs() const -> std::unique_ptr<std::vector<GpgUID>> { auto p_uids = std::make_unique<std::vector<GpgUID>>(); - auto uid_next = key_ref_->uids; + auto *uid_next = key_ref_->uids; while (uid_next != nullptr) { p_uids->push_back(GpgUID(uid_next)); uid_next = uid_next->next; @@ -189,32 +204,24 @@ std::unique_ptr<std::vector<GpgFrontend::GpgUID>> GpgFrontend::GpgKey::GetUIDs() return p_uids; } -bool GpgFrontend::GpgKey::IsHasActualSigningCapability() const { +auto GpgKey::IsHasActualSigningCapability() const -> bool { auto subkeys = GetSubKeys(); - if (std::any_of(subkeys->begin(), subkeys->end(), - [](const GpgSubKey &subkey) -> bool { - return subkey.IsSecretKey() && - subkey.IsHasSigningCapability() && - !subkey.IsDisabled() && !subkey.IsRevoked() && - !subkey.IsExpired(); - })) - return true; - else - return false; + return std::any_of( + subkeys->begin(), subkeys->end(), [](const GpgSubKey &subkey) -> bool { + return subkey.IsSecretKey() && subkey.IsHasSigningCapability() && + !subkey.IsDisabled() && !subkey.IsRevoked() && + !subkey.IsExpired(); + }); } -bool GpgFrontend::GpgKey::IsHasActualAuthenticationCapability() const { +auto GpgKey::IsHasActualAuthenticationCapability() const -> bool { auto subkeys = GetSubKeys(); - if (std::any_of(subkeys->begin(), subkeys->end(), - [](const GpgSubKey &subkey) -> bool { - return subkey.IsSecretKey() && - subkey.IsHasAuthenticationCapability() && - !subkey.IsDisabled() && !subkey.IsRevoked() && - !subkey.IsExpired(); - })) - return true; - else - return false; + return std::any_of( + subkeys->begin(), subkeys->end(), [](const GpgSubKey &subkey) -> bool { + return subkey.IsSecretKey() && subkey.IsHasAuthenticationCapability() && + !subkey.IsDisabled() && !subkey.IsRevoked() && + !subkey.IsExpired(); + }); } /** @@ -222,7 +229,7 @@ bool GpgFrontend::GpgKey::IsHasActualAuthenticationCapability() const { * @param key target key * @return if key certify */ -bool GpgFrontend::GpgKey::IsHasActualCertificationCapability() const { +auto GpgKey::IsHasActualCertificationCapability() const -> bool { return IsHasMasterKey() && !IsExpired() && !IsRevoked() && !IsDisabled(); } @@ -231,28 +238,17 @@ bool GpgFrontend::GpgKey::IsHasActualCertificationCapability() const { * @param key target key * @return if key encrypt */ -bool GpgFrontend::GpgKey::IsHasActualEncryptionCapability() const { +auto GpgKey::IsHasActualEncryptionCapability() const -> bool { auto subkeys = GetSubKeys(); - if (std::any_of(subkeys->begin(), subkeys->end(), - [](const GpgSubKey &subkey) -> bool { - return subkey.IsHasEncryptionCapability() && - !subkey.IsDisabled() && !subkey.IsRevoked() && - !subkey.IsExpired(); - })) - return true; - else - return false; -} - -GpgFrontend::GpgKey GpgFrontend::GpgKey::Copy() const { - { - const std::lock_guard<std::mutex> guard(gpgme_key_opera_mutex); - gpgme_key_ref(key_ref_.get()); - } - auto *_new_key_ref = key_ref_.get(); - return GpgKey(std::move(_new_key_ref)); + return std::any_of( + subkeys->begin(), subkeys->end(), [](const GpgSubKey &subkey) -> bool { + return subkey.IsHasEncryptionCapability() && !subkey.IsDisabled() && + !subkey.IsRevoked() && !subkey.IsExpired(); + }); } -void GpgFrontend::GpgKey::_key_ref_deleter::operator()(gpgme_key_t _key) { +void GpgKey::KeyRefDeleter::operator()(gpgme_key_t _key) { if (_key != nullptr) gpgme_key_unref(_key); } + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/model/GpgKey.h b/src/core/model/GpgKey.h index fb87b791..d9c97d59 100644 --- a/src/core/model/GpgKey.h +++ b/src/core/model/GpgKey.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,19 +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_GPGKEY_H -#define GPGFRONTEND_GPGKEY_H +#pragma once -#include <mutex> - -#include "GpgSubKey.h" -#include "GpgUID.h" +#include "core/model/GpgSubKey.h" +#include "core/model/GpgUID.h" namespace GpgFrontend { @@ -41,6 +38,7 @@ namespace GpgFrontend { * */ class GPGFRONTEND_CORE_EXPORT GpgKey { + Q_DECLARE_TR_FUNCTIONS(GpgKey) public: /** * @brief @@ -48,98 +46,105 @@ class GPGFRONTEND_CORE_EXPORT GpgKey { * @return true * @return false */ - [[nodiscard]] bool IsGood() const; + [[nodiscard]] auto IsGood() const -> bool; /** * @brief * - * @return std::string + * @return QString */ - [[nodiscard]] std::string GetId() const; + [[nodiscard]] auto GetId() const -> QString; /** * @brief * - * @return std::string + * @return QString */ - [[nodiscard]] std::string GetName() const; + [[nodiscard]] auto GetName() const -> QString; /** * @brief * - * @return std::string + * @return QString */ - [[nodiscard]] std::string GetEmail() const; + [[nodiscard]] auto GetEmail() const -> QString; /** * @brief * - * @return std::string + * @return QString */ - [[nodiscard]] std::string GetComment() const; + [[nodiscard]] auto GetComment() const -> QString; /** * @brief * - * @return std::string + * @return QString */ - [[nodiscard]] std::string GetFingerprint() const; + [[nodiscard]] auto GetFingerprint() const -> QString; /** * @brief * - * @return std::string + * @return QString */ - [[nodiscard]] std::string GetProtocol() const; + [[nodiscard]] auto GetProtocol() const -> QString; /** * @brief * - * @return std::string + * @return QString */ - [[nodiscard]] std::string GetOwnerTrust() const; + [[nodiscard]] auto GetOwnerTrust() const -> QString; /** * @brief * * @return int */ - [[nodiscard]] int GetOwnerTrustLevel() const; + [[nodiscard]] auto GetOwnerTrustLevel() const -> int; /** * @brief * - * @return std::string + * @return QString */ - [[nodiscard]] std::string GetPublicKeyAlgo() const; + [[nodiscard]] auto GetPublicKeyAlgo() const -> QString; /** * @brief * - * @return boost::posix_time::ptime + * @return QString */ - [[nodiscard]] boost::posix_time::ptime GetLastUpdateTime() const; + [[nodiscard]] auto GetKeyAlgo() const -> QString; /** * @brief * - * @return boost::posix_time::ptime + * @return QDateTime */ - [[nodiscard]] boost::posix_time::ptime GetExpireTime() const; + [[nodiscard]] auto GetLastUpdateTime() const -> QDateTime; + + /** + * @brief + * + * @return QDateTime + */ + [[nodiscard]] auto GetExpireTime() const -> QDateTime; /** * @brief Create a time object * - * @return boost::posix_time::ptime + * @return QDateTime */ - [[nodiscard]] boost::posix_time::ptime GetCreateTime() const; + [[nodiscard]] auto GetCreateTime() const -> QDateTime; /** * @brief s * * @return unsigned int */ - [[nodiscard]] unsigned int GetPrimaryKeyLength() const; + [[nodiscard]] auto GetPrimaryKeyLength() const -> unsigned int; /** * @brief @@ -147,7 +152,7 @@ class GPGFRONTEND_CORE_EXPORT GpgKey { * @return true * @return false */ - [[nodiscard]] bool IsHasEncryptionCapability() const; + [[nodiscard]] auto IsHasEncryptionCapability() const -> bool; /** * @brief @@ -156,7 +161,7 @@ class GPGFRONTEND_CORE_EXPORT GpgKey { * @return true * @return false */ - [[nodiscard]] bool IsHasActualEncryptionCapability() const; + [[nodiscard]] auto IsHasActualEncryptionCapability() const -> bool; /** * @brief @@ -164,7 +169,7 @@ class GPGFRONTEND_CORE_EXPORT GpgKey { * @return true * @return false */ - [[nodiscard]] bool IsHasSigningCapability() const; + [[nodiscard]] auto IsHasSigningCapability() const -> bool; /** * @brief @@ -172,7 +177,7 @@ class GPGFRONTEND_CORE_EXPORT GpgKey { * @return true * @return false */ - [[nodiscard]] bool IsHasActualSigningCapability() const; + [[nodiscard]] auto IsHasActualSigningCapability() const -> bool; /** * @brief @@ -180,7 +185,7 @@ class GPGFRONTEND_CORE_EXPORT GpgKey { * @return true * @return false */ - [[nodiscard]] bool IsHasCertificationCapability() const; + [[nodiscard]] auto IsHasCertificationCapability() const -> bool; /** * @brief @@ -188,7 +193,7 @@ class GPGFRONTEND_CORE_EXPORT GpgKey { * @return true * @return false */ - [[nodiscard]] bool IsHasActualCertificationCapability() const; + [[nodiscard]] auto IsHasActualCertificationCapability() const -> bool; /** * @brief @@ -196,7 +201,7 @@ class GPGFRONTEND_CORE_EXPORT GpgKey { * @return true * @return false */ - [[nodiscard]] bool IsHasAuthenticationCapability() const; + [[nodiscard]] auto IsHasAuthenticationCapability() const -> bool; /** * @brief @@ -204,7 +209,7 @@ class GPGFRONTEND_CORE_EXPORT GpgKey { * @return true * @return false */ - [[nodiscard]] bool IsHasActualAuthenticationCapability() const; + [[nodiscard]] auto IsHasActualAuthenticationCapability() const -> bool; /** * @brief @@ -212,7 +217,7 @@ class GPGFRONTEND_CORE_EXPORT GpgKey { * @return true * @return false */ - [[nodiscard]] bool IsHasCardKey() const; + [[nodiscard]] auto IsHasCardKey() const -> bool; /** * @brief @@ -220,7 +225,7 @@ class GPGFRONTEND_CORE_EXPORT GpgKey { * @return true * @return false */ - [[nodiscard]] bool IsPrivateKey() const; + [[nodiscard]] auto IsPrivateKey() const -> bool; /** * @brief @@ -228,7 +233,7 @@ class GPGFRONTEND_CORE_EXPORT GpgKey { * @return true * @return false */ - [[nodiscard]] bool IsExpired() const; + [[nodiscard]] auto IsExpired() const -> bool; /** * @brief @@ -236,7 +241,7 @@ class GPGFRONTEND_CORE_EXPORT GpgKey { * @return true * @return false */ - [[nodiscard]] bool IsRevoked() const; + [[nodiscard]] auto IsRevoked() const -> bool; /** * @brief @@ -244,7 +249,7 @@ class GPGFRONTEND_CORE_EXPORT GpgKey { * @return true * @return false */ - [[nodiscard]] bool IsDisabled() const; + [[nodiscard]] auto IsDisabled() const -> bool; /** * @brief @@ -252,21 +257,22 @@ class GPGFRONTEND_CORE_EXPORT GpgKey { * @return true * @return false */ - [[nodiscard]] bool IsHasMasterKey() const; + [[nodiscard]] auto IsHasMasterKey() const -> bool; /** * @brief * * @return std::unique_ptr<std::vector<GpgSubKey>> */ - [[nodiscard]] std::unique_ptr<std::vector<GpgSubKey>> GetSubKeys() const; + [[nodiscard]] auto GetSubKeys() const + -> std::unique_ptr<std::vector<GpgSubKey>>; /** * @brief * * @return std::unique_ptr<std::vector<GpgUID>> */ - [[nodiscard]] std::unique_ptr<std::vector<GpgUID>> GetUIDs() const; + [[nodiscard]] auto GetUIDs() const -> std::unique_ptr<std::vector<GpgUID>>; /** * @brief Construct a new Gpg Key object @@ -299,7 +305,22 @@ class GPGFRONTEND_CORE_EXPORT GpgKey { * * @param k */ - GpgKey(GpgKey&& k) noexcept; + GpgKey(GpgKey&&) noexcept; + + /** + * @brief + * + * @param k + * @return GpgKey& + */ + auto operator=(GpgKey&&) noexcept -> GpgKey&; + + /** + * @brief Construct a new Gpg Key object + * + * @param k + */ + GpgKey(const GpgKey&); /** * @brief @@ -307,7 +328,7 @@ class GPGFRONTEND_CORE_EXPORT GpgKey { * @param k * @return GpgKey& */ - GpgKey& operator=(GpgKey&& k) noexcept; + auto operator=(const GpgKey&) -> GpgKey&; /** * @brief @@ -315,7 +336,7 @@ class GPGFRONTEND_CORE_EXPORT GpgKey { * @param key * @return GpgKey& */ - GpgKey& operator=(const gpgme_key_t& key) = delete; + auto operator=(const gpgme_key_t&) -> GpgKey& = delete; /** * @brief @@ -324,7 +345,7 @@ class GPGFRONTEND_CORE_EXPORT GpgKey { * @return true * @return false */ - bool operator==(const GpgKey& o) const; + auto operator==(const GpgKey&) const -> bool; /** * @brief @@ -333,7 +354,7 @@ class GPGFRONTEND_CORE_EXPORT GpgKey { * @return true * @return false */ - bool operator<=(const GpgKey& o) const; + auto operator<=(const GpgKey&) const -> bool; /** * @brief @@ -342,30 +363,18 @@ class GPGFRONTEND_CORE_EXPORT GpgKey { */ explicit operator gpgme_key_t() const; - /** - * @brief - * - * @return GpgKey - */ - [[nodiscard]] GpgKey Copy() const; - private: /** * @brief * */ - struct GPGFRONTEND_CORE_EXPORT _key_ref_deleter { + struct GPGFRONTEND_CORE_EXPORT KeyRefDeleter { void operator()(gpgme_key_t _key); }; - using KeyRefHandler = - std::unique_ptr<struct _gpgme_key, _key_ref_deleter>; ///< + using KeyRefHandler = std::unique_ptr<struct _gpgme_key, KeyRefDeleter>; ///< KeyRefHandler key_ref_ = nullptr; ///< - - mutable std::mutex gpgme_key_opera_mutex; // mutex for gpgme key operations }; } // namespace GpgFrontend - -#endif // GPGFRONTEND_GPGKEY_H diff --git a/src/core/model/GpgKeySignature.cpp b/src/core/model/GpgKeySignature.cpp index aa196391..3182000c 100644 --- a/src/core/model/GpgKeySignature.cpp +++ b/src/core/model/GpgKeySignature.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,67 +28,53 @@ #include "core/model/GpgKeySignature.h" -GpgFrontend::GpgKeySignature::GpgKeySignature() = default; +namespace GpgFrontend { -GpgFrontend::GpgKeySignature::~GpgKeySignature() = default; +GpgKeySignature::GpgKeySignature() = default; -GpgFrontend::GpgKeySignature::GpgKeySignature(gpgme_key_sig_t sig) +GpgKeySignature::~GpgKeySignature() = default; + +GpgKeySignature::GpgKeySignature(gpgme_key_sig_t sig) : signature_ref_(sig, [&](gpgme_key_sig_t signature) {}) {} -GpgFrontend::GpgKeySignature::GpgKeySignature(GpgKeySignature &&) noexcept = +GpgKeySignature::GpgKeySignature(GpgKeySignature &&) noexcept = default; + +GpgKeySignature &GpgKeySignature::operator=(GpgKeySignature &&) noexcept = default; -GpgFrontend::GpgKeySignature &GpgFrontend::GpgKeySignature::operator=( - GpgKeySignature &&) noexcept = default; +bool GpgKeySignature::IsRevoked() const { return signature_ref_->revoked; } -bool GpgFrontend::GpgKeySignature::IsRevoked() const { - return signature_ref_->revoked; -} - -bool GpgFrontend::GpgKeySignature::IsExpired() const { - return signature_ref_->expired; -} +bool GpgKeySignature::IsExpired() const { return signature_ref_->expired; } -bool GpgFrontend::GpgKeySignature::IsInvalid() const { - return signature_ref_->invalid; -} +bool GpgKeySignature::IsInvalid() const { return signature_ref_->invalid; } -bool GpgFrontend::GpgKeySignature::IsExportable() const { +bool GpgKeySignature::IsExportable() const { return signature_ref_->exportable; } -gpgme_error_t GpgFrontend::GpgKeySignature::GetStatus() const { +gpgme_error_t GpgKeySignature::GetStatus() const { return signature_ref_->status; } -std::string GpgFrontend::GpgKeySignature::GetKeyID() const { - return signature_ref_->keyid; -} +QString GpgKeySignature::GetKeyID() const { return signature_ref_->keyid; } -std::string GpgFrontend::GpgKeySignature::GetPubkeyAlgo() const { +QString GpgKeySignature::GetPubkeyAlgo() const { return gpgme_pubkey_algo_name(signature_ref_->pubkey_algo); } -boost::posix_time::ptime GpgFrontend::GpgKeySignature::GetCreateTime() const { - return boost::posix_time::from_time_t(signature_ref_->timestamp); +QDateTime GpgKeySignature::GetCreateTime() const { + return QDateTime::fromSecsSinceEpoch(signature_ref_->timestamp); } -boost::posix_time::ptime GpgFrontend::GpgKeySignature::GetExpireTime() const { - return boost::posix_time::from_time_t(signature_ref_->expires); +QDateTime GpgKeySignature::GetExpireTime() const { + return QDateTime::fromSecsSinceEpoch(signature_ref_->expires); } -std::string GpgFrontend::GpgKeySignature::GetUID() const { - return signature_ref_->uid; -} +QString GpgKeySignature::GetUID() const { return signature_ref_->uid; } -std::string GpgFrontend::GpgKeySignature::GetName() const { - return signature_ref_->name; -} +QString GpgKeySignature::GetName() const { return signature_ref_->name; } -std::string GpgFrontend::GpgKeySignature::GetEmail() const { - return signature_ref_->email; -} +QString GpgKeySignature::GetEmail() const { return signature_ref_->email; } -std::string GpgFrontend::GpgKeySignature::GetComment() const { - return signature_ref_->comment; -}
\ No newline at end of file +QString GpgKeySignature::GetComment() const { return signature_ref_->comment; } +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/model/GpgKeySignature.h b/src/core/model/GpgKeySignature.h index 25de2c75..c9ceeccc 100644 --- a/src/core/model/GpgKeySignature.h +++ b/src/core/model/GpgKeySignature.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,19 +20,15 @@ * 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_GPGKEYSIGNATURE_H -#define GPGFRONTEND_GPGKEYSIGNATURE_H +#pragma once -#include <boost/date_time.hpp> -#include <string> - -#include "core/GpgConstants.h" +#include "core/typedef/GpgTypedef.h" /** * @brief @@ -52,7 +48,7 @@ class GPGFRONTEND_CORE_EXPORT GpgKeySignature { * @return true * @return false */ - [[nodiscard]] bool IsRevoked() const; + [[nodiscard]] auto IsRevoked() const -> bool; /** * @brief @@ -60,7 +56,7 @@ class GPGFRONTEND_CORE_EXPORT GpgKeySignature { * @return true * @return false */ - [[nodiscard]] bool IsExpired() const; + [[nodiscard]] auto IsExpired() const -> bool; /** * @brief @@ -68,7 +64,7 @@ class GPGFRONTEND_CORE_EXPORT GpgKeySignature { * @return true * @return false */ - [[nodiscard]] bool IsInvalid() const; + [[nodiscard]] auto IsInvalid() const -> bool; /** * @brief @@ -76,70 +72,70 @@ class GPGFRONTEND_CORE_EXPORT GpgKeySignature { * @return true * @return false */ - [[nodiscard]] bool IsExportable() const; + [[nodiscard]] auto IsExportable() const -> bool; /** * @brief * * @return gpgme_error_t */ - [[nodiscard]] gpgme_error_t GetStatus() const; + [[nodiscard]] auto GetStatus() const -> GpgError; /** * @brief * - * @return std::string + * @return QString */ - [[nodiscard]] std::string GetKeyID() const; + [[nodiscard]] auto GetKeyID() const -> QString; /** * @brief * - * @return std::string + * @return QString */ - [[nodiscard]] std::string GetPubkeyAlgo() const; + [[nodiscard]] auto GetPubkeyAlgo() const -> QString; /** * @brief Create a time object * - * @return boost::posix_time::ptime + * @return QDateTime */ - [[nodiscard]] boost::posix_time::ptime GetCreateTime() const; + [[nodiscard]] auto GetCreateTime() const -> QDateTime; /** * @brief * - * @return boost::posix_time::ptime + * @return QDateTime */ - [[nodiscard]] boost::posix_time::ptime GetExpireTime() const; + [[nodiscard]] auto GetExpireTime() const -> QDateTime; /** * @brief * - * @return std::string + * @return QString */ - [[nodiscard]] std::string GetUID() const; + [[nodiscard]] auto GetUID() const -> QString; /** * @brief * - * @return std::string + * @return QString */ - [[nodiscard]] std::string GetName() const; + [[nodiscard]] auto GetName() const -> QString; /** * @brief * - * @return std::string + * @return QString */ - [[nodiscard]] std::string GetEmail() const; + [[nodiscard]] auto GetEmail() const -> QString; /** * @brief * - * @return std::string + * @return QString */ - [[nodiscard]] std::string GetComment() const; + [[nodiscard]] auto GetComment() const -> QString; /** * @brief Construct a new Gpg Key Signature object @@ -177,14 +173,14 @@ class GPGFRONTEND_CORE_EXPORT GpgKeySignature { * * @return GpgKeySignature& */ - GpgKeySignature &operator=(GpgKeySignature &&) noexcept; + auto operator=(GpgKeySignature &&) noexcept -> GpgKeySignature &; /** * @brief * * @return GpgKeySignature& */ - GpgKeySignature &operator=(const GpgKeySignature &) = delete; + auto operator=(const GpgKeySignature &) -> GpgKeySignature & = delete; private: using KeySignatrueRefHandler = @@ -195,5 +191,3 @@ class GPGFRONTEND_CORE_EXPORT GpgKeySignature { }; } // namespace GpgFrontend - -#endif // GPGFRONTEND_GPGKEYSIGNATURE_H diff --git a/src/core/model/GpgPassphraseContext.cpp b/src/core/model/GpgPassphraseContext.cpp new file mode 100644 index 00000000..5df3f5a8 --- /dev/null +++ b/src/core/model/GpgPassphraseContext.cpp @@ -0,0 +1,60 @@ +/** + * 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 "GpgPassphraseContext.h" + +namespace GpgFrontend { + +GpgPassphraseContext::GpgPassphraseContext(const QString& uids_info, + const QString& passphrase_info, + bool prev_was_bad, bool ask_for_new) + : passphrase_info_(passphrase_info), + uids_info_(uids_info), + prev_was_bad_(prev_was_bad), + ask_for_new_(ask_for_new) {} + +GpgPassphraseContext::GpgPassphraseContext() = default; + +auto GpgPassphraseContext::GetPassphrase() const -> QString { + return passphrase_; +} + +void GpgPassphraseContext::SetPassphrase(const QString& passphrase) { + passphrase_ = passphrase; +} + +auto GpgPassphraseContext::GetUidsInfo() const -> QString { return uids_info_; } + +auto GpgPassphraseContext::GetPassphraseInfo() const -> QString { + return passphrase_info_; +} + +auto GpgPassphraseContext::IsPreWasBad() const -> bool { return prev_was_bad_; } + +auto GpgPassphraseContext::IsAskForNew() const -> bool { return ask_for_new_; } +} // namespace GpgFrontend diff --git a/src/core/model/GpgPassphraseContext.h b/src/core/model/GpgPassphraseContext.h new file mode 100644 index 00000000..2bc1ac75 --- /dev/null +++ b/src/core/model/GpgPassphraseContext.h @@ -0,0 +1,63 @@ + + +/** + * 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 + +namespace GpgFrontend { + +class GPGFRONTEND_CORE_EXPORT GpgPassphraseContext : public QObject { + Q_OBJECT + public: + GpgPassphraseContext(const QString& uids_info, const QString& passphrase_info, + bool prev_was_bad, bool ask_for_new); + + GpgPassphraseContext(); + + void SetPassphrase(const QString& passphrase); + + [[nodiscard]] auto GetPassphrase() const -> QString; + + [[nodiscard]] auto GetUidsInfo() const -> QString; + + [[nodiscard]] auto GetPassphraseInfo() const -> QString; + + [[nodiscard]] auto IsPreWasBad() const -> bool; + + [[nodiscard]] auto IsAskForNew() const -> bool; + + private: + QString passphrase_info_; + QString uids_info_; + QString passphrase_; + bool prev_was_bad_; + bool ask_for_new_; +}; + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/model/GpgRecipient.cpp b/src/core/model/GpgRecipient.cpp new file mode 100644 index 00000000..54de43bc --- /dev/null +++ b/src/core/model/GpgRecipient.cpp @@ -0,0 +1,40 @@ +/** + * 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 "GpgRecipient.h" + +namespace GpgFrontend { + +GpgRecipient::GpgRecipient() = default; + +GpgRecipient::GpgRecipient(gpgme_recipient_t r) { + this->keyid = QString{r->keyid}; + this->pubkey_algo = QString{gpgme_pubkey_algo_name(r->pubkey_algo)}; + this->status = r->status; +} +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/model/GpgRecipient.h b/src/core/model/GpgRecipient.h new file mode 100644 index 00000000..a436c1d7 --- /dev/null +++ b/src/core/model/GpgRecipient.h @@ -0,0 +1,51 @@ +/** + * 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/GpgFrontendCoreExport.h" +#include "core/typedef/GpgTypedef.h" + +namespace GpgFrontend { + +struct GPGFRONTEND_CORE_EXPORT GpgRecipient { + /* The key ID of key for which the text was encrypted. */ + QString keyid; + + /* The public key algorithm of the recipient key. */ + QString pubkey_algo; + + /* The status of the recipient. */ + GpgError status; + + GpgRecipient(); + + explicit GpgRecipient(gpgme_recipient_t r); +}; + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/model/GpgSignResult.cpp b/src/core/model/GpgSignResult.cpp new file mode 100644 index 00000000..4a0e5f35 --- /dev/null +++ b/src/core/model/GpgSignResult.cpp @@ -0,0 +1,65 @@ +/** + * 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 "GpgSignResult.h" + +namespace GpgFrontend { +GpgSignResult::GpgSignResult(gpgme_sign_result_t r) + : result_ref_(std::shared_ptr<struct _gpgme_op_sign_result>( + (gpgme_result_ref(r), r), [](gpgme_sign_result_t p) { + if (p != nullptr) { + gpgme_result_unref(p); + } + })) {} + +GpgSignResult::GpgSignResult() = default; + +GpgSignResult::~GpgSignResult() = default; + +auto GpgSignResult::IsGood() -> bool { return result_ref_ != nullptr; } + +auto GpgSignResult::GetRaw() -> gpgme_sign_result_t { + return result_ref_.get(); +} + +auto GpgSignResult::InvalidSigners() + -> std::vector<std::tuple<QString, GpgError>> { + std::vector<std::tuple<QString, GpgError>> result; + for (auto* invalid_key = result_ref_->invalid_signers; invalid_key != nullptr; + invalid_key = invalid_key->next) { + try { + result.emplace_back(QString{invalid_key->fpr}, invalid_key->reason); + } catch (...) { + GF_CORE_LOG_ERROR( + "caught exception when processing invalid_signers, " + "maybe nullptr of fpr"); + } + } + return result; +} +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/model/GpgSignResult.h b/src/core/model/GpgSignResult.h new file mode 100644 index 00000000..ccb0361f --- /dev/null +++ b/src/core/model/GpgSignResult.h @@ -0,0 +1,53 @@ +/** + * 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/GpgFrontendCoreExport.h" +#include "core/typedef/GpgTypedef.h" + +namespace GpgFrontend { + +class GPGFRONTEND_CORE_EXPORT GpgSignResult { + public: + auto IsGood() -> bool; + + auto GetRaw() -> gpgme_sign_result_t; + + auto InvalidSigners() -> std::vector<std::tuple<QString, GpgError>>; + + explicit GpgSignResult(gpgme_sign_result_t); + + GpgSignResult(); + + virtual ~GpgSignResult(); + + private: + std::shared_ptr<struct _gpgme_op_sign_result> result_ref_ = nullptr; ///< +}; +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/model/GpgSignature.cpp b/src/core/model/GpgSignature.cpp index 73f9179d..e2cb7e4b 100644 --- a/src/core/model/GpgSignature.cpp +++ b/src/core/model/GpgSignature.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,21 +28,28 @@ #include "GpgSignature.h" +namespace GpgFrontend { + /** * @brief Construct a new Gpg Signature object * */ -GpgFrontend::GpgSignature::GpgSignature(GpgSignature &&) noexcept = default; +GpgSignature::GpgSignature(GpgSignature &&) noexcept = default; /** * @brief * * @return GpgSignature& */ -GpgFrontend::GpgSignature &GpgFrontend::GpgSignature::operator=( - GpgFrontend::GpgSignature &&) noexcept = default; +auto GpgSignature::operator=(GpgSignature &&) noexcept + -> GpgSignature & = default; -GpgFrontend::GpgSignature::GpgSignature(gpgme_signature_t sig) +/** + * @brief Construct a new Gpg Signature:: Gpg Signature object + * + * @param sig + */ +GpgSignature::GpgSignature(gpgme_signature_t sig) : signature_ref_(sig, [&](gpgme_signature_t signature) {}) {} /** @@ -50,7 +57,7 @@ GpgFrontend::GpgSignature::GpgSignature(gpgme_signature_t sig) * * @return gpgme_validity_t */ -gpgme_validity_t GpgFrontend::GpgSignature::GetValidity() const { +auto GpgSignature::GetValidity() const -> gpgme_validity_t { return signature_ref_->validity; } @@ -59,7 +66,7 @@ gpgme_validity_t GpgFrontend::GpgSignature::GetValidity() const { * * @return gpgme_error_t */ -gpgme_error_t GpgFrontend::GpgSignature::GetStatus() const { +auto GpgSignature::GetStatus() const -> gpgme_error_t { return signature_ref_->status; } @@ -68,52 +75,52 @@ gpgme_error_t GpgFrontend::GpgSignature::GetStatus() const { * * @return gpgme_error_t */ -gpgme_error_t GpgFrontend::GpgSignature::GetSummary() const { +auto GpgSignature::GetSummary() const -> gpgme_error_t { return signature_ref_->summary; } /** * @brief * - * @return std::string + * @return QString */ -std::string GpgFrontend::GpgSignature::GetPubkeyAlgo() const { +auto GpgSignature::GetPubkeyAlgo() const -> QString { return gpgme_pubkey_algo_name(signature_ref_->pubkey_algo); } /** * @brief * - * @return std::string + * @return QString */ -std::string GpgFrontend::GpgSignature::GetHashAlgo() const { +auto GpgSignature::GetHashAlgo() const -> QString { return gpgme_hash_algo_name(signature_ref_->hash_algo); } /** * @brief Create a time object * - * @return boost::posix_time::ptime + * @return QDateTime */ -boost::posix_time::ptime GpgFrontend::GpgSignature::GetCreateTime() const { - return boost::posix_time::from_time_t(signature_ref_->timestamp); +auto GpgSignature::GetCreateTime() const -> QDateTime { + return QDateTime::fromSecsSinceEpoch(signature_ref_->timestamp); } /** * @brief * - * @return boost::posix_time::ptime + * @return QDateTime */ -boost::posix_time::ptime GpgFrontend::GpgSignature::GetExpireTime() const { - return boost::posix_time::from_time_t(signature_ref_->exp_timestamp); +auto GpgSignature::GetExpireTime() const -> QDateTime { + return QDateTime::fromSecsSinceEpoch(signature_ref_->exp_timestamp); } /** * @brief * - * @return std::string + * @return QString */ -std::string GpgFrontend::GpgSignature::GetFingerprint() const { +auto GpgSignature::GetFingerprint() const -> QString { return signature_ref_->fpr; } @@ -121,10 +128,12 @@ std::string GpgFrontend::GpgSignature::GetFingerprint() const { * @brief Construct a new Gpg Signature object * */ -GpgFrontend::GpgSignature::GpgSignature() = default; +GpgSignature::GpgSignature() = default; /** * @brief Destroy the Gpg Signature object * */ -GpgFrontend::GpgSignature::~GpgSignature() = default; +GpgSignature::~GpgSignature() = default; + +} // namespace GpgFrontend diff --git a/src/core/model/GpgSignature.h b/src/core/model/GpgSignature.h index 2e49c4d7..316b9100 100644 --- a/src/core/model/GpgSignature.h +++ b/src/core/model/GpgSignature.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,19 +20,15 @@ * 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_GPGSIGNATURE_H -#define GPGFRONTEND_GPGSIGNATURE_H +#pragma once -#include <boost/date_time/gregorian/greg_date.hpp> -#include <boost/date_time/posix_time/conversion.hpp> - -#include "core/GpgConstants.h" +#include "core/typedef/GpgTypedef.h" namespace GpgFrontend { @@ -47,56 +43,56 @@ class GPGFRONTEND_CORE_EXPORT GpgSignature { * * @return gpgme_validity_t */ - [[nodiscard]] gpgme_validity_t GetValidity() const; + [[nodiscard]] auto GetValidity() const -> gpgme_validity_t; /** * @brief * * @return gpgme_error_t */ - [[nodiscard]] gpgme_error_t GetStatus() const; + [[nodiscard]] auto GetStatus() const -> GpgError; /** * @brief * * @return gpgme_error_t */ - [[nodiscard]] gpgme_error_t GetSummary() const; + [[nodiscard]] auto GetSummary() const -> GpgError; /** * @brief * - * @return std::string + * @return QString */ - [[nodiscard]] std::string GetPubkeyAlgo() const; + [[nodiscard]] auto GetPubkeyAlgo() const -> QString; /** * @brief * - * @return std::string + * @return QString */ - [[nodiscard]] std::string GetHashAlgo() const; + [[nodiscard]] auto GetHashAlgo() const -> QString; /** * @brief Create a time object * - * @return boost::posix_time::ptime + * @return QDateTime */ - [[nodiscard]] boost::posix_time::ptime GetCreateTime() const; + [[nodiscard]] auto GetCreateTime() const -> QDateTime; /** * @brief * - * @return boost::posix_time::ptime + * @return QDateTime */ - [[nodiscard]] boost::posix_time::ptime GetExpireTime() const; + [[nodiscard]] auto GetExpireTime() const -> QDateTime; /** * @brief * - * @return std::string + * @return QString */ - [[nodiscard]] std::string GetFingerprint() const; + [[nodiscard]] auto GetFingerprint() const -> QString; /** * @brief Construct a new Gpg Signature object @@ -134,14 +130,14 @@ class GPGFRONTEND_CORE_EXPORT GpgSignature { * * @return GpgSignature& */ - GpgSignature &operator=(GpgSignature &&) noexcept; + auto operator=(GpgSignature &&) noexcept -> GpgSignature &; /** * @brief * * @return GpgSignature& */ - GpgSignature &operator=(const GpgSignature &) = delete; + auto operator=(const GpgSignature &) -> GpgSignature & = delete; private: using KeySignatrueRefHandler = @@ -151,5 +147,3 @@ class GPGFRONTEND_CORE_EXPORT GpgSignature { KeySignatrueRefHandler signature_ref_ = nullptr; ///< }; } // namespace GpgFrontend - -#endif // GPGFRONTEND_GPGSIGNATURE_H diff --git a/src/core/model/GpgSubKey.cpp b/src/core/model/GpgSubKey.cpp index e63816b1..cb0078de 100644 --- a/src/core/model/GpgSubKey.cpp +++ b/src/core/model/GpgSubKey.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,84 +20,86 @@ * 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 "core/model/GpgSubKey.h" +#include "GpgSubKey.h" -GpgFrontend::GpgSubKey::GpgSubKey() = default; +namespace GpgFrontend { -GpgFrontend::GpgSubKey::GpgSubKey(gpgme_subkey_t subkey) - : _subkey_ref(subkey, [&](gpgme_subkey_t subkey) {}) {} +GpgSubKey::GpgSubKey() = default; -GpgFrontend::GpgSubKey::GpgSubKey(GpgSubKey&& o) noexcept { - swap(_subkey_ref, o._subkey_ref); +GpgSubKey::GpgSubKey(gpgme_subkey_t subkey) + : subkey_ref_(subkey, [&](gpgme_subkey_t subkey) {}) {} + +GpgSubKey::GpgSubKey(GpgSubKey&& o) noexcept { + swap(subkey_ref_, o.subkey_ref_); } -GpgFrontend::GpgSubKey& GpgFrontend::GpgSubKey::operator=( - GpgSubKey&& o) noexcept { - swap(_subkey_ref, o._subkey_ref); +auto GpgSubKey::operator=(GpgSubKey&& o) noexcept -> GpgSubKey& { + swap(subkey_ref_, o.subkey_ref_); return *this; }; -bool GpgFrontend::GpgSubKey::operator==(const GpgSubKey& o) const { +auto GpgSubKey::operator==(const GpgSubKey& o) const -> bool { return GetFingerprint() == o.GetFingerprint(); } -std::string GpgFrontend::GpgSubKey::GetID() const { return _subkey_ref->keyid; } +auto GpgSubKey::GetID() const -> QString { return subkey_ref_->keyid; } -std::string GpgFrontend::GpgSubKey::GetFingerprint() const { - return _subkey_ref->fpr; -} +auto GpgSubKey::GetFingerprint() const -> QString { return subkey_ref_->fpr; } -std::string GpgFrontend::GpgSubKey::GetPubkeyAlgo() const { - return gpgme_pubkey_algo_name(_subkey_ref->pubkey_algo); +auto GpgSubKey::GetPubkeyAlgo() const -> QString { + return gpgme_pubkey_algo_name(subkey_ref_->pubkey_algo); } -unsigned int GpgFrontend::GpgSubKey::GetKeyLength() const { - return _subkey_ref->length; +auto GpgSubKey::GetKeyAlgo() const -> QString { + auto* buffer = gpgme_pubkey_algo_string(subkey_ref_.get()); + auto algo = QString(buffer); + gpgme_free(buffer); + return algo.toUpper(); } -bool GpgFrontend::GpgSubKey::IsHasEncryptionCapability() const { - return _subkey_ref->can_encrypt; +auto GpgSubKey::GetKeyLength() const -> unsigned int { + return subkey_ref_->length; } -bool GpgFrontend::GpgSubKey::IsHasSigningCapability() const { - return _subkey_ref->can_sign; +auto GpgSubKey::IsHasEncryptionCapability() const -> bool { + return subkey_ref_->can_encrypt; } -bool GpgFrontend::GpgSubKey::IsHasCertificationCapability() const { - return _subkey_ref->can_certify; +auto GpgSubKey::IsHasSigningCapability() const -> bool { + return subkey_ref_->can_sign; } -bool GpgFrontend::GpgSubKey::IsHasAuthenticationCapability() const { - return _subkey_ref->can_authenticate; +auto GpgSubKey::IsHasCertificationCapability() const -> bool { + return subkey_ref_->can_certify; } -bool GpgFrontend::GpgSubKey::IsPrivateKey() const { - return _subkey_ref->secret; +auto GpgSubKey::IsHasAuthenticationCapability() const -> bool { + return subkey_ref_->can_authenticate; } -bool GpgFrontend::GpgSubKey::IsExpired() const { return _subkey_ref->expired; } +auto GpgSubKey::IsPrivateKey() const -> bool { return subkey_ref_->secret; } -bool GpgFrontend::GpgSubKey::IsRevoked() const { return _subkey_ref->revoked; } +auto GpgSubKey::IsExpired() const -> bool { return subkey_ref_->expired; } -bool GpgFrontend::GpgSubKey::IsDisabled() const { - return _subkey_ref->disabled; -} +auto GpgSubKey::IsRevoked() const -> bool { return subkey_ref_->revoked; } -bool GpgFrontend::GpgSubKey::IsSecretKey() const { return _subkey_ref->secret; } +auto GpgSubKey::IsDisabled() const -> bool { return subkey_ref_->disabled; } -bool GpgFrontend::GpgSubKey::IsCardKey() const { - return _subkey_ref->is_cardkey; -} +auto GpgSubKey::IsSecretKey() const -> bool { return subkey_ref_->secret; } + +auto GpgSubKey::IsCardKey() const -> bool { return subkey_ref_->is_cardkey; } -boost::posix_time::ptime GpgFrontend::GpgSubKey::GetCreateTime() const { - return boost::posix_time::from_time_t(_subkey_ref->timestamp); +auto GpgSubKey::GetCreateTime() const -> QDateTime { + return QDateTime::fromSecsSinceEpoch(subkey_ref_->timestamp); } -boost::posix_time::ptime GpgFrontend::GpgSubKey::GetExpireTime() const { - return boost::posix_time::from_time_t(_subkey_ref->expires); +auto GpgSubKey::GetExpireTime() const -> QDateTime { + return QDateTime::fromSecsSinceEpoch(subkey_ref_->expires); } + +} // namespace GpgFrontend diff --git a/src/core/model/GpgSubKey.h b/src/core/model/GpgSubKey.h index 5a86d21d..83d75e2d 100644 --- a/src/core/model/GpgSubKey.h +++ b/src/core/model/GpgSubKey.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,19 +20,13 @@ * 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_GPGSUBKEY_H -#define GPGFRONTEND_GPGSUBKEY_H - -#include <boost/date_time.hpp> -#include <string> - -#include "core/GpgConstants.h" +#pragma once namespace GpgFrontend { @@ -45,30 +39,37 @@ class GPGFRONTEND_CORE_EXPORT GpgSubKey { /** * @brief * - * @return std::string + * @return QString + */ + [[nodiscard]] auto GetID() const -> QString; + + /** + * @brief + * + * @return QString */ - [[nodiscard]] std::string GetID() const; + [[nodiscard]] auto GetFingerprint() const -> QString; /** * @brief * - * @return std::string + * @return QString */ - [[nodiscard]] std::string GetFingerprint() const; + [[nodiscard]] auto GetPubkeyAlgo() const -> QString; /** * @brief * - * @return std::string + * @return QString */ - [[nodiscard]] std::string GetPubkeyAlgo() const; + [[nodiscard]] auto GetKeyAlgo() const -> QString; /** * @brief * * @return unsigned int */ - [[nodiscard]] unsigned int GetKeyLength() const; + [[nodiscard]] auto GetKeyLength() const -> unsigned int; /** * @brief @@ -76,7 +77,7 @@ class GPGFRONTEND_CORE_EXPORT GpgSubKey { * @return true * @return false */ - [[nodiscard]] bool IsHasEncryptionCapability() const; + [[nodiscard]] auto IsHasEncryptionCapability() const -> bool; /** * @brief @@ -84,7 +85,7 @@ class GPGFRONTEND_CORE_EXPORT GpgSubKey { * @return true * @return false */ - [[nodiscard]] bool IsHasSigningCapability() const; + [[nodiscard]] auto IsHasSigningCapability() const -> bool; /** * @brief @@ -92,7 +93,7 @@ class GPGFRONTEND_CORE_EXPORT GpgSubKey { * @return true * @return false */ - [[nodiscard]] bool IsHasCertificationCapability() const; + [[nodiscard]] auto IsHasCertificationCapability() const -> bool; /** * @brief @@ -100,7 +101,7 @@ class GPGFRONTEND_CORE_EXPORT GpgSubKey { * @return true * @return false */ - [[nodiscard]] bool IsHasAuthenticationCapability() const; + [[nodiscard]] auto IsHasAuthenticationCapability() const -> bool; /** * @brief @@ -108,7 +109,7 @@ class GPGFRONTEND_CORE_EXPORT GpgSubKey { * @return true * @return false */ - [[nodiscard]] bool IsPrivateKey() const; + [[nodiscard]] auto IsPrivateKey() const -> bool; /** * @brief @@ -116,7 +117,7 @@ class GPGFRONTEND_CORE_EXPORT GpgSubKey { * @return true * @return false */ - [[nodiscard]] bool IsExpired() const; + [[nodiscard]] auto IsExpired() const -> bool; /** * @brief @@ -124,7 +125,7 @@ class GPGFRONTEND_CORE_EXPORT GpgSubKey { * @return true * @return false */ - [[nodiscard]] bool IsRevoked() const; + [[nodiscard]] auto IsRevoked() const -> bool; /** * @brief @@ -132,7 +133,7 @@ class GPGFRONTEND_CORE_EXPORT GpgSubKey { * @return true * @return false */ - [[nodiscard]] bool IsDisabled() const; + [[nodiscard]] auto IsDisabled() const -> bool; /** * @brief @@ -140,7 +141,7 @@ class GPGFRONTEND_CORE_EXPORT GpgSubKey { * @return true * @return false */ - [[nodiscard]] bool IsSecretKey() const; + [[nodiscard]] auto IsSecretKey() const -> bool; /** * @brief @@ -148,21 +149,21 @@ class GPGFRONTEND_CORE_EXPORT GpgSubKey { * @return true * @return false */ - [[nodiscard]] bool IsCardKey() const; + [[nodiscard]] auto IsCardKey() const -> bool; /** * @brief * - * @return boost::posix_time::ptime + * @return QDateTime */ - [[nodiscard]] boost::posix_time::ptime GetCreateTime() const; + [[nodiscard]] auto GetCreateTime() const -> QDateTime; /** * @brief * - * @return boost::posix_time::ptime + * @return QDateTime */ - [[nodiscard]] boost::posix_time::ptime GetExpireTime() const; + [[nodiscard]] QDateTime GetExpireTime() const; /** * @brief Construct a new Gpg Sub Key object @@ -196,14 +197,14 @@ class GPGFRONTEND_CORE_EXPORT GpgSubKey { * @param o * @return GpgSubKey& */ - GpgSubKey& operator=(GpgSubKey&& o) noexcept; + auto operator=(GpgSubKey&& o) noexcept -> GpgSubKey&; /** * @brief * * @return GpgSubKey& */ - GpgSubKey& operator=(const GpgSubKey&) = delete; + auto operator=(const GpgSubKey&) -> GpgSubKey& = delete; /** * @brief @@ -212,16 +213,14 @@ class GPGFRONTEND_CORE_EXPORT GpgSubKey { * @return true * @return false */ - bool operator==(const GpgSubKey& o) const; + auto operator==(const GpgSubKey& o) const -> bool; private: using SubkeyRefHandler = std::unique_ptr<struct _gpgme_subkey, std::function<void(gpgme_subkey_t)>>; ///< - SubkeyRefHandler _subkey_ref = nullptr; ///< + SubkeyRefHandler subkey_ref_ = nullptr; ///< }; } // namespace GpgFrontend - -#endif // GPGFRONTEND_GPGSUBKEY_H diff --git a/src/core/model/GpgTOFUInfo.cpp b/src/core/model/GpgTOFUInfo.cpp index 84ce1e29..251affc2 100644 --- a/src/core/model/GpgTOFUInfo.cpp +++ b/src/core/model/GpgTOFUInfo.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,39 +28,40 @@ #include "GpgTOFUInfo.h" -GpgFrontend::GpgTOFUInfo::GpgTOFUInfo() = default; +namespace GpgFrontend { -GpgFrontend::GpgTOFUInfo::GpgTOFUInfo(gpgme_tofu_info_t tofu_info) - : _tofu_info_ref(tofu_info, [&](gpgme_tofu_info_t tofu_info) {}) {} +GpgTOFUInfo::GpgTOFUInfo() = default; -GpgFrontend::GpgTOFUInfo::GpgTOFUInfo(GpgTOFUInfo&& o) noexcept { - swap(_tofu_info_ref, o._tofu_info_ref); +GpgTOFUInfo::GpgTOFUInfo(gpgme_tofu_info_t tofu_info) + : tofu_info_ref_(tofu_info, [&](gpgme_tofu_info_t tofu_info) {}) {} + +GpgTOFUInfo::GpgTOFUInfo(GpgTOFUInfo&& o) noexcept { + swap(tofu_info_ref_, o.tofu_info_ref_); } -GpgFrontend::GpgTOFUInfo& GpgFrontend::GpgTOFUInfo::operator=( - GpgTOFUInfo&& o) noexcept { - swap(_tofu_info_ref, o._tofu_info_ref); +auto GpgTOFUInfo::operator=(GpgTOFUInfo&& o) noexcept -> GpgTOFUInfo& { + swap(tofu_info_ref_, o.tofu_info_ref_); return *this; }; -unsigned GpgFrontend::GpgTOFUInfo::GetValidity() const { - return _tofu_info_ref->validity; +auto GpgTOFUInfo::GetValidity() const -> unsigned { + return tofu_info_ref_->validity; } -unsigned GpgFrontend::GpgTOFUInfo::GetPolicy() const { - return _tofu_info_ref->policy; +auto GpgTOFUInfo::GetPolicy() const -> unsigned { + return tofu_info_ref_->policy; } -unsigned long GpgFrontend::GpgTOFUInfo::GetSignCount() const { - return _tofu_info_ref->signcount; +auto GpgTOFUInfo::GetSignCount() const -> unsigned long { + return tofu_info_ref_->signcount; } -unsigned long GpgFrontend::GpgTOFUInfo::GetEncrCount() const { - return _tofu_info_ref->encrcount; +auto GpgTOFUInfo::GetEncrCount() const -> unsigned long { + return tofu_info_ref_->encrcount; } -unsigned long GpgFrontend::GpgTOFUInfo::GetSignFirst() const { - return _tofu_info_ref->signfirst; +auto GpgTOFUInfo::GetSignFirst() const -> unsigned long { + return tofu_info_ref_->signfirst; } /** @@ -68,8 +69,8 @@ unsigned long GpgFrontend::GpgTOFUInfo::GetSignFirst() const { * * @return unsigned long */ -unsigned long GpgFrontend::GpgTOFUInfo::GetSignLast() const { - return _tofu_info_ref->signlast; +auto GpgTOFUInfo::GetSignLast() const -> unsigned long { + return tofu_info_ref_->signlast; } /** @@ -77,15 +78,17 @@ unsigned long GpgFrontend::GpgTOFUInfo::GetSignLast() const { * * @return unsigned long */ -unsigned long GpgFrontend::GpgTOFUInfo::GetEncrLast() const { - return _tofu_info_ref->encrlast; +auto GpgTOFUInfo::GetEncrLast() const -> unsigned long { + return tofu_info_ref_->encrlast; } /** * @brief * - * @return std::string + * @return QString */ -std::string GpgFrontend::GpgTOFUInfo::GetDescription() const { - return _tofu_info_ref->description; -}
\ No newline at end of file +auto GpgTOFUInfo::GetDescription() const -> QString { + return tofu_info_ref_->description; +} + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/model/GpgTOFUInfo.h b/src/core/model/GpgTOFUInfo.h index b82a4eb2..ec4c49b7 100644 --- a/src/core/model/GpgTOFUInfo.h +++ b/src/core/model/GpgTOFUInfo.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,16 +20,13 @@ * 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_GPGTOFU_H -#define GPGFRONTEND_GPGTOFU_H - -#include "core/GpgConstants.h" +#pragma once namespace GpgFrontend { /** @@ -43,55 +40,55 @@ class GPGFRONTEND_CORE_EXPORT GpgTOFUInfo { * * @return unsigned */ - [[nodiscard]] unsigned GetValidity() const; + [[nodiscard]] auto GetValidity() const -> unsigned; /** * @brief * * @return unsigned */ - [[nodiscard]] unsigned GetPolicy() const; + [[nodiscard]] auto GetPolicy() const -> unsigned; /** * @brief * * @return unsigned long */ - [[nodiscard]] unsigned long GetSignCount() const; + [[nodiscard]] auto GetSignCount() const -> unsigned long; /** * @brief * * @return unsigned long */ - [[nodiscard]] unsigned long GetEncrCount() const; + [[nodiscard]] auto GetEncrCount() const -> unsigned long; /** * @brief * * @return unsigned long */ - [[nodiscard]] unsigned long GetSignFirst() const; + [[nodiscard]] auto GetSignFirst() const -> unsigned long; /** * @brief * * @return unsigned long */ - [[nodiscard]] unsigned long GetSignLast() const; + [[nodiscard]] auto GetSignLast() const -> unsigned long; /** * @brief * * @return unsigned long */ - [[nodiscard]] unsigned long GetEncrLast() const; + [[nodiscard]] auto GetEncrLast() const -> unsigned long; /** * @brief * - * @return std::string + * @return QString */ - [[nodiscard]] std::string GetDescription() const; + [[nodiscard]] auto GetDescription() const -> QString; /** * @brief Construct a new Gpg T O F U Info object @@ -125,23 +122,21 @@ class GPGFRONTEND_CORE_EXPORT GpgTOFUInfo { * @param o * @return GpgTOFUInfo& */ - GpgTOFUInfo& operator=(GpgTOFUInfo&& o) noexcept; + auto operator=(GpgTOFUInfo&& o) noexcept -> GpgTOFUInfo&; /** * @brief * * @return GpgTOFUInfo& */ - GpgTOFUInfo& operator=(const GpgTOFUInfo&) = delete; + auto operator=(const GpgTOFUInfo&) -> GpgTOFUInfo& = delete; private: using SubkeyRefHandler = std::unique_ptr<struct _gpgme_tofu_info, std::function<void(gpgme_tofu_info_t)>>; ///< - SubkeyRefHandler _tofu_info_ref = nullptr; ///< + SubkeyRefHandler tofu_info_ref_ = nullptr; ///< }; } // namespace GpgFrontend - -#endif // GPGFRONTEND_GPGTOFU_H diff --git a/src/core/model/GpgUID.cpp b/src/core/model/GpgUID.cpp index d87192c3..e0d9d3a6 100644 --- a/src/core/model/GpgUID.cpp +++ b/src/core/model/GpgUID.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,31 +28,30 @@ #include "core/model/GpgUID.h" -GpgFrontend::GpgUID::GpgUID() = default; +namespace GpgFrontend { -GpgFrontend::GpgUID::GpgUID(gpgme_user_id_t uid) +GpgUID::GpgUID() = default; + +GpgUID::GpgUID(gpgme_user_id_t uid) : uid_ref_(uid, [&](gpgme_user_id_t uid) {}) {} -GpgFrontend::GpgUID::GpgUID(GpgUID &&o) noexcept { swap(uid_ref_, o.uid_ref_); } +GpgUID::GpgUID(GpgUID &&o) noexcept { swap(uid_ref_, o.uid_ref_); } -std::string GpgFrontend::GpgUID::GetName() const { return uid_ref_->name; } +auto GpgUID::GetName() const -> QString { return uid_ref_->name; } -std::string GpgFrontend::GpgUID::GetEmail() const { return uid_ref_->email; } +auto GpgUID::GetEmail() const -> QString { return uid_ref_->email; } -std::string GpgFrontend::GpgUID::GetComment() const { - return uid_ref_->comment; -} +auto GpgUID::GetComment() const -> QString { return uid_ref_->comment; } -std::string GpgFrontend::GpgUID::GetUID() const { return uid_ref_->uid; } +auto GpgUID::GetUID() const -> QString { return uid_ref_->uid; } -bool GpgFrontend::GpgUID::GetRevoked() const { return uid_ref_->revoked; } +auto GpgUID::GetRevoked() const -> bool { return uid_ref_->revoked; } -bool GpgFrontend::GpgUID::GetInvalid() const { return uid_ref_->invalid; } +auto GpgUID::GetInvalid() const -> bool { return uid_ref_->invalid; } -std::unique_ptr<std::vector<GpgFrontend::GpgTOFUInfo>> -GpgFrontend::GpgUID::GetTofuInfos() const { +auto GpgUID::GetTofuInfos() const -> std::unique_ptr<std::vector<GpgTOFUInfo>> { auto infos = std::make_unique<std::vector<GpgTOFUInfo>>(); - auto info_next = uid_ref_->tofu; + auto *info_next = uid_ref_->tofu; while (info_next != nullptr) { infos->push_back(GpgTOFUInfo(info_next)); info_next = info_next->next; @@ -60,13 +59,15 @@ GpgFrontend::GpgUID::GetTofuInfos() const { return infos; } -std::unique_ptr<std::vector<GpgFrontend::GpgKeySignature>> -GpgFrontend::GpgUID::GetSignatures() const { +auto GpgUID::GetSignatures() const + -> std::unique_ptr<std::vector<GpgKeySignature>> { auto sigs = std::make_unique<std::vector<GpgKeySignature>>(); - auto sig_next = uid_ref_->signatures; + auto *sig_next = uid_ref_->signatures; while (sig_next != nullptr) { sigs->push_back(GpgKeySignature(sig_next)); sig_next = sig_next->next; } return sigs; } + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/model/GpgUID.h b/src/core/model/GpgUID.h index 670c318d..14b4db3f 100644 --- a/src/core/model/GpgUID.h +++ b/src/core/model/GpgUID.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,14 +20,13 @@ * 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_GPGUID_H -#define GPGFRONTEND_GPGUID_H +#pragma once #include "GpgKeySignature.h" #include "GpgTOFUInfo.h" @@ -42,30 +41,30 @@ class GPGFRONTEND_CORE_EXPORT GpgUID { /** * @brief * - * @return std::string + * @return QString */ - [[nodiscard]] std::string GetName() const; + [[nodiscard]] auto GetName() const -> QString; /** * @brief * - * @return std::string + * @return QString */ - [[nodiscard]] std::string GetEmail() const; + [[nodiscard]] auto GetEmail() const -> QString; /** * @brief * - * @return std::string + * @return QString */ - [[nodiscard]] std::string GetComment() const; + [[nodiscard]] auto GetComment() const -> QString; /** * @brief * - * @return std::string + * @return QString */ - [[nodiscard]] std::string GetUID() const; + [[nodiscard]] auto GetUID() const -> QString; /** * @brief @@ -73,7 +72,7 @@ class GPGFRONTEND_CORE_EXPORT GpgUID { * @return true * @return false */ - [[nodiscard]] bool GetRevoked() const; + [[nodiscard]] auto GetRevoked() const -> bool; /** * @brief @@ -81,22 +80,23 @@ class GPGFRONTEND_CORE_EXPORT GpgUID { * @return true * @return false */ - [[nodiscard]] bool GetInvalid() const; + [[nodiscard]] auto GetInvalid() const -> bool; /** * @brief * * @return std::unique_ptr<std::vector<GpgTOFUInfo>> */ - [[nodiscard]] std::unique_ptr<std::vector<GpgTOFUInfo>> GetTofuInfos() const; + [[nodiscard]] auto GetTofuInfos() const + -> std::unique_ptr<std::vector<GpgTOFUInfo>>; /** * @brief * * @return std::unique_ptr<std::vector<GpgKeySignature>> */ - [[nodiscard]] std::unique_ptr<std::vector<GpgKeySignature>> GetSignatures() - const; + [[nodiscard]] auto GetSignatures() const + -> std::unique_ptr<std::vector<GpgKeySignature>>; /** * @brief Construct a new Gpg U I D object @@ -130,14 +130,14 @@ class GPGFRONTEND_CORE_EXPORT GpgUID { * @param o * @return GpgUID& */ - GpgUID &operator=(GpgUID &&o) noexcept; + auto operator=(GpgUID &&o) noexcept -> GpgUID &; /** * @brief * * @return GpgUID& */ - GpgUID &operator=(const GpgUID &) = delete; + auto operator=(const GpgUID &) -> GpgUID & = delete; private: using UidRefHandler = @@ -148,5 +148,3 @@ class GPGFRONTEND_CORE_EXPORT GpgUID { }; } // namespace GpgFrontend - -#endif // GPGFRONTEND_GPGUID_H
\ No newline at end of file diff --git a/src/core/model/GpgVerifyResult.cpp b/src/core/model/GpgVerifyResult.cpp new file mode 100644 index 00000000..75421c69 --- /dev/null +++ b/src/core/model/GpgVerifyResult.cpp @@ -0,0 +1,62 @@ +/** + * 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 "GpgVerifyResult.h" + +#include "core/model/GpgSignature.h" + +namespace GpgFrontend { +GpgVerifyResult::GpgVerifyResult(gpgme_verify_result_t r) + : result_ref_(std::shared_ptr<struct _gpgme_op_verify_result>( + (gpgme_result_ref(r), r), [](gpgme_verify_result_t p) { + if (p != nullptr) { + gpgme_result_unref(p); + } + })) {} + +GpgVerifyResult::GpgVerifyResult() = default; + +GpgVerifyResult::~GpgVerifyResult() = default; + +auto GpgVerifyResult::IsGood() const -> bool { return result_ref_ != nullptr; } + +auto GpgVerifyResult::GetRaw() const -> gpgme_verify_result_t { + return result_ref_.get(); +} + +auto GpgVerifyResult::GetSignature() const -> std::vector<GpgSignature> { + std::vector<GpgSignature> sigatures; + + auto* signature = result_ref_->signatures; + while (signature != nullptr) { + sigatures.emplace_back(signature); + signature = signature->next; + } + return sigatures; +} +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/model/GpgVerifyResult.h b/src/core/model/GpgVerifyResult.h new file mode 100644 index 00000000..cae43c10 --- /dev/null +++ b/src/core/model/GpgVerifyResult.h @@ -0,0 +1,53 @@ +/** + * 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/GpgFrontendCoreExport.h" +#include "core/typedef/GpgTypedef.h" + +namespace GpgFrontend { + +class GPGFRONTEND_CORE_EXPORT GpgVerifyResult { + public: + [[nodiscard]] auto IsGood() const -> bool; + + [[nodiscard]] auto GetRaw() const -> gpgme_verify_result_t; + + [[nodiscard]] auto GetSignature() const -> std::vector<GpgSignature>; + + explicit GpgVerifyResult(gpgme_verify_result_t); + + GpgVerifyResult(); + + virtual ~GpgVerifyResult(); + + private: + std::shared_ptr<struct _gpgme_op_verify_result> result_ref_ = nullptr; ///< +}; +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/module/Event.cpp b/src/core/module/Event.cpp new file mode 100644 index 00000000..fab26453 --- /dev/null +++ b/src/core/module/Event.cpp @@ -0,0 +1,139 @@ +/** + * 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 "Event.h" + +namespace GpgFrontend::Module { + +class Event::Impl { + public: + Impl(QString event_id, std::initializer_list<ParameterInitializer> params, + EventCallback callback) + : event_identifier_(std::move(event_id)), + callback_(std::move(callback)), + callback_thread_(QThread::currentThread()) { + for (const auto& param : params) { + AddParameter(param); + } + GF_CORE_LOG_DEBUG("create event {}", event_identifier_); + } + + auto operator[](const QString& key) const -> std::optional<ParameterValue> { + auto it_data = data_.find(key); + if (it_data != data_.end()) { + return it_data->second; + } + return std::nullopt; + } + + auto operator==(const Event& other) const -> bool { + return event_identifier_ == other.p_->event_identifier_; + } + + auto operator!=(const Event& other) const -> bool { + return !(*this == other); + } + + auto operator<(const Event& other) const -> bool { + return this->event_identifier_ < other.p_->event_identifier_; + } + + explicit operator QString() const { return event_identifier_; } + + auto GetIdentifier() -> EventIdentifier { return event_identifier_; } + + void AddParameter(const QString& key, const ParameterValue& value) { + data_[key] = value; + } + + void AddParameter(const ParameterInitializer& param) { + AddParameter(param.key, param.value); + } + + void ExecuteCallback(ListenerIdentifier listener_id, + const DataObjectPtr& data_object) { + GF_CORE_LOG_DEBUG("try to execute callback for event {} with listener {}", + event_identifier_, listener_id); + if (callback_) { + GF_CORE_LOG_DEBUG("executing callback for event {} with listener {}", + event_identifier_, listener_id); + if (!QMetaObject::invokeMethod( + callback_thread_, + [callback = callback_, event_identifier = event_identifier_, + listener_id, data_object]() { + callback(event_identifier, listener_id, data_object); + })) { + GF_CORE_LOG_ERROR( + "failed to invoke callback for event {} with listener {}", + event_identifier_, listener_id); + } + } + } + + private: + EventIdentifier event_identifier_; + std::map<QString, ParameterValue> data_; + EventCallback callback_; + QThread* callback_thread_ = nullptr; ///< +}; + +Event::Event(const QString& event_id, + std::initializer_list<ParameterInitializer> params, + EventCallback callback) + : p_(SecureCreateUniqueObject<Impl>(event_id, params, + std::move(callback))) {} + +Event::~Event() = default; + +auto Event::Event::operator==(const Event& other) const -> bool { + return this->p_ == other.p_; +} + +auto Event::Event::operator!=(const Event& other) const -> bool { + return this->p_ != other.p_; +} + +auto Event::Event::operator<(const Event& other) const -> bool { + return this->p_ < other.p_; +} + +Event::Event::operator QString() const { return static_cast<QString>(*p_); } + +auto Event::Event::GetIdentifier() -> EventIdentifier { + return p_->GetIdentifier(); +} + +void Event::AddParameter(const QString& key, const ParameterValue& value) { + p_->AddParameter(key, value); +} + +void Event::ExecuteCallback(ListenerIdentifier l_id, DataObjectPtr d_o) { + p_->ExecuteCallback(std::move(l_id), d_o); +} + +} // namespace GpgFrontend::Module
\ No newline at end of file diff --git a/src/core/module/Event.h b/src/core/module/Event.h new file mode 100644 index 00000000..92268216 --- /dev/null +++ b/src/core/module/Event.h @@ -0,0 +1,95 @@ +/** + * 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 <any> +#include <functional> +#include <optional> + +#include "core/GpgFrontendCore.h" +#include "core/model/DataObject.h" + +namespace GpgFrontend::Module { + +class Event; + +using EventRefrernce = std::shared_ptr<Event>; +using EventIdentifier = QString; +using Evnets = std::vector<Event>; + +class GPGFRONTEND_CORE_EXPORT Event { + public: + using ParameterValue = std::any; + using EventIdentifier = QString; + using ListenerIdentifier = QString; + using EventCallback = + std::function<void(EventIdentifier, ListenerIdentifier, DataObjectPtr)>; + struct ParameterInitializer { + QString key; + ParameterValue value; + }; + + explicit Event(const QString&, + std::initializer_list<ParameterInitializer> = {}, + EventCallback = nullptr); + + ~Event(); + + auto operator[](const QString& key) const -> std::optional<ParameterValue>; + + auto operator==(const Event& other) const -> bool; + + auto operator!=(const Event& other) const -> bool; + + auto operator<(const Event& other) const -> bool; + + auto operator<=(const Event& other) const -> bool; + + explicit operator QString() const; + + auto GetIdentifier() -> EventIdentifier; + + void AddParameter(const QString& key, const ParameterValue& value); + + void ExecuteCallback(ListenerIdentifier, DataObjectPtr); + + private: + class Impl; + SecureUniquePtr<Impl> p_; +}; + +template <typename... Args> +auto MakeEvent(const EventIdentifier& event_id, Args&&... args, + Event::EventCallback e_cb) -> EventRefrernce { + std::initializer_list<Event::ParameterInitializer> params = { + Event::ParameterInitializer{std::forward<Args>(args)}...}; + return GpgFrontend::SecureCreateSharedObject<Event>(event_id, params, e_cb); +} + +} // namespace GpgFrontend::Module
\ No newline at end of file diff --git a/src/core/module/GlobalModuleContext.cpp b/src/core/module/GlobalModuleContext.cpp new file mode 100644 index 00000000..9bc4f06b --- /dev/null +++ b/src/core/module/GlobalModuleContext.cpp @@ -0,0 +1,377 @@ +/** + * 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 "GlobalModuleContext.h" + +#include <set> +#include <unordered_map> +#include <unordered_set> + +#include "core/module/Event.h" +#include "core/module/Module.h" +#include "core/thread/Task.h" +#include "model/DataObject.h" +#include "thread/TaskRunnerGetter.h" +#include "utils/MemoryUtils.h" + +namespace GpgFrontend::Module { + +class GlobalModuleContext::Impl { + public: + explicit Impl() { + // Initialize acquired channels with default values. + acquired_channel_.insert(kGpgFrontendDefaultChannel); + acquired_channel_.insert(kGpgFrontendNonAsciiChannel); + } + + auto GetChannel(ModuleRawPtr module) -> int { + // Search for the module in the register table. + auto module_info_opt = + search_module_register_table(module->GetModuleIdentifier()); + if (!module_info_opt.has_value()) { + GF_CORE_LOG_ERROR( + "cannot find module id {} at register table, fallbacking to " + "default " + "channel", + module->GetModuleIdentifier()); + return GetDefaultChannel(module); + } + + auto module_info = module_info_opt.value(); + return module_info->channel; + } + + static auto GetDefaultChannel(ModuleRawPtr) -> int { + return kGpgFrontendDefaultChannel; + } + + auto GetTaskRunner(ModuleRawPtr /*module*/) -> std::optional<TaskRunnerPtr> { + return Thread::TaskRunnerGetter::GetInstance().GetTaskRunner( + Thread::TaskRunnerGetter::kTaskRunnerType_Module); + } + + auto GetTaskRunner(ModuleIdentifier /*module_id*/) + -> std::optional<TaskRunnerPtr> { + return Thread::TaskRunnerGetter::GetInstance().GetTaskRunner( + Thread::TaskRunnerGetter::kTaskRunnerType_Module); + } + + auto GetGlobalTaskRunner() -> std::optional<TaskRunnerPtr> { + return default_task_runner_; + } + + auto RegisterModule(const ModulePtr& module) -> bool { + GF_CORE_LOG_DEBUG("attempting to register module: {}", + module->GetModuleIdentifier()); + // Check if the module is null or already registered. + if (module == nullptr || + module_register_table_.find(module->GetModuleIdentifier()) != + module_register_table_.end()) { + GF_CORE_LOG_ERROR( + "module is null or have already registered this module"); + return false; + } + + if (!module->Register()) { + GF_CORE_LOG_ERROR("register module {} failed", + module->GetModuleIdentifier()); + return false; + } + + auto register_info = + GpgFrontend::SecureCreateSharedObject<ModuleRegisterInfo>(); + register_info->module = module; + register_info->channel = acquire_new_unique_channel(); + + // move module to its task runner' thread + register_info->module->setParent(nullptr); + register_info->module->moveToThread( + Thread::TaskRunnerGetter::GetInstance() + .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_Module) + ->GetThread()); + + // Register the module with its identifier. + module_register_table_[module->GetModuleIdentifier()] = register_info; + + GF_CORE_LOG_DEBUG("successfully registered module: {}", + module->GetModuleIdentifier()); + return true; + } + + auto ActiveModule(ModuleIdentifier module_id) -> bool { + GF_CORE_LOG_DEBUG("attempting to activate module: {}", module_id); + + // Search for the module in the register table. + auto module_info_opt = search_module_register_table(module_id); + if (!module_info_opt.has_value()) { + GF_CORE_LOG_ERROR("cannot find module id {} at register table", + module_id); + return false; + } + + auto module_info = module_info_opt.value(); + + // try to get module from module info + auto module = module_info->module; + if (module == nullptr) { + GF_CORE_LOG_ERROR( + "module id {} at register table is releated to a null module", + module_id); + return false; + } + + // Activate the module if it is not already active. + if (!module_info->activate) { + module->Active(); + module_info->activate = true; + } + + GF_CORE_LOG_DEBUG("module activation status: {}", module_info->activate); + return module_info->activate; + } + + auto ListenEvent(ModuleIdentifier module_id, EventIdentifier event) -> bool { + GF_CORE_LOG_DEBUG("module: {} is attempting to listen to event {}", + module_id, event); + // Check if the event exists, if not, create it. + auto met_it = module_events_table_.find(event); + if (met_it == module_events_table_.end()) { + module_events_table_[event] = std::unordered_set<ModuleIdentifier>(); + met_it = module_events_table_.find(event); + GF_CORE_LOG_DEBUG("new event {} of module system created", event); + } + + auto& listeners_set = met_it->second; + // Add the listener (module) to the event. + auto listener_it = listeners_set.find(module_id); + if (listener_it == listeners_set.end()) { + listeners_set.insert(module_id); + } + return true; + } + + auto DeactivateModule(ModuleIdentifier module_id) -> bool { + // Search for the module in the register table. + auto module_info_opt = search_module_register_table(module_id); + if (!module_info_opt.has_value()) { + GF_CORE_LOG_ERROR("cannot find module id {} at register table", + module_id); + return false; + } + + auto module_info = module_info_opt.value(); + // Activate the module if it is not already deactive. + if (!module_info->activate && module_info->module->Deactive()) { + module_info->activate = false; + } + + return !module_info->activate; + } + + auto TriggerEvent(const EventRefrernce& event) -> bool { + auto event_id = event->GetIdentifier(); + GF_CORE_LOG_DEBUG("attempting to trigger event: {}", event_id); + + // Find the set of listeners associated with the given event in the table + auto met_it = module_events_table_.find(event_id); + if (met_it == module_events_table_.end()) { + // Log a warning if the event is not registered and nobody is listening + GF_CORE_LOG_WARN( + "event {} is not listening by anyone and not registered as well", + event_id); + return false; + } + + // Retrieve the set of listeners for this event + auto& listeners_set = met_it->second; + + // Check if the set of listeners is empty + if (listeners_set.empty()) { + // Log a warning if nobody is listening to this event + GF_CORE_LOG_WARN("event {} is not listening by anyone", + event->GetIdentifier()); + return false; + } + + // Log the number of listeners for this event + GF_CORE_LOG_DEBUG("event {}'s current listeners size: {}", + event->GetIdentifier(), listeners_set.size()); + + // Iterate through each listener and execute the corresponding module + for (const auto& listener_module_id : listeners_set) { + // Search for the module's information in the registration table + auto module_info_opt = search_module_register_table(listener_module_id); + + // Log an error if the module is not found in the registration table + if (!module_info_opt.has_value()) { + GF_CORE_LOG_ERROR("cannot find module id {} at register table", + listener_module_id); + continue; + } + + // Retrieve the module's information + auto module_info = module_info_opt.value(); + auto module = module_info->module; + + GF_CORE_LOG_DEBUG( + "module {} is listening to event {}, activate state: {}", + module_info->module->GetModuleIdentifier(), event->GetIdentifier(), + module_info->activate); + + // Check if the module is activated + if (!module_info->activate) continue; + + Thread::Task::TaskRunnable const exec_runnerable = + [module, event](DataObjectPtr) -> int { return module->Exec(event); }; + + Thread::Task::TaskCallback const exec_callback = + [listener_module_id, event_id](int code, DataObjectPtr) { + if (code < 0) { + // Log an error if the module execution fails + GF_CORE_LOG_ERROR( + "module {} execution failed of event {}: exec return code {}", + listener_module_id, event_id, code); + } + }; + + Thread::TaskRunnerGetter::GetInstance() + .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_Module) + ->PostTask(new Thread::Task(exec_runnerable, + QString("event/%1/module/exec/%2") + .arg(event_id) + .arg(listener_module_id), + nullptr, exec_callback)); + } + + // Return true to indicate successful execution of all modules + return true; + } + + auto IsModuleActivated(const ModuleIdentifier& m_id) const -> bool { + auto m = search_module_register_table(m_id); + return m.has_value() && m->get()->activate; + } + + private: + struct ModuleRegisterInfo { + int channel; + ModulePtr module; + bool activate; + }; + + using ModuleRegisterInfoPtr = std::shared_ptr<ModuleRegisterInfo>; + + std::unordered_map<ModuleIdentifier, ModuleRegisterInfoPtr> + module_register_table_; + std::map<EventIdentifier, std::unordered_set<ModuleIdentifier>> + module_events_table_; + + std::set<int> acquired_channel_; + TaskRunnerPtr default_task_runner_; + + auto acquire_new_unique_channel() -> int { + int random_channel = QRandomGenerator::global()->bounded(65535); + // Ensure the acquired channel is unique. + while (acquired_channel_.find(random_channel) != acquired_channel_.end()) { + random_channel = QRandomGenerator::global()->bounded(65535); + } + + // Add the acquired channel to the set. + acquired_channel_.insert(random_channel); + return random_channel; + } + + // Function to search for a module in the register table. + auto search_module_register_table(const ModuleIdentifier& identifier) const + -> std::optional<ModuleRegisterInfoPtr> { + auto mrt_it = module_register_table_.find(identifier); + if (mrt_it == module_register_table_.end()) { + return std::nullopt; + } + return mrt_it->second; + } +}; + +// Constructor for GlobalModuleContext, takes a TaskRunnerPtr as an argument. +GlobalModuleContext::GlobalModuleContext() + : p_(SecureCreateUniqueObject<Impl>()) {} + +GlobalModuleContext::~GlobalModuleContext() = default; + +// Function to get the task runner associated with a module. +auto GlobalModuleContext::GetTaskRunner(ModuleRawPtr module) + -> std::optional<TaskRunnerPtr> { + return p_->GetTaskRunner(module); +} + +// Function to get the task runner associated with a module. +auto GlobalModuleContext::GetTaskRunner(ModuleIdentifier module_id) + -> std::optional<TaskRunnerPtr> { + return p_->GetTaskRunner(std::move(module_id)); +} + +// Function to get the global task runner. +auto GlobalModuleContext::GetGlobalTaskRunner() + -> std::optional<TaskRunnerPtr> { + return p_->GetGlobalTaskRunner(); +} + +auto GlobalModuleContext::RegisterModule(ModulePtr module) -> bool { + return p_->RegisterModule(std::move(module)); +} + +auto GlobalModuleContext::ActiveModule(ModuleIdentifier module_id) -> bool { + return p_->ActiveModule(std::move(module_id)); +} + +auto GlobalModuleContext::ListenEvent(ModuleIdentifier module_id, + EventIdentifier event) -> bool { + return p_->ListenEvent(std::move(module_id), std::move(event)); +} + +auto GlobalModuleContext::DeactivateModule(ModuleIdentifier module_id) -> bool { + return p_->DeactivateModule(std::move(module_id)); +} + +auto GlobalModuleContext::TriggerEvent(EventRefrernce event) -> bool { + return p_->TriggerEvent(std::move(event)); +} + +auto GlobalModuleContext::GetChannel(ModuleRawPtr module) -> int { + return p_->GetChannel(module); +} + +auto GlobalModuleContext::GetDefaultChannel(ModuleRawPtr channel) -> int { + return GlobalModuleContext::Impl::GetDefaultChannel(channel); +} + +auto GlobalModuleContext::IsModuleActivated(ModuleIdentifier m_id) -> bool { + return p_->IsModuleActivated(std::move(m_id)); +} + +} // namespace GpgFrontend::Module diff --git a/src/core/module/GlobalModuleContext.h b/src/core/module/GlobalModuleContext.h new file mode 100644 index 00000000..1c971bb5 --- /dev/null +++ b/src/core/module/GlobalModuleContext.h @@ -0,0 +1,88 @@ +/** + * 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 <optional> + +#include "core/module/Event.h" +#include "core/thread/TaskRunner.h" +#include "function/SecureMemoryAllocator.h" +#include "module/GlobalRegisterTable.h" + +namespace GpgFrontend::Module { + +class GlobalModuleContext; +class GlobalRegisterTable; + +class Module; +class ModuleManager; +using ModuleIdentifier = QString; +using ModulePtr = std::shared_ptr<Module>; +using ModuleRawPtr = Module*; + +using GMCPtr = std::shared_ptr<GlobalModuleContext>; +using GRTPtr = std::shared_ptr<GlobalRegisterTable>; + +using TaskRunnerPtr = std::shared_ptr<Thread::TaskRunner>; + +class GPGFRONTEND_CORE_EXPORT GlobalModuleContext : public QObject { + Q_OBJECT + public: + explicit GlobalModuleContext(); + + ~GlobalModuleContext() override; + + auto GetChannel(ModuleRawPtr) -> int; + + static auto GetDefaultChannel(ModuleRawPtr) -> int; + + auto GetTaskRunner(ModuleRawPtr) -> std::optional<TaskRunnerPtr>; + + auto GetTaskRunner(ModuleIdentifier) -> std::optional<TaskRunnerPtr>; + + auto GetGlobalTaskRunner() -> std::optional<TaskRunnerPtr>; + + auto RegisterModule(ModulePtr) -> bool; + + auto ActiveModule(ModuleIdentifier) -> bool; + + auto DeactivateModule(ModuleIdentifier) -> bool; + + auto ListenEvent(ModuleIdentifier, EventIdentifier) -> bool; + + auto TriggerEvent(EventRefrernce) -> bool; + + auto IsModuleActivated(ModuleIdentifier) -> bool; + + private: + class Impl; + SecureUniquePtr<Impl> p_; +}; + +} // namespace GpgFrontend::Module
\ No newline at end of file diff --git a/src/core/module/GlobalRegisterTable.cpp b/src/core/module/GlobalRegisterTable.cpp new file mode 100644 index 00000000..c16eba37 --- /dev/null +++ b/src/core/module/GlobalRegisterTable.cpp @@ -0,0 +1,167 @@ +/** + * 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 "GlobalRegisterTable.h" + +#include <any> +#include <optional> +#include <shared_mutex> +#include <sstream> +#include <unordered_map> +#include <vector> + +#include "function/SecureMemoryAllocator.h" +#include "utils/MemoryUtils.h" + +namespace GpgFrontend::Module { + +class GlobalRegisterTable::Impl { + public: + struct RTNode { + std::optional<std::any> value = std::nullopt; + std::unordered_map<QString, SecureUniquePtr<RTNode>> children; + int version = 0; + const std::type_info* type = nullptr; + }; + + explicit Impl(GlobalRegisterTable* parent) : parent_(parent) {} + + auto PublishKV(const Namespace& n, const Key& k, std::any v) -> bool { + QStringList const segments = k.split('.'); + int version = 0; + + { + std::unique_lock lock(lock_); + auto& root_rt_node = + global_register_table_.emplace(n, SecureCreateUniqueObject<RTNode>()) + .first->second; + + RTNode* current = root_rt_node.get(); + for (const QString& segment : segments) { + current = current->children + .emplace(segment, SecureCreateUniqueObject<RTNode>()) + .first->second.get(); + } + + current->value = v; + current->type = &v.type(); + version = ++current->version; + } + + emit parent_->SignalPublish(n, k, version, v); + return true; + } + + auto LookupKV(const Namespace& n, const Key& k) -> std::optional<std::any> { + QStringList const segments = k.split('.'); + + std::optional<std::any> rtn = std::nullopt; + { + std::shared_lock const lock(lock_); + auto it = global_register_table_.find(n); + if (it == global_register_table_.end()) return std::nullopt; + + RTNode* current = it->second.get(); + for (const QString& segment : segments) { + auto it = current->children.find(segment); + if (it == current->children.end()) return std::nullopt; + current = it->second.get(); + } + rtn = current->value; + } + return rtn; + } + + auto ListChildKeys(const Namespace& n, const Key& k) -> std::vector<Key> { + QStringList const segments = k.split('.'); + + std::vector<Key> rtn; + { + std::shared_lock lock(lock_); + auto it = global_register_table_.find(n); + if (it == global_register_table_.end()) return {}; + + RTNode* current = it->second.get(); + for (const QString& segment : segments) { + auto it = current->children.find(segment); + if (it == current->children.end()) return {}; + current = it->second.get(); + } + + for (auto& it : current->children) { + rtn.emplace_back(it.first); + } + } + return rtn; + } + + auto ListenPublish(QObject* o, const Namespace& n, const Key& k, LPCallback c) + -> bool { + if (o == nullptr) return false; + return QObject::connect(parent_, &GlobalRegisterTable::SignalPublish, o, + [n, k, c](const Namespace& pn, const Key& pk, + int ver, std::any value) { + if (pn == n && pk == k) { + c(pn, pk, ver, std::move(value)); + } + }) == nullptr; + } + + private: + using Table = std::map<Namespace, SecureUniquePtr<RTNode>>; + std::shared_mutex lock_; + GlobalRegisterTable* parent_; + + Table global_register_table_; +}; + +GlobalRegisterTable::GlobalRegisterTable() + : p_(SecureCreateUniqueObject<Impl>(this)) {} + +GlobalRegisterTable::~GlobalRegisterTable() = default; + +auto GlobalRegisterTable::PublishKV(Namespace n, Key k, std::any v) -> bool { + return p_->PublishKV(n, k, v); +} + +auto GlobalRegisterTable::LookupKV(Namespace n, Key v) + -> std::optional<std::any> { + return p_->LookupKV(n, v); +} + +auto GlobalRegisterTable::ListenPublish(QObject* o, Namespace n, Key k, + LPCallback c) -> bool { + return p_->ListenPublish(o, n, k, c); +} + +auto GlobalRegisterTable::ListChildKeys(Namespace n, Key k) + -> std::vector<Key> { + return p_->ListChildKeys(n, k); +} + +} // namespace GpgFrontend::Module
\ No newline at end of file diff --git a/src/core/module/GlobalRegisterTable.h b/src/core/module/GlobalRegisterTable.h new file mode 100644 index 00000000..db68c888 --- /dev/null +++ b/src/core/module/GlobalRegisterTable.h @@ -0,0 +1,66 @@ +/** + * 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 <any> +#include <functional> +#include <optional> + +#include "function/SecureMemoryAllocator.h" + +namespace GpgFrontend::Module { + +using Namespace = QString; +using Key = QString; +using LPCallback = std::function<void(Namespace, Key, int, std::any)>; + +class GlobalRegisterTable : public QObject { + Q_OBJECT + public: + GlobalRegisterTable(); + + ~GlobalRegisterTable() override; + + auto PublishKV(Namespace, Key, std::any) -> bool; + + auto LookupKV(Namespace, Key) -> std::optional<std::any>; + + auto ListenPublish(QObject *, Namespace, Key, LPCallback) -> bool; + + auto ListChildKeys(Namespace n, Key k) -> std::vector<Key>; + + signals: + void SignalPublish(Namespace, Key, int, std::any); + + private: + class Impl; + SecureUniquePtr<Impl> p_; +}; + +} // namespace GpgFrontend::Module
\ No newline at end of file diff --git a/src/core/module/GpgFrontendModuleSystem.h b/src/core/module/GpgFrontendModuleSystem.h new file mode 100644 index 00000000..903aec69 --- /dev/null +++ b/src/core/module/GpgFrontendModuleSystem.h @@ -0,0 +1,34 @@ +/** + * 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/GpgFrontendCore.h> +#include <core/module/Event.h> +#include <core/module/Module.h> +#include <core/module/ModuleManager.h>
\ No newline at end of file diff --git a/src/core/module/Module.cpp b/src/core/module/Module.cpp new file mode 100644 index 00000000..9076dc2c --- /dev/null +++ b/src/core/module/Module.cpp @@ -0,0 +1,106 @@ +/** + * 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 "Module.h" + +#include "core/module/GlobalModuleContext.h" + +namespace GpgFrontend::Module { + +class Module::Impl { + public: + friend class GlobalModuleContext; + + using ExecCallback = std::function<void(int)>; + + Impl(ModuleRawPtr m_ptr, ModuleIdentifier id, ModuleVersion version, + ModuleMetaData meta_data) + : m_ptr_(m_ptr), + identifier_(std::move(id)), + version_(std::move(version)), + meta_data_(std::move(meta_data)) {} + + auto GetChannel() -> int { return get_gpc()->GetChannel(m_ptr_); } + + auto GetDefaultChannel() -> int { + return GlobalModuleContext::GetDefaultChannel(m_ptr_); + } + + auto GetTaskRunner() -> std::optional<TaskRunnerPtr> { + return get_gpc()->GetTaskRunner(m_ptr_); + } + + auto ListenEvent(EventIdentifier event) -> bool { + return get_gpc()->ListenEvent(GetModuleIdentifier(), std::move(event)); + } + + [[nodiscard]] auto GetModuleIdentifier() const -> ModuleIdentifier { + return identifier_; + } + + void SetGPC(GlobalModuleContext* gpc) { gpc_ = gpc; } + + private: + GlobalModuleContext* gpc_{}; + Module* m_ptr_; + const ModuleIdentifier identifier_; + const ModuleVersion version_; + const ModuleMetaData meta_data_; + + auto get_gpc() -> GlobalModuleContext* { + if (gpc_ == nullptr) { + throw std::runtime_error("module is not registered by module manager"); + } + return gpc_; + } +}; + +Module::Module(ModuleIdentifier id, ModuleVersion version, + const ModuleMetaData& meta_data) + : p_(SecureCreateUniqueObject<Impl>(this, id, version, meta_data)) {} + +Module::~Module() = default; + +auto Module::getChannel() -> int { return p_->GetChannel(); } + +auto Module::getDefaultChannel() -> int { return p_->GetDefaultChannel(); } + +auto Module::getTaskRunner() -> TaskRunnerPtr { + return p_->GetTaskRunner().value_or(nullptr); +} + +auto Module::listenEvent(EventIdentifier event) -> bool { + return p_->ListenEvent(std::move(event)); +} + +auto Module::GetModuleIdentifier() const -> ModuleIdentifier { + return p_->GetModuleIdentifier(); +} + +void Module::SetGPC(GlobalModuleContext* gpc) { p_->SetGPC(gpc); } +} // namespace GpgFrontend::Module
\ No newline at end of file diff --git a/src/core/module/Module.h b/src/core/module/Module.h new file mode 100644 index 00000000..2a5b54e7 --- /dev/null +++ b/src/core/module/Module.h @@ -0,0 +1,80 @@ +/** + * 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/module/Event.h" +#include "core/thread/TaskRunner.h" + +namespace GpgFrontend::Module { + +class Module; +class GlobalModuleContext; +class ModuleManager; + +using ModuleIdentifier = QString; +using ModuleVersion = QString; +using ModuleMetaData = std::map<QString, QString>; +using ModulePtr = std::shared_ptr<Module>; + +using TaskRunnerPtr = std::shared_ptr<Thread::TaskRunner>; + +class GPGFRONTEND_CORE_EXPORT Module : public QObject { + Q_OBJECT + public: + Module(ModuleIdentifier, ModuleVersion, const ModuleMetaData&); + + ~Module(); + + virtual auto Register() -> bool = 0; + + virtual auto Active() -> bool = 0; + + virtual auto Exec(EventRefrernce) -> int = 0; + + virtual auto Deactive() -> bool = 0; + + [[nodiscard]] auto GetModuleIdentifier() const -> ModuleIdentifier; + + void SetGPC(GlobalModuleContext*); + + protected: + auto getChannel() -> int; + + auto getDefaultChannel() -> int; + + auto getTaskRunner() -> TaskRunnerPtr; + + auto listenEvent(EventIdentifier) -> bool; + + private: + class Impl; + SecureUniquePtr<Impl> p_; +}; + +} // namespace GpgFrontend::Module
\ No newline at end of file diff --git a/src/core/module/ModuleManager.cpp b/src/core/module/ModuleManager.cpp new file mode 100644 index 00000000..83e7c1ff --- /dev/null +++ b/src/core/module/ModuleManager.cpp @@ -0,0 +1,184 @@ +/** + * 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 "ModuleManager.h" + +#include <memory> + +#include "GpgConstants.h" +#include "core/module/GlobalModuleContext.h" +#include "core/module/GlobalRegisterTable.h" +#include "core/module/Module.h" +#include "core/thread/Task.h" +#include "function/SecureMemoryAllocator.h" +#include "function/basic/GpgFunctionObject.h" +#include "thread/TaskRunnerGetter.h" +#include "utils/MemoryUtils.h" + +namespace GpgFrontend::Module { + +class ModuleManager::Impl { + public: + Impl() + : gmc_(GpgFrontend::SecureCreateUniqueObject<GlobalModuleContext>()), + grt_(GpgFrontend::SecureCreateUniqueObject<GlobalRegisterTable>()) {} + + ~Impl() = default; + + void RegisterModule(const ModulePtr& module) { + Thread::TaskRunnerGetter::GetInstance() + .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_Default) + ->PostTask(new Thread::Task( + [=](GpgFrontend::DataObjectPtr) -> int { + module->SetGPC(gmc_.get()); + gmc_->RegisterModule(module); + return 0; + }, + __func__, nullptr)); + } + + void TriggerEvent(const EventRefrernce& event) { + Thread::TaskRunnerGetter::GetInstance() + .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_Default) + ->PostTask(new Thread::Task( + [=](const GpgFrontend::DataObjectPtr&) -> int { + gmc_->TriggerEvent(event); + return 0; + }, + __func__, nullptr)); + } + + void ActiveModule(const ModuleIdentifier& identifier) { + Thread::TaskRunnerGetter::GetInstance() + .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_Default) + ->PostTask(new Thread::Task( + [=](const GpgFrontend::DataObjectPtr&) -> int { + gmc_->ActiveModule(identifier); + return 0; + }, + __func__, nullptr)); + } + + auto GetTaskRunner(ModuleIdentifier module_id) + -> std::optional<TaskRunnerPtr> { + return gmc_->GetTaskRunner(std::move(module_id)); + } + + auto UpsertRTValue(Namespace n, Key k, std::any v) -> bool { + return grt_->PublishKV(n, k, v); + } + + auto RetrieveRTValue(Namespace n, Key k) -> std::optional<std::any> { + return grt_->LookupKV(n, k); + } + + auto ListenPublish(QObject* o, Namespace n, Key k, LPCallback c) -> bool { + return grt_->ListenPublish(o, n, k, c); + } + + auto ListRTChildKeys(const QString& n, const QString& k) -> std::vector<Key> { + return grt_->ListChildKeys(n, k); + } + + auto IsModuleActivated(ModuleIdentifier id) -> bool { + return gmc_->IsModuleActivated(id); + } + + private: + static ModuleMangerPtr global_module_manager; + SecureUniquePtr<GlobalModuleContext> gmc_; + SecureUniquePtr<GlobalRegisterTable> grt_; +}; + +auto IsModuleAcivate(ModuleIdentifier id) -> bool { + return ModuleManager::GetInstance().IsModuleActivated(id); +} + +auto UpsertRTValue(const QString& namespace_, const QString& key, + const std::any& value) -> bool { + return ModuleManager::GetInstance().UpsertRTValue(namespace_, key, + std::any(value)); +} + +auto ListenRTPublishEvent(QObject* o, Namespace n, Key k, LPCallback c) + -> bool { + return ModuleManager::GetInstance().ListenRTPublish(o, n, k, c); +} + +auto ListRTChildKeys(const QString& namespace_, const QString& key) + -> std::vector<Key> { + return ModuleManager::GetInstance().ListRTChildKeys(namespace_, key); +} + +ModuleManager::ModuleManager(int channel) + : SingletonFunctionObject<ModuleManager>(channel), + p_(SecureCreateUniqueObject<Impl>()) {} + +ModuleManager::~ModuleManager() = default; + +void ModuleManager::RegisterModule(ModulePtr module) { + return p_->RegisterModule(module); +} + +void ModuleManager::TriggerEvent(EventRefrernce event) { + return p_->TriggerEvent(event); +} + +void ModuleManager::ActiveModule(ModuleIdentifier id) { + return p_->ActiveModule(id); +} + +auto ModuleManager::GetTaskRunner(ModuleIdentifier id) + -> std::optional<TaskRunnerPtr> { + return p_->GetTaskRunner(std::move(id)); +} + +auto ModuleManager::UpsertRTValue(Namespace n, Key k, std::any v) -> bool { + return p_->UpsertRTValue(n, k, v); +} + +auto ModuleManager::RetrieveRTValue(Namespace n, Key k) + -> std::optional<std::any> { + return p_->RetrieveRTValue(n, k); +} + +auto ModuleManager::ListenRTPublish(QObject* o, Namespace n, Key k, + LPCallback c) -> bool { + return p_->ListenPublish(o, n, k, c); +} + +auto ModuleManager::ListRTChildKeys(const QString& n, const QString& k) + -> std::vector<Key> { + return p_->ListRTChildKeys(n, k); +} + +auto ModuleManager::IsModuleActivated(ModuleIdentifier id) -> bool { + return p_->IsModuleActivated(id); +} + +} // namespace GpgFrontend::Module
\ No newline at end of file diff --git a/src/core/module/ModuleManager.h b/src/core/module/ModuleManager.h new file mode 100644 index 00000000..93b89e95 --- /dev/null +++ b/src/core/module/ModuleManager.h @@ -0,0 +1,179 @@ +/** + * 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 <mutex> +#include <vector> + +#include "core/function/SecureMemoryAllocator.h" +#include "core/function/basic/GpgFunctionObject.h" +#include "core/module/Event.h" +#include "core/utils/MemoryUtils.h" + +namespace GpgFrontend::Thread { +class TaskRunner; +} + +namespace GpgFrontend::Module { + +using TaskRunnerPtr = std::shared_ptr<Thread::TaskRunner>; + +class Event; +class Module; +class GlobalModuleContext; +class ModuleManager; + +using EventRefrernce = std::shared_ptr<Event>; +using ModuleIdentifier = QString; +using ModulePtr = std::shared_ptr<Module>; +using ModuleMangerPtr = std::shared_ptr<ModuleManager>; +using GMCPtr = std::shared_ptr<GlobalModuleContext>; +using Namespace = QString; +using Key = QString; +using LPCallback = std::function<void(Namespace, Key, int, std::any)>; + +class GPGFRONTEND_CORE_EXPORT ModuleManager + : public SingletonFunctionObject<ModuleManager> { + public: + explicit ModuleManager(int channel); + + virtual ~ModuleManager() override; + + void RegisterModule(ModulePtr); + + auto IsModuleActivated(ModuleIdentifier) -> bool; + + void TriggerEvent(EventRefrernce); + + void ActiveModule(ModuleIdentifier); + + void DeactiveModule(ModuleIdentifier); + + auto GetTaskRunner(ModuleIdentifier) -> std::optional<TaskRunnerPtr>; + + auto UpsertRTValue(Namespace, Key, std::any) -> bool; + + auto RetrieveRTValue(Namespace, Key) -> std::optional<std::any>; + + auto ListenRTPublish(QObject*, Namespace, Key, LPCallback) -> bool; + + auto ListRTChildKeys(const QString&, const QString&) -> std::vector<Key>; + + private: + class Impl; + SecureUniquePtr<Impl> p_; +}; + +template <typename T, typename... Args> +void RegisterModule(Args&&... args) { + ModuleManager::GetInstance().RegisterModule( + GpgFrontend::SecureCreateSharedObject<T>(std::forward<Args>(args)...)); +} + +template <typename T, typename... Args> +void RegisterAndActivateModule(Args&&... args) { + auto& manager = ModuleManager::GetInstance(); + auto module = + GpgFrontend::SecureCreateSharedObject<T>(std::forward<Args>(args)...); + manager.RegisterModule(module); + manager.ActiveModule(module->GetModuleIdentifier()); +} + +template <typename... Args> +void TriggerEvent(const EventIdentifier& event_id, Args&&... args, + Event::EventCallback e_cb = nullptr) { + ModuleManager::GetInstance().TriggerEvent( + std::move(MakeEvent(event_id, std::forward<Args>(args)..., e_cb))); +} + +/** + * @brief + * + * @return true + * @return false + */ +auto GPGFRONTEND_CORE_EXPORT IsModuleAcivate(ModuleIdentifier) -> bool; + +/** + * @brief + * + * @param namespace_ + * @param key + * @param value + * @return true + * @return false + */ +auto GPGFRONTEND_CORE_EXPORT UpsertRTValue(const QString& namespace_, + const QString& key, + const std::any& value) -> bool; + +/** + * @brief + * + * @return true + * @return false + */ +auto GPGFRONTEND_CORE_EXPORT ListenRTPublishEvent(QObject*, Namespace, Key, + LPCallback) -> bool; + +/** + * @brief + * + * @param namespace_ + * @param key + * @return std::vector<Key> + */ +auto GPGFRONTEND_CORE_EXPORT ListRTChildKeys(const QString& namespace_, + const QString& key) + -> std::vector<Key>; + +template <typename T> +auto RetrieveRTValueTyped(const QString& namespace_, const QString& key) + -> std::optional<T> { + auto any_value = + ModuleManager::GetInstance().RetrieveRTValue(namespace_, key); + if (any_value && any_value->type() == typeid(T)) { + return std::any_cast<T>(*any_value); + } + return std::nullopt; +} + +template <typename T> +auto RetrieveRTValueTypedOrDefault(const QString& namespace_, + const QString& key, const T& defaultValue) + -> T { + auto any_value = + ModuleManager::GetInstance().RetrieveRTValue(namespace_, key); + if (any_value && any_value->type() == typeid(T)) { + return std::any_cast<T>(*any_value); + } + return defaultValue; +} + +} // namespace GpgFrontend::Module
\ No newline at end of file diff --git a/src/core/thread/CtxCheckTask.cpp b/src/core/thread/CtxCheckTask.cpp deleted file mode 100644 index 9735fcaa..00000000 --- a/src/core/thread/CtxCheckTask.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/** - * Copyright (C) 2021 Saturneric - * - * This file is part of GpgFrontend. - * - * GpgFrontend is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GpgFrontend is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GpgFrontend. If not, see <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. - * - * The source code version of this software was modified and released - * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021. - * - */ - -#include "core/thread/CtxCheckTask.h" - -#include "core/GpgContext.h" -#include "core/GpgCoreInit.h" -#include "core/common/CoreCommonUtil.h" -#include "core/function/gpg/GpgKeyGetter.h" -#include "thread/Task.h" - -GpgFrontend::Thread::CtxCheckTask::CtxCheckTask() : Task("ctx_check_task") { - connect(this, &CtxCheckTask::SignalGnupgNotInstall, - CoreCommonUtil::GetInstance(), - &CoreCommonUtil::SignalGnupgNotInstall); -} - -void GpgFrontend::Thread::CtxCheckTask::Run() { - // Init GpgFrontend Core - init_gpgfrontend_core(); - - // Create & Check Gnupg Context Status - if (!GpgContext::GetInstance().good()) { - emit SignalGnupgNotInstall(); - } - // Try flushing key cache - else - GpgFrontend::GpgKeyGetter::GetInstance().FlushKeyCache(); - - SPDLOG_DEBUG("ctx check task runnable done"); -} diff --git a/src/core/thread/FileReadTask.cpp b/src/core/thread/FileReadTask.cpp index 73954d28..49a3f540 100644 --- a/src/core/thread/FileReadTask.cpp +++ b/src/core/thread/FileReadTask.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -19,8 +19,10 @@ * The initial version of the source code is inherited from * the gpg4usb project, which is under GPL-3.0-or-later. * - * The source code version of this software was modified and released - * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021. + * 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 * */ @@ -28,58 +30,52 @@ namespace GpgFrontend::UI { -FileReadTask::FileReadTask(std::string path) : Task("file_read_task") { - connect(this, &FileReadTask::SignalFileBytesReadNext, this, - &FileReadTask::read_bytes); +constexpr size_t kBufferSize = 8192; -#ifdef WINDOWS - std::filesystem::path read_file_path( - QString::fromStdString(path).toStdU16String()); -#else - std::filesystem::path read_file_path( - QString::fromStdString(path).toStdString()); -#endif - read_file_path_ = read_file_path; +FileReadTask::FileReadTask(QString path) + : Task("file_read_task"), read_file_path_(std::move(path)) { + HoldOnLifeCycle(true); + connect(this, &FileReadTask::SignalFileBytesReadNext, this, + &FileReadTask::slot_read_bytes); } -void FileReadTask::Run() { - SetFinishAfterRun(false); - - if (is_regular_file(read_file_path_)) { - SPDLOG_DEBUG("read open file: {}", read_file_path_.u8string()); +auto FileReadTask::Run() -> int { + if (QFileInfo(read_file_path_).isFile()) { + GF_CORE_LOG_DEBUG("read open file: {}", read_file_path_); - target_file_.setFileName( - QString::fromStdString(read_file_path_.u8string())); + target_file_.setFileName(read_file_path_); target_file_.open(QIODevice::ReadOnly); if (!(target_file_.isOpen() && target_file_.isReadable())) { - SPDLOG_ERROR("file not open or not readable"); + GF_CORE_LOG_ERROR("file not open or not readable"); if (target_file_.isOpen()) target_file_.close(); - return; + return -1; } - SPDLOG_DEBUG("started reading: {}", read_file_path_.u8string()); - read_bytes(); + GF_CORE_LOG_DEBUG("started reading: {}", read_file_path_); + slot_read_bytes(); } else { emit SignalFileBytesReadEnd(); } + return 0; } -void FileReadTask::read_bytes() { +void FileReadTask::slot_read_bytes() { QByteArray read_buffer; - if (!target_file_.atEnd() && - (read_buffer = target_file_.read(buffer_size_)).size() > 0) { - SPDLOG_DEBUG("read bytes: {}", read_buffer.size()); + if (QByteArray read_buffer; + !target_file_.atEnd() && + (read_buffer = target_file_.read(kBufferSize)).size() > 0) { + GF_CORE_LOG_DEBUG("io thread read bytes: {}", read_buffer.size()); emit SignalFileBytesRead(std::move(read_buffer)); } else { - SPDLOG_DEBUG("read bytes end"); + GF_CORE_LOG_DEBUG("io thread read bytes end"); emit SignalFileBytesReadEnd(); // announce finish task - emit SignalTaskRunnableEnd(0); + emit SignalTaskShouldEnd(0); } } FileReadTask::~FileReadTask() { - SPDLOG_DEBUG("close file: {}", read_file_path_.u8string()); + GF_CORE_LOG_DEBUG("close file: {}", read_file_path_); if (target_file_.isOpen()) target_file_.close(); } diff --git a/src/core/thread/FileReadTask.h b/src/core/thread/FileReadTask.h index d4e61cbe..22be33ef 100644 --- a/src/core/thread/FileReadTask.h +++ b/src/core/thread/FileReadTask.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -19,13 +19,14 @@ * The initial version of the source code is inherited from * the gpg4usb project, which is under GPL-3.0-or-later. * - * The source code version of this software was modified and released - * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021. + * 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 * */ -#ifndef GPGFRONTEND_FILEREADTHREAD_H -#define GPGFRONTEND_FILEREADTHREAD_H +#pragma once #include "core/GpgFrontendCore.h" #include "core/thread/Task.h" @@ -39,11 +40,11 @@ namespace GpgFrontend::UI { class GPGFRONTEND_CORE_EXPORT FileReadTask : public GpgFrontend::Thread::Task { Q_OBJECT public: - explicit FileReadTask(std::string path); + explicit FileReadTask(QString path); virtual ~FileReadTask() override; - void Run() override; + int Run() override; signals: void SignalFileBytesRead(QByteArray bytes); @@ -51,15 +52,12 @@ class GPGFRONTEND_CORE_EXPORT FileReadTask : public GpgFrontend::Thread::Task { void SignalFileBytesReadNext(); private: - std::filesystem::path read_file_path_; + QString read_file_path_; QFile target_file_; - const size_t buffer_size_ = 4096; QEventLoop looper; private slots: - void read_bytes(); + void slot_read_bytes(); }; } // namespace GpgFrontend::UI - -#endif // GPGFRONTEND_FILEREADTHREAD_H diff --git a/src/core/thread/Task.cpp b/src/core/thread/Task.cpp index 7173b69e..dc0cfe94 100644 --- a/src/core/thread/Task.cpp +++ b/src/core/thread/Task.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -19,209 +19,237 @@ * The initial version of the source code is inherited from * the gpg4usb project, which is under GPL-3.0-or-later. * - * The source code version of this software was modified and released - * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021. + * 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/thread/Task.h" -#include <boost/uuid/uuid.hpp> -#include <boost/uuid/uuid_generators.hpp> -#include <boost/uuid/uuid_io.hpp> -#include <functional> -#include <string> -#include <utility> +#include <qscopedpointer.h> -#include "core/thread/TaskRunner.h" +#include "utils/MemoryUtils.h" -const std::string GpgFrontend::Thread::Task::DEFAULT_TASK_NAME = "default-task"; +namespace GpgFrontend::Thread { -GpgFrontend::Thread::Task::Task(std::string name) - : uuid_(generate_uuid()), name_(name) { - SPDLOG_TRACE("task {}/ created", GetFullID()); - init(); -} +class Task::Impl { + public: + Impl(Task *parent, QString name) + : parent_(parent), uuid_(generate_uuid()), name_(std::move(name)) { + GF_CORE_LOG_TRACE("task {} created", GetFullID()); + init(); + } -GpgFrontend::Thread::Task::Task(TaskRunnable runnable, std::string name, - DataObjectPtr data_object, bool sequency) - : uuid_(generate_uuid()), - name_(name), - runnable_(std::move(runnable)), - callback_(std::move([](int, const std::shared_ptr<DataObject> &) {})), - callback_thread_(QThread::currentThread()), - data_object_(data_object), - sequency_(sequency) { - SPDLOG_TRACE("task {} created with runnable, callback_thread_: {}", - GetFullID(), static_cast<void *>(callback_thread_)); - init(); -} + Impl(Task *parent, TaskRunnable runnable, QString name, + DataObjectPtr data_object) + : parent_(parent), + uuid_(generate_uuid()), + name_(std::move(name)), + runnable_(std::move(runnable)), + callback_([](int, const DataObjectPtr &) {}), + callback_thread_(QThread::currentThread()), + data_object_(std::move(data_object)) { + GF_CORE_LOG_TRACE("task {} created with runnable, callback_thread_: {}", + GetFullID(), static_cast<void *>(callback_thread_)); + init(); + } -GpgFrontend::Thread::Task::Task(TaskRunnable runnable, std::string name, - DataObjectPtr data_object, - TaskCallback callback, bool sequency) - : uuid_(generate_uuid()), - name_(name), - runnable_(std::move(runnable)), - callback_(std::move(callback)), - callback_thread_(QThread::currentThread()), - data_object_(data_object), - sequency_(sequency) { - init(); - SPDLOG_TRACE( - "task {} created with runnable and callback, callback_thread_: {}", - GetFullID(), static_cast<void *>(callback_thread_)); -} + Impl(Task *parent, TaskRunnable runnable, QString name, + DataObjectPtr data_object, TaskCallback callback) + : parent_(parent), + uuid_(generate_uuid()), + name_(std::move(name)), + runnable_(std::move(runnable)), + callback_(std::move(callback)), + callback_thread_(QThread::currentThread()), + data_object_(std::move(data_object)) { + GF_CORE_LOG_TRACE( + "task {} created with runnable and callback, callback_thread_: {}", + GetFullID(), static_cast<void *>(callback_thread_)); + init(); + } -GpgFrontend::Thread::Task::~Task() { - SPDLOG_TRACE("task {} destroyed", GetFullID()); -} + ~Impl() { GF_CORE_LOG_TRACE("task {} destroyed", GetFullID()); } + + /** + * @brief + * + * @return QString + */ + [[nodiscard]] auto GetFullID() const -> QString { + return uuid_ + "/" + name_; + } + + /** + * @brief + * + * @return QString + */ + [[nodiscard]] auto GetUUID() const -> QString { return uuid_; } + + /** + * @brief + * + * @return int + */ + auto Run() -> int { + GF_CORE_LOG_TRACE("task {} is in classical runnable and callback mode", + GetFullID()); + + if (runnable_) return runnable_(data_object_); + + GF_CORE_LOG_WARN("no runnable in task, do callback operation, task: {}", + GetFullID()); + return 0; + } + + /** + * @brief Set the Finish After Run object + * + * @param finish_after_run + */ + void HoldOnLifeCycle(bool hold_on) { parent_->setAutoDelete(!hold_on); } + + /** + * @brief + * + * @param rtn + */ + void SetRTN(int rtn) { this->rtn_ = rtn; } + + /** + * @brief + * + * @return auto + */ + [[nodiscard]] auto GetRTN() const { return this->rtn_; } + + private: + Task *const parent_; + const QString uuid_; + const QString name_; + TaskRunnable runnable_; ///< + TaskCallback callback_; ///< + int rtn_ = -99; ///< + QThread *callback_thread_ = nullptr; ///< + DataObjectPtr data_object_ = nullptr; ///< + + void init() { + GF_CORE_LOG_TRACE("task {} created, parent: {}, impl: {}", name_, + static_cast<void *>(parent_), static_cast<void *>(this)); + + // + HoldOnLifeCycle(false); + + // + connect(parent_, &Task::SignalRun, parent_, &Task::slot_exception_safe_run); + + auto *callback_thread = callback_thread_ != nullptr + ? callback_thread_ + : QCoreApplication::instance()->thread(); + // + connect(parent_, &Task::SignalTaskShouldEnd, callback_thread, + [this](int rtn) { + // set task returning code + SetRTN(rtn); + try { + if (callback_) { + GF_CORE_LOG_TRACE( + "task callback {} is starting with runnerable rtn: {}", + GetFullID(), rtn); + + callback_(rtn_, data_object_); + GF_CORE_LOG_TRACE("task callback {} finished, rtn: {}", + GetFullID(), rtn); + } + } catch (...) { + GF_CORE_LOG_ERROR("task {} callback caught exception, rtn: {}", + GetFullID(), rtn); + } + emit parent_->SignalTaskEnd(); + }); + + // + connect(parent_, &Task::SignalTaskEnd, parent_, &Task::deleteLater); + } + + /** + * @brief + * + * @return QString + */ + static auto generate_uuid() -> QString { + return QUuid::createUuid().toString(); + } +}; + +Task::Task(QString name) : p_(new Impl(this, name)) {} + +Task::Task(TaskRunnable runnable, QString name, DataObjectPtr data_object) + : p_(SecureCreateUniqueObject<Impl>(this, runnable, name, data_object)) {} + +Task::Task(TaskRunnable runnable, QString name, DataObjectPtr data_object, + TaskCallback callback) + : p_(SecureCreateUniqueObject<Impl>(this, runnable, name, data_object, + callback)) {} + +Task::~Task() = default; /** * @brief * - * @return std::string + * @return QString */ -std::string GpgFrontend::Thread::Task::GetFullID() const { - return uuid_ + "/" + name_; -} - -std::string GpgFrontend::Thread::Task::GetUUID() const { return uuid_; } +QString Task::GetFullID() const { return p_->GetFullID(); } -bool GpgFrontend::Thread::Task::GetSequency() const { return sequency_; } +QString Task::GetUUID() const { return p_->GetUUID(); } -void GpgFrontend::Thread::Task::SetFinishAfterRun( - bool run_callback_after_runnable_finished) { - this->run_callback_after_runnable_finished_ = - run_callback_after_runnable_finished; -} +void Task::HoldOnLifeCycle(bool hold_on) { p_->HoldOnLifeCycle(hold_on); } -void GpgFrontend::Thread::Task::SetRTN(int rtn) { this->rtn_ = rtn; } - -void GpgFrontend::Thread::Task::init() { - // after runnable finished, running callback - connect(this, &Task::SignalTaskRunnableEnd, this, - &Task::slot_task_run_callback); -} +void Task::setRTN(int rtn) { p_->SetRTN(rtn); } -void GpgFrontend::Thread::Task::slot_task_run_callback(int rtn) { - SPDLOG_TRACE("task runnable {} finished, rtn: {}", GetFullID(), rtn); - // set return value - this->SetRTN(rtn); +void Task::SafelyRun() { emit SignalRun(); } - try { - if (callback_) { - if (callback_thread_ == QThread::currentThread()) { - SPDLOG_DEBUG("callback thread is the same thread"); - if (!QMetaObject::invokeMethod(callback_thread_, - [callback = callback_, rtn = rtn_, - data_object = data_object_, this]() { - callback(rtn, data_object); - // do cleaning work - emit SignalTaskEnd(); - })) { - SPDLOG_ERROR("failed to invoke callback"); - } - // just finished, let callack thread to raise SignalTaskEnd - return; - } else { - // waiting for callback to finish - if (!QMetaObject::invokeMethod( - callback_thread_, - [callback = callback_, rtn = rtn_, - data_object = data_object_]() { callback(rtn, data_object); }, - Qt::BlockingQueuedConnection)) { - SPDLOG_ERROR("failed to invoke callback"); - } - } - } - } catch (std::exception &e) { - SPDLOG_ERROR("exception caught: {}", e.what()); - } catch (...) { - SPDLOG_ERROR("unknown exception caught"); - } +int Task::Run() { return p_->Run(); } - // raise signal, announcing this task come to an end - SPDLOG_DEBUG("task {}, starting calling signal SignalTaskEnd", GetFullID()); - emit SignalTaskEnd(); +void Task::run() { + GF_CORE_LOG_TRACE("interface run() of task {} was called by thread: {}", + GetFullID(), QThread::currentThread()->currentThreadId()); + this->SafelyRun(); } -void GpgFrontend::Thread::Task::run() { - SPDLOG_TRACE("task {} starting", GetFullID()); +Task::TaskHandler::TaskHandler(Task *task) : task_(task) {} - // build runnable package for running - auto runnable_package = [=, id = GetFullID()]() { - SPDLOG_DEBUG("task {} runnable start runing", id); - // Run() will set rtn by itself - Run(); - // raise signal to anounce after runnable returned - if (run_callback_after_runnable_finished_) emit SignalTaskRunnableEnd(rtn_); - }; - - if (thread() != QThread::currentThread()) { - SPDLOG_DEBUG("task running thread is not object living thread"); - // if running sequently - if (sequency_) { - // running in another thread, blocking until returned - if (!QMetaObject::invokeMethod(thread(), runnable_package, - Qt::BlockingQueuedConnection)) { - SPDLOG_ERROR("qt invoke method failed"); - } - } else { - // running in another thread, non-blocking - if (!QMetaObject::invokeMethod(thread(), runnable_package)) { - SPDLOG_ERROR("qt invoke method failed"); - } - } - } else { - if (!QMetaObject::invokeMethod(this, runnable_package)) { - SPDLOG_ERROR("qt invoke method failed"); - } - } +void Task::TaskHandler::Start() { + if (task_ != nullptr) task_->SafelyRun(); } -void GpgFrontend::Thread::Task::SlotRun() { run(); } - -void GpgFrontend::Thread::Task::Run() { - if (runnable_) { - SetRTN(runnable_(data_object_)); - } else { - SPDLOG_WARN("no runnable in task, do callback operation"); - } +void Task::TaskHandler::Cancel() { + if (task_ != nullptr) emit task_->SignalTaskEnd(); } -GpgFrontend::Thread::Task::DataObject::Destructor * -GpgFrontend::Thread::Task::DataObject::get_heap_ptr(size_t bytes_size) { - Destructor *dstr_ptr = new Destructor(); - dstr_ptr->p_obj = malloc(bytes_size); - return dstr_ptr; +auto Task::TaskHandler::GetTask() -> Task * { + if (task_ != nullptr) return task_; + return nullptr; } -GpgFrontend::Thread::Task::DataObject::~DataObject() { - if (!data_objects_.empty()) - SPDLOG_WARN("data_objects_ is not empty", - "address:", static_cast<void *>(this)); - while (!data_objects_.empty()) { - free_heap_ptr(data_objects_.top()); - data_objects_.pop(); - } -} +void Task::slot_exception_safe_run() noexcept { + auto rtn = p_->GetRTN(); + try { + GF_CORE_LOG_TRACE("task runnable {} is starting...", GetFullID()); -size_t GpgFrontend::Thread::Task::DataObject::GetObjectSize() { - return data_objects_.size(); -} + // Run() will set rtn by itself + rtn = this->Run(); -void GpgFrontend::Thread::Task::DataObject::free_heap_ptr(Destructor *ptr) { - SPDLOG_TRACE("p_obj: {} data object: {}", - static_cast<const void *>(ptr->p_obj), - static_cast<void *>(this)); - if (ptr->destroy != nullptr) { - ptr->destroy(ptr->p_obj); + GF_CORE_LOG_TRACE("task runnable {} finished, rtn: {}", GetFullID()); + } catch (...) { + GF_CORE_LOG_ERROR("exception was caught at task: {}", GetFullID()); } - free(const_cast<void *>(ptr->p_obj)); - delete ptr; -} -std::string GpgFrontend::Thread::Task::generate_uuid() { - return boost::uuids::to_string(boost::uuids::random_generator()()); + // raise signal to anounce after runnable returned + if (this->autoDelete()) emit this->SignalTaskShouldEnd(rtn); } +auto Task::GetRTN() { return p_->GetRTN(); } +} // namespace GpgFrontend::Thread
\ No newline at end of file diff --git a/src/core/thread/Task.h b/src/core/thread/Task.h index ce354697..97a14949 100644 --- a/src/core/thread/Task.h +++ b/src/core/thread/Task.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,23 +20,17 @@ * 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_TASK_H -#define GPGFRONTEND_TASK_H - -#include <functional> -#include <memory> -#include <stack> -#include <string> -#include <type_traits> -#include <utility> +#pragma once #include "core/GpgFrontendCore.h" +#include "core/function/SecureMemoryAllocator.h" +#include "core/model/DataObject.h" namespace GpgFrontend::Thread { @@ -45,253 +39,136 @@ class TaskRunner; class GPGFRONTEND_CORE_EXPORT Task : public QObject, public QRunnable { Q_OBJECT public: - class DataObject; - using DataObjectPtr = std::shared_ptr<DataObject>; ///< + friend class TaskRunner; + using TaskRunnable = std::function<int(DataObjectPtr)>; ///< using TaskCallback = std::function<void(int, DataObjectPtr)>; ///< - static const std::string DEFAULT_TASK_NAME; - - friend class TaskRunner; - - /** - * @brief DataObject to be passed to the callback function. - * - */ - class GPGFRONTEND_CORE_EXPORT DataObject { + class TaskHandler { public: - struct Destructor { - const void *p_obj; - void (*destroy)(const void *); - }; - - /** - * @brief Get the Objects Size - * - * @return size_t - */ - size_t GetObjectSize(); - - /** - * @brief - * - * @tparam T - * @param ptr - */ - template <typename T> - void AppendObject(T &&obj) { - SPDLOG_TRACE("append object: {}", static_cast<void *>(this)); - auto *obj_dstr = this->get_heap_ptr(sizeof(T)); - new ((void *)obj_dstr->p_obj) T(std::forward<T>(obj)); + explicit TaskHandler(Task*); - if (std::is_class_v<T>) { - auto destructor = [](const void *x) { - static_cast<const T *>(x)->~T(); - }; - obj_dstr->destroy = destructor; - } else { - obj_dstr->destroy = nullptr; - } + void Start(); - data_objects_.push(obj_dstr); - } + void Cancel(); - /** - * @brief - * - * @tparam T - * @param ptr - */ - template <typename T> - void AppendObject(T *obj) { - SPDLOG_TRACE("called: {}", static_cast<void *>(this)); - auto *obj_dstr = this->get_heap_ptr(sizeof(T)); - auto *ptr_heap = new ((void *)obj_dstr->p_obj) T(std::move(*obj)); - if (std::is_class_v<T>) { - SPDLOG_TRACE("is class"); - auto destructor = [](const void *x) { - static_cast<const T *>(x)->~T(); - }; - obj_dstr->destroy = destructor; - } else { - obj_dstr->destroy = nullptr; - } - data_objects_.push(std::move(obj_dstr)); - } - - /** - * @brief - * - * @tparam T - * @return std::shared_ptr<T> - */ - template <typename T> - T PopObject() { - SPDLOG_TRACE("pop object: {}", static_cast<void *>(this)); - if (data_objects_.empty()) throw std::runtime_error("No object to pop"); - auto *obj_dstr = data_objects_.top(); - auto *heap_ptr = (T *)obj_dstr->p_obj; - auto obj = std::move(*(T *)(heap_ptr)); - this->free_heap_ptr(obj_dstr); - data_objects_.pop(); - return obj; - } - - /** - * @brief Destroy the Data Object object - * - */ - ~DataObject(); + auto GetTask() -> Task*; private: - std::stack<Destructor *> data_objects_; ///< - - /** - * @brief Get the heap ptr object - * - * @param bytes_size - * @return void* - */ - Destructor *get_heap_ptr(size_t bytes_size); - - /** - * @brief - * - * @param heap_ptr - */ - void free_heap_ptr(Destructor *); + QPointer<Task> task_; }; /** * @brief Construct a new Task object * */ - Task(std::string name = DEFAULT_TASK_NAME); + explicit Task(QString name); /** * @brief Construct a new Task object * * @param callback The callback function to be executed. */ - explicit Task(TaskRunnable runnable, std::string name = DEFAULT_TASK_NAME, - DataObjectPtr data_object = nullptr, bool sequency = true); + explicit Task(TaskRunnable runnable, QString name, + DataObjectPtr data_object = nullptr); /** * @brief Construct a new Task object * * @param runnable */ - explicit Task( - TaskRunnable runnable, std::string name, DataObjectPtr data, - TaskCallback callback = [](int, const std::shared_ptr<DataObject> &) {}, - bool sequency = true); + explicit Task(TaskRunnable runnable, QString name, DataObjectPtr data, + TaskCallback callback); /** * @brief Destroy the Task object * */ - virtual ~Task() override; + ~Task() override; /** - * @brief Run - run the task + * @brief * + * @return QString */ - virtual void Run(); + [[nodiscard]] auto GetUUID() const -> QString; /** - * @brief + * @brief Get the Full I D object * - * @return std::string + * @return QString */ - std::string GetUUID() const; + [[nodiscard]] auto GetFullID() const -> QString; /** * @brief * - * @return std::string + * @param hold_on */ - std::string GetFullID() const; + void HoldOnLifeCycle(bool hold_on); /** - * @brief + * @brief can be overwrite by subclass * - * @return std::string + * @return int */ - bool GetSequency() const; - - public slots: + virtual auto Run() -> int; /** * @brief * + * @return auto */ - void SlotRun(); + [[nodiscard]] auto GetRTN(); - signals: - /** - * @brief announce runnable finished - * - */ - void SignalTaskRunnableEnd(int rtn); + public slots: /** - * @brief runnable and callabck all finished + * @brief shouldn't be overwrite by subclass * */ - void SignalTaskEnd(); + void SafelyRun(); - protected: - /** - * @brief Set the Finish After Run object - * - * @param finish_after_run - */ - void SetFinishAfterRun(bool finish_after_run); + signals: /** * @brief * - * @param rtn */ - void SetRTN(int rtn); - - private: - const std::string uuid_; - const std::string name_; - const bool sequency_ = true; ///< must run in the same thread - TaskCallback callback_; ///< - TaskRunnable runnable_; ///< - bool run_callback_after_runnable_finished_ = true; ///< - int rtn_ = 0; ///< - QThread *callback_thread_ = nullptr; ///< - DataObjectPtr data_object_ = nullptr; ///< + void SignalRun(); /** * @brief * */ - void init(); + void SignalTaskShouldEnd(int); /** * @brief * */ - virtual void run() override; + void SignalTaskEnd(); + protected: /** * @brief * - * @return std::string + * @param rtn */ - static std::string generate_uuid(); + void setRTN(int rtn); private slots: + /** * @brief * */ - void slot_task_run_callback(int rtn); + void slot_exception_safe_run() noexcept; + + private: + class Impl; + SecureUniquePtr<Impl> p_; + + void run() override; }; } // namespace GpgFrontend::Thread - -#endif // GPGFRONTEND_TASK_H
\ No newline at end of file diff --git a/src/core/thread/TaskRunner.cpp b/src/core/thread/TaskRunner.cpp index 461d5fb5..8e381384 100644 --- a/src/core/thread/TaskRunner.cpp +++ b/src/core/thread/TaskRunner.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -19,128 +19,132 @@ * The initial version of the source code is inherited from * the gpg4usb project, which is under GPL-3.0-or-later. * - * The source code version of this software was modified and released - * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021. + * 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/thread/TaskRunner.h" #include "core/thread/Task.h" -#include "spdlog/spdlog.h" -GpgFrontend::Thread::TaskRunner::TaskRunner() = default; +namespace GpgFrontend::Thread { + +class TaskRunner::Impl : public QThread { + public: + Impl() : QThread(nullptr) {} -GpgFrontend::Thread::TaskRunner::~TaskRunner() = default; + void PostTask(Task* task) { + if (task == nullptr) { + GF_CORE_LOG_ERROR("task posted is null"); + return; + } -void GpgFrontend::Thread::TaskRunner::PostTask(Task* task) { - if (task == nullptr) { - SPDLOG_ERROR("task posted is null"); - return; + task->setParent(nullptr); + task->moveToThread(this); + + GF_CORE_LOG_TRACE("runner starts task: {} at thread: {}", task->GetFullID(), + this->currentThreadId()); + task->SafelyRun(); } - SPDLOG_TRACE("post task: {}", task->GetFullID()); + auto RegisterTask(const QString& name, const Task::TaskRunnable& runnerable, + const Task::TaskCallback& cb, DataObjectPtr params) + -> Task::TaskHandler { + auto* raw_task = new Task(runnerable, name, std::move(params), cb); + raw_task->setParent(nullptr); + raw_task->moveToThread(this); + + connect(raw_task, &Task::SignalRun, this, [this, raw_task]() { + pending_tasks_[raw_task->GetFullID()] = raw_task; + }); - task->setParent(nullptr); - task->moveToThread(this); + connect(raw_task, &Task::SignalTaskEnd, this, [this, raw_task]() { + pending_tasks_.remove(raw_task->GetFullID()); + }); - { - std::lock_guard<std::mutex> lock(tasks_mutex_); - tasks.push(task); + GF_CORE_LOG_TRACE("runner starts task: {} at thread: {}", + raw_task->GetFullID(), this->currentThreadId()); + + return Task::TaskHandler(raw_task); } - quit(); -} -void GpgFrontend::Thread::TaskRunner::PostScheduleTask(Task* task, - size_t seconds) { - if (task == nullptr) return; - // TODO -} + void PostTask(const QString& name, const Task::TaskRunnable& runnerable, + const Task::TaskCallback& cb, DataObjectPtr params) { + PostTask(new Task(runnerable, name, std::move(params), cb)); + } -[[noreturn]] void GpgFrontend::Thread::TaskRunner::run() { - SPDLOG_TRACE("task runner runing, thread id: {}", QThread::currentThreadId()); - while (true) { - if (tasks.empty()) { - SPDLOG_TRACE("no tasks to run, trapping into event loop..."); - exec(); - } else { - SPDLOG_TRACE("start to run task(s), queue size: {}", tasks.size()); - - Task* task = nullptr; - { - std::lock_guard<std::mutex> lock(tasks_mutex_); - task = std::move(tasks.front()); - tasks.pop(); - pending_tasks_.insert({task->GetUUID(), task}); - } - - if (task != nullptr) { - try { - // triger - SPDLOG_TRACE("running task {}, sequency: {}", task->GetFullID(), - task->GetSequency()); - - // when a signal SignalTaskEnd raise, do unregister work - connect(task, &Task::SignalTaskEnd, this, [this, task]() { - unregister_finished_task(task->GetUUID()); - }); - - if (!task->GetSequency()) { - // if it need to run concurrently, we should create a new thread to - // run it. - auto* concurrent_thread = new QThread(nullptr); - task->setParent(nullptr); - task->moveToThread(concurrent_thread); - // start thread - concurrent_thread->start(); - - connect(task, &Task::SignalTaskEnd, concurrent_thread, - &QThread::quit); - // concurrent thread is responsible for deleting the task - connect(concurrent_thread, &QThread::finished, task, - &Task::deleteLater); - } - - // run the task - task->run(); - } catch (const std::exception& e) { - SPDLOG_ERROR("task runner: exception in task {}, exception: {}", - task->GetFullID(), e.what()); - // if any exception caught, destroy the task, remove the task from the - // pending tasks - unregister_finished_task(task->GetUUID()); - } catch (...) { - SPDLOG_ERROR("task runner: unknown exception in task: {}", - task->GetFullID()); - // if any exception caught, destroy the task, remove the task from the - // pending tasks - unregister_finished_task(task->GetUUID()); - } - } + void PostConcurrentTask(Task* task) { + if (task == nullptr) { + GF_CORE_LOG_ERROR("task posted is null"); + return; } + + auto* concurrent_thread = new QThread(this); + + task->setParent(nullptr); + task->moveToThread(concurrent_thread); + + connect(task, &Task::SignalTaskEnd, concurrent_thread, &QThread::quit); + connect(concurrent_thread, &QThread::finished, concurrent_thread, + &QThread::deleteLater); + + concurrent_thread->start(); + + GF_CORE_LOG_TRACE("runner starts task concurrenctly: {}", + task->GetFullID()); + task->SafelyRun(); } -} -/** - * @brief - * - */ -void GpgFrontend::Thread::TaskRunner::unregister_finished_task( - std::string task_uuid) { - SPDLOG_DEBUG("cleaning task {}", task_uuid); - // search in map - auto pending_task = pending_tasks_.find(task_uuid); - if (pending_task == pending_tasks_.end()) { - SPDLOG_ERROR("cannot find task in pending list: {}", task_uuid); - return; - } else { - std::lock_guard<std::mutex> lock(tasks_mutex_); - // if thread runs sequenctly, that means the thread is living in this - // thread, so we can delete it. Or, its living thread need to delete it. - if (pending_task->second->GetSequency()) - pending_task->second->deleteLater(); - pending_tasks_.erase(pending_task); + void PostScheduleTask(Task* task, size_t seconds) { + if (task == nullptr) return; + // TODO } - SPDLOG_DEBUG("clean task {} done", task_uuid); + private: + QMap<QString, Task*> pending_tasks_; +}; + +TaskRunner::TaskRunner() : p_(SecureCreateUniqueObject<Impl>()) {} + +TaskRunner::~TaskRunner() { + if (p_->isRunning()) { + Stop(); + } +} + +void TaskRunner::PostTask(Task* task) { p_->PostTask(task); } + +void TaskRunner::PostTask(const QString& name, const Task::TaskRunnable& runner, + const Task::TaskCallback& cb, DataObjectPtr params) { + p_->PostTask(name, runner, cb, std::move(params)); +} + +void TaskRunner::PostConcurrentTask(Task* task) { + p_->PostConcurrentTask(task); +} + +void TaskRunner::PostScheduleTask(Task* task, size_t seconds) { + p_->PostScheduleTask(task, seconds); +} + +void TaskRunner::Start() { p_->start(); } + +void TaskRunner::Stop() { + p_->quit(); + p_->wait(); +} + +auto TaskRunner::GetThread() -> QThread* { return p_.get(); } + +auto TaskRunner::IsRunning() -> bool { return p_->isRunning(); } + +auto TaskRunner::RegisterTask(const QString& name, + const Task::TaskRunnable& runnable, + const Task::TaskCallback& cb, DataObjectPtr p_pbj) + -> Task::TaskHandler { + return p_->RegisterTask(name, runnable, cb, p_pbj); } +} // namespace GpgFrontend::Thread diff --git a/src/core/thread/TaskRunner.h b/src/core/thread/TaskRunner.h index 35cd1a30..8a93ad0b 100644 --- a/src/core/thread/TaskRunner.h +++ b/src/core/thread/TaskRunner.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -19,25 +19,22 @@ * The initial version of the source code is inherited from * the gpg4usb project, which is under GPL-3.0-or-later. * - * The source code version of this software was modified and released - * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021. + * 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 * */ -#ifndef GPGFRONTEND_TASKRUNNER_H -#define GPGFRONTEND_TASKRUNNER_H - -#include <cstddef> -#include <mutex> -#include <queue> +#pragma once #include "core/GpgFrontendCore.h" +#include "core/function/SecureMemoryAllocator.h" +#include "core/thread/Task.h" namespace GpgFrontend::Thread { -class Task; - -class GPGFRONTEND_CORE_EXPORT TaskRunner : public QThread { +class GPGFRONTEND_CORE_EXPORT TaskRunner : public QObject { Q_OBJECT public: /** @@ -50,13 +47,34 @@ class GPGFRONTEND_CORE_EXPORT TaskRunner : public QThread { * @brief Destroy the Task Runner object * */ - virtual ~TaskRunner() override; + ~TaskRunner() override; + + /** + * @brief + * + */ + void Start(); /** * @brief * */ - [[noreturn]] void run() override; + void Stop(); + + /** + * @brief Get the Thread object + * + * @return QThread* + */ + auto GetThread() -> QThread*; + + /** + * @brief + * + * @return true + * @return false + */ + auto IsRunning() -> bool; public slots: @@ -70,23 +88,38 @@ class GPGFRONTEND_CORE_EXPORT TaskRunner : public QThread { /** * @brief * - * @param task - * @param seconds + * @param runner + * @param cb */ - void PostScheduleTask(Task* task, size_t seconds); + void PostTask(const QString&, const Task::TaskRunnable&, + const Task::TaskCallback&, DataObjectPtr); - private: - std::queue<Task*> tasks; ///< The task queue - std::map<std::string, Task*> pending_tasks_; ///< The pending tasks - std::mutex tasks_mutex_; ///< The task queue mutex - QThreadPool thread_pool_{this}; ///< run non-sequency task + /** + * @brief + * + * @return std::tuple<QPointer<Task>, TaskTrigger> + */ + auto RegisterTask(const QString&, const Task::TaskRunnable&, + const Task::TaskCallback&, DataObjectPtr) + -> Task::TaskHandler; + + /** + * @brief + * + * @param task + */ + void PostConcurrentTask(Task* task); /** * @brief * + * @param task + * @param seconds */ - void unregister_finished_task(std::string); + void PostScheduleTask(Task* task, size_t seconds); + + private: + class Impl; + SecureUniquePtr<Impl> p_; }; } // namespace GpgFrontend::Thread - -#endif // GPGFRONTEND_TASKRUNNER_H
\ No newline at end of file diff --git a/src/core/thread/TaskRunnerGetter.cpp b/src/core/thread/TaskRunnerGetter.cpp index 186483ec..bdcd89d0 100644 --- a/src/core/thread/TaskRunnerGetter.cpp +++ b/src/core/thread/TaskRunnerGetter.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -19,28 +19,46 @@ * The initial version of the source code is inherited from * the gpg4usb project, which is under GPL-3.0-or-later. * - * The source code version of this software was modified and released - * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021. + * 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/thread/TaskRunnerGetter.h" -GpgFrontend::Thread::TaskRunnerGetter::TaskRunnerGetter(int channel) - : SingletonFunctionObject<TaskRunnerGetter>(channel) {} +#include <mutex> + +#include "core/GpgConstants.h" +#include "core/thread/TaskRunner.h" + +namespace GpgFrontend::Thread { -GpgFrontend::Thread::TaskRunner* -GpgFrontend::Thread::TaskRunnerGetter::GetTaskRunner( - TaskRunnerType runner_type) { +TaskRunnerGetter::TaskRunnerGetter(int) + : SingletonFunctionObject<TaskRunnerGetter>(kGpgFrontendDefaultChannel) {} + +auto TaskRunnerGetter::GetTaskRunner(TaskRunnerType runner_type) + -> TaskRunnerPtr { + std::lock_guard<std::mutex> lock_guard(task_runners_map_lock_); while (true) { auto it = task_runners_.find(runner_type); if (it != task_runners_.end()) { return it->second; - } else { - auto runner = new TaskRunner(); - task_runners_[runner_type] = runner; - runner->start(); - continue; + } + + auto runner = GpgFrontend::SecureCreateSharedObject<TaskRunner>(); + task_runners_[runner_type] = runner; + runner->Start(); + } +} + +void TaskRunnerGetter::StopAllTeakRunner() { + for (const auto& [key, value] : task_runners_) { + if (value->IsRunning()) { + value->Stop(); } } } + +} // namespace GpgFrontend::Thread
\ No newline at end of file diff --git a/src/core/thread/TaskRunnerGetter.h b/src/core/thread/TaskRunnerGetter.h index 80b25c3e..49ed25c0 100644 --- a/src/core/thread/TaskRunnerGetter.h +++ b/src/core/thread/TaskRunnerGetter.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -19,20 +19,25 @@ * The initial version of the source code is inherited from * the gpg4usb project, which is under GPL-3.0-or-later. * - * The source code version of this software was modified and released - * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021. + * 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 * */ -#ifndef GPGFRONTEND_TASKRUNNERGETTER_H -#define GPGFRONTEND_TASKRUNNERGETTER_H +#pragma once + +#include <mutex> #include "core/GpgFrontendCore.h" -#include "core/GpgFunctionObject.h" +#include "core/function/basic/GpgFunctionObject.h" #include "core/thread/TaskRunner.h" namespace GpgFrontend::Thread { +using TaskRunnerPtr = std::shared_ptr<TaskRunner>; + class GPGFRONTEND_CORE_EXPORT TaskRunnerGetter : public GpgFrontend::SingletonFunctionObject<TaskRunnerGetter> { public: @@ -41,18 +46,21 @@ class GPGFRONTEND_CORE_EXPORT TaskRunnerGetter kTaskRunnerType_GPG, kTaskRunnerType_IO, kTaskRunnerType_Network, + kTaskRunnerType_Module, kTaskRunnerType_External_Process, }; - TaskRunnerGetter(int channel = SingletonFunctionObject::GetDefaultChannel()); + explicit TaskRunnerGetter( + int channel = SingletonFunctionObject::GetDefaultChannel()); - TaskRunner *GetTaskRunner( - TaskRunnerType runner_type = kTaskRunnerType_Default); + auto GetTaskRunner(TaskRunnerType runner_type = kTaskRunnerType_Default) + -> TaskRunnerPtr; + + void StopAllTeakRunner(); private: - std::map<TaskRunnerType, TaskRunner *> task_runners_; + std::map<TaskRunnerType, TaskRunnerPtr> task_runners_; + std::mutex task_runners_map_lock_; }; } // namespace GpgFrontend::Thread - -#endif // GPGFRONTEND_TASKRUNNERGETTER_H
\ No newline at end of file diff --git a/src/core/thread/ThreadingModel.h b/src/core/thread/ThreadingModel.h index eb6c9039..2fcc11c8 100644 --- a/src/core/thread/ThreadingModel.h +++ b/src/core/thread/ThreadingModel.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,17 +20,14 @@ * 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_THREADINGMODEL_H -#define GPGFRONTEND_THREADINGMODEL_H +#pragma once #include "core/thread/Task.h" #include "core/thread/TaskRunner.h" #include "core/thread/TaskRunnerGetter.h" - -#endif // GPGFRONTEND_THREADINGMODEL_H
\ No newline at end of file diff --git a/src/core/typedef/CoreTypedef.h b/src/core/typedef/CoreTypedef.h new file mode 100644 index 00000000..51c6d11a --- /dev/null +++ b/src/core/typedef/CoreTypedef.h @@ -0,0 +1,49 @@ +/** + * 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/model/DataObject.h" + +namespace GpgFrontend { + +using GFError = uint32_t; +using ByteArray = QByteArray; ///< +using ByteArrayPtr = std::shared_ptr<ByteArray>; ///< +using StdBypeArrayPtr = std::shared_ptr<ByteArray>; ///< +using BypeArrayRef = ByteArray&; ///< +using ConstBypeArrayRef = const ByteArray&; ///< +using BypeArrayConstRef = const ByteArray&; ///< +using StringArgsPtr = std::unique_ptr<std::vector<QString>>; ///< +using StringArgsRef = std::vector<QString>&; ///< + /// + /// + +using OperaRunnable = std::function<GFError(DataObjectPtr)>; +using OperationCallback = std::function<void(GFError, DataObjectPtr)>; +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/typedef/GpgTypedef.h b/src/core/typedef/GpgTypedef.h new file mode 100644 index 00000000..cf0887bf --- /dev/null +++ b/src/core/typedef/GpgTypedef.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 <tuple> + +#include "core/model/DataObject.h" + +namespace GpgFrontend { + +class GpgKey; ///< forward declaration +class GpgSubKey; +class GpgSignature; +class GpgTOFUInfo; + +using GpgError = gpgme_error_t; ///< gpgme error +using GpgErrorCode = gpg_err_code_t; +using GpgErrorDesc = std::pair<QString, QString>; + +using KeyId = QString; ///< +using SubkeyId = QString; ///< +using KeyIdArgsList = std::vector<KeyId>; ///< +using KeyIdArgsListPtr = std::unique_ptr<KeyIdArgsList>; ///< +using UIDArgsList = std::vector<QString>; ///< +using UIDArgsListPtr = std::unique_ptr<UIDArgsList>; ///< +using SignIdArgsList = std::vector<std::pair<QString, QString>>; ///< +using SignIdArgsListPtr = std::unique_ptr<SignIdArgsList>; ///< +using KeyFprArgsListPtr = std::unique_ptr<std::vector<QString>>; ///< +using KeyArgsList = std::vector<GpgKey>; ///< +using KeyListPtr = std::shared_ptr<KeyArgsList>; ///< +using GpgKeyLinkList = std::list<GpgKey>; ///< +using KeyLinkListPtr = std::unique_ptr<GpgKeyLinkList>; ///< +using KeyPtr = std::unique_ptr<GpgKey>; ///< +using KeyPtrArgsList = const std::initializer_list<KeyPtr>; ///< + +using GpgSignMode = gpgme_sig_mode_t; + +using GpgOperaRunnable = std::function<GpgError(DataObjectPtr)>; +using GpgOperationCallback = std::function<void(GpgError, DataObjectPtr)>; +using GpgOperationFuture = std::future<std::tuple<GpgError, DataObjectPtr>>; + +enum GpgOperation { + kENCRYPT, + kDECRYPT, + kSIGN, + kVERIFY, + kENCRYPT_SIGN, + kDECRYPT_VERIFY +}; +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/utils/AsyncUtils.cpp b/src/core/utils/AsyncUtils.cpp new file mode 100644 index 00000000..9ce94247 --- /dev/null +++ b/src/core/utils/AsyncUtils.cpp @@ -0,0 +1,154 @@ +/** + * 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 "AsyncUtils.h" + +#include "core/module/ModuleManager.h" +#include "core/thread/Task.h" +#include "core/thread/TaskRunnerGetter.h" +#include "core/utils/CommonUtils.h" +#include "model/DataObject.h" + +namespace GpgFrontend { + +auto RunGpgOperaAsync(const GpgOperaRunnable& runnable, + const GpgOperationCallback& callback, + const QString& operation, const QString& minial_version) + -> Thread::Task::TaskHandler { + const auto gnupg_version = Module::RetrieveRTValueTypedOrDefault<>( + "core", "gpgme.ctx.gnupg_version", minial_version); + GF_CORE_LOG_DEBUG("got gnupg version from rt: {}, operation: {}", + gnupg_version, operation); + + if (CompareSoftwareVersion(gnupg_version, minial_version) < 0) { + GF_CORE_LOG_ERROR("operaton {} not support for gnupg version: {}", + operation, gnupg_version); + callback(GPG_ERR_NOT_SUPPORTED, TransferParams()); + return Thread::Task::TaskHandler(nullptr); + } + + auto handler = + Thread::TaskRunnerGetter::GetInstance() + .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_GPG) + ->RegisterTask( + operation, + [=](const DataObjectPtr& data_object) -> int { + auto custom_data_object = TransferParams(); + auto err = runnable(custom_data_object); + data_object->Swap({err, custom_data_object}); + return 0; + }, + [=](int rtn, const DataObjectPtr& data_object) { + if (rtn < 0) { + callback(GPG_ERR_USER_1, + ExtractParams<DataObjectPtr>(data_object, 1)); + } else { + callback(ExtractParams<GpgError>(data_object, 0), + ExtractParams<DataObjectPtr>(data_object, 1)); + } + }, + TransferParams()); + handler.Start(); + return handler; +} + +auto RunGpgOperaSync(const GpgOperaRunnable& runnable, const QString& operation, + const QString& minial_version) + -> std::tuple<GpgError, DataObjectPtr> { + const auto gnupg_version = Module::RetrieveRTValueTypedOrDefault<>( + "core", "gpgme.ctx.gnupg_version", minial_version); + GF_CORE_LOG_DEBUG("got gnupg version from rt: {}, operation: {}", + gnupg_version, operation); + + if (CompareSoftwareVersion(gnupg_version, minial_version) < 0) { + GF_CORE_LOG_ERROR("operaton {} not support for gnupg version: {}", + operation, gnupg_version); + return {GPG_ERR_NOT_SUPPORTED, TransferParams()}; + } + + auto data_object = TransferParams(); + auto err = runnable(data_object); + return {err, data_object}; +} + +auto RunIOOperaAsync(const OperaRunnable& runnable, + const OperationCallback& callback, + const QString& operation) -> Thread::Task::TaskHandler { + auto handler = + Thread::TaskRunnerGetter::GetInstance() + .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_IO) + ->RegisterTask( + operation, + [=](const DataObjectPtr& data_object) -> int { + auto custom_data_object = TransferParams(); + GpgError err = runnable(custom_data_object); + + data_object->Swap({err, custom_data_object}); + return 0; + }, + [=](int rtn, const DataObjectPtr& data_object) { + if (rtn < 0) { + callback(-1, ExtractParams<DataObjectPtr>(data_object, 1)); + } else { + callback(ExtractParams<GFError>(data_object, 0), + ExtractParams<DataObjectPtr>(data_object, 1)); + } + }, + TransferParams()); + handler.Start(); + return handler; +} + +auto RunOperaAsync(const OperaRunnable& runnable, + const OperationCallback& callback, const QString& operation) + -> Thread::Task::TaskHandler { + auto handler = + Thread::TaskRunnerGetter::GetInstance() + .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_Default) + ->RegisterTask( + operation, + [=](const DataObjectPtr& data_object) -> int { + auto custom_data_object = TransferParams(); + GpgError err = runnable(custom_data_object); + + data_object->Swap({err, custom_data_object}); + return 0; + }, + [=](int rtn, const DataObjectPtr& data_object) { + if (rtn < 0) { + callback(-1, ExtractParams<DataObjectPtr>(data_object, 1)); + } else { + callback(ExtractParams<GFError>(data_object, 0), + ExtractParams<DataObjectPtr>(data_object, 1)); + } + }, + TransferParams()); + handler.Start(); + return handler; +} +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/utils/AsyncUtils.h b/src/core/utils/AsyncUtils.h new file mode 100644 index 00000000..c16fc122 --- /dev/null +++ b/src/core/utils/AsyncUtils.h @@ -0,0 +1,88 @@ +/** + * 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/GpgFrontendCore.h" +#include "core/thread/Task.h" +#include "core/typedef/CoreTypedef.h" +#include "core/typedef/GpgTypedef.h" + +namespace GpgFrontend { + +/** + * @brief + * + * @param runnable + * @param callback + * @param operation + * @param minial_version + */ +auto GPGFRONTEND_CORE_EXPORT +RunGpgOperaAsync(const GpgOperaRunnable& runnable, + const GpgOperationCallback& callback, const QString& operation, + const QString& minial_version) -> Thread::Task::TaskHandler; + +/** + * @brief + * + * @param runnable + * @param operation + * @param minial_version + * @return std::tuple<GpgError, DataObjectPtr> + */ +auto GPGFRONTEND_CORE_EXPORT RunGpgOperaSync(const GpgOperaRunnable& runnable, + const QString& operation, + const QString& minial_version) + -> std::tuple<GpgError, DataObjectPtr>; + +/** + * @brief + * + * @param runnable + * @param callback + * @param operation + */ +auto GPGFRONTEND_CORE_EXPORT RunIOOperaAsync(const OperaRunnable& runnable, + const OperationCallback& callback, + const QString& operation) + -> Thread::Task::TaskHandler; + +/** + * @brief + * + * @param runnable + * @param callback + * @param operation + * @return Thread::Task::TaskHandler + */ +auto GPGFRONTEND_CORE_EXPORT RunOperaAsync(const OperaRunnable& runnable, + const OperationCallback& callback, + const QString& operation) + -> Thread::Task::TaskHandler; +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/utils/CacheUtils.cpp b/src/core/utils/CacheUtils.cpp new file mode 100644 index 00000000..e521870c --- /dev/null +++ b/src/core/utils/CacheUtils.cpp @@ -0,0 +1,47 @@ +/** + * 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 "CacheUtils.h" + +#include "core/function/CacheManager.h" + +namespace GpgFrontend { + +void SetCacheValue(const QString& key, QString value) { + CacheManager::GetInstance().SaveCache(key, std::move(value)); +} + +auto GetCacheValue(const QString& key) -> QString { + return CacheManager::GetInstance().LoadCache(key); +} + +void ResetCacheValue(const QString& key) { + CacheManager::GetInstance().ResetCache(key); +} + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/utils/CacheUtils.h b/src/core/utils/CacheUtils.h new file mode 100644 index 00000000..48b9ac4b --- /dev/null +++ b/src/core/utils/CacheUtils.h @@ -0,0 +1,54 @@ +/** + * 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 + +namespace GpgFrontend { + +/** + * @brief set a temp cache under a certain key + * + */ +void GPGFRONTEND_CORE_EXPORT SetCacheValue(const QString &key, QString value); + +/** + * @brief after get the temp cache, its value will be imediately ease in + * storage + * + * @return QString + */ +auto GPGFRONTEND_CORE_EXPORT GetCacheValue(const QString &key) -> QString; + +/** + * @brief imediately ease temp cache in storage + * + * @return QString + */ +void GPGFRONTEND_CORE_EXPORT ResetCacheValue(const QString &); + +} // namespace GpgFrontend diff --git a/src/core/utils/CommonUtils.cpp b/src/core/utils/CommonUtils.cpp new file mode 100644 index 00000000..0b182241 --- /dev/null +++ b/src/core/utils/CommonUtils.cpp @@ -0,0 +1,74 @@ +/** + * 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 "CommonUtils.h" + +namespace GpgFrontend { + +auto BeautifyFingerprint(QString fingerprint) -> QString { + auto len = fingerprint.size(); + QString buffer; + QTextStream out(&buffer); + decltype(len) count = 0; + while (count < len) { + if ((count != 0U) && ((count % 5) == 0)) out << " "; + out << fingerprint[count]; + count++; + } + return out.readAll(); +} + +auto CompareSoftwareVersion(const QString& a, const QString& b) -> int { + auto remove_prefix = [](const QString& version) { + return version.startsWith('v') ? version.mid(1) : version; + }; + + auto real_version_a = remove_prefix(a); + auto real_version_b = remove_prefix(b); + + QStringList split_a = real_version_a.split('.'); + QStringList split_b = real_version_b.split('.'); + + const auto min_depth = std::min(split_a.size(), split_b.size()); + + for (int i = 0; i < min_depth; ++i) { + int const num_a = split_a[i].toInt(); + int const num_b = split_b[i].toInt(); + + if (num_a != num_b) { + return (num_a > num_b) ? 1 : -1; + } + } + + if (split_a.size() != split_b.size()) { + return (split_a.size() > split_b.size()) ? 1 : -1; + } + + return 0; +} +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/utils/CommonUtils.h b/src/core/utils/CommonUtils.h new file mode 100644 index 00000000..a45c6056 --- /dev/null +++ b/src/core/utils/CommonUtils.h @@ -0,0 +1,54 @@ +/** + * 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/typedef/CoreTypedef.h" + +namespace GpgFrontend { + +/** + * @brief + * + * @param fingerprint + * @return QString + */ +auto GPGFRONTEND_CORE_EXPORT BeautifyFingerprint(QString fingerprint) + -> QString; + +/** + * @brief + * + * @param a + * @param b + * @return int + */ +auto GPGFRONTEND_CORE_EXPORT CompareSoftwareVersion(const QString& a, + const QString& b) -> int; + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/utils/FilesystemUtils.cpp b/src/core/utils/FilesystemUtils.cpp new file mode 100644 index 00000000..9e531955 --- /dev/null +++ b/src/core/utils/FilesystemUtils.cpp @@ -0,0 +1,104 @@ +/** + * 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 "FilesystemUtils.h" + +namespace GpgFrontend { + +auto GetOnlyFileNameWithPath(const QString &path) -> QString { + // Create a path object from given string + QFileInfo file_info(path); + // Check if file name in the path object has extension + if (!file_info.fileName().isEmpty()) { + // Fetch the extension from path object and return + return file_info.path() + "/" + file_info.baseName(); + } + // In case of no extension return empty string + return {}; +} + +auto GetFileExtension(const QString &path) -> QString { + return QFileInfo(path).suffix(); +} + +/** + * @brief + * + */ +auto GetFileSizeByPath(const QString &path, const QString &filename_pattern) + -> int64_t { + auto dir = QDir(path); + QFileInfoList const file_list = + dir.entryInfoList(QStringList() << filename_pattern, QDir::Files); + qint64 total_size = 0; + + for (const QFileInfo &file_info : file_list) { + total_size += file_info.size(); + } + return total_size; +} + +/** + * @brief + * + */ +auto GetHumanFriendlyFileSize(int64_t size) -> QString { + auto num = static_cast<double>(size); + QStringList list; + list << "KB" + << "MB" + << "GB" + << "TB"; + + QStringListIterator i(list); + QString unit("bytes"); + + while (num >= 1024.0 && i.hasNext()) { + unit = i.next(); + num /= 1024.0; + } + return (QString().setNum(num, 'f', 2) + " " + unit); +} + +/** + * @brief + * + */ +void DeleteAllFilesByPattern(const QString &path, + const QString &filename_pattern) { + auto dir = QDir(path); + + QStringList const log_files = + dir.entryList(QStringList() << filename_pattern, QDir::Files); + + for (const auto &file : log_files) { + QFile::remove(dir.absoluteFilePath(file)); + } +} + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/utils/FilesystemUtils.h b/src/core/utils/FilesystemUtils.h new file mode 100644 index 00000000..0b58bbb7 --- /dev/null +++ b/src/core/utils/FilesystemUtils.h @@ -0,0 +1,78 @@ +/** + * 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 + +namespace GpgFrontend { + +/** + * @brief Get the file extension object + * + * @param path + * @return QString + */ +auto GPGFRONTEND_CORE_EXPORT GetFileExtension(const QString& path) -> QString; + +/** + * @brief Get the only file name with path object + * + * @param path + * @return QString + */ +auto GPGFRONTEND_CORE_EXPORT GetOnlyFileNameWithPath(const QString& path) + -> QString; + +/** + * @brief Get the File Size By Path object + * + * @param path The path of the file + * @param filename_pattern The pattern of the file name, e.g. "*.txt" + * @return int64_t + */ +auto GPGFRONTEND_CORE_EXPORT GetFileSizeByPath( + const QString& path, const QString& filename_pattern) + -> int64_t; + +/** + * @brief Get the Human Readable File Size object + * + * @param size + * @return QString + */ +auto GPGFRONTEND_CORE_EXPORT GetHumanFriendlyFileSize(int64_t size) -> QString; + +/** + * @brief + * + * @param path + * @param filename_pattern + */ +void GPGFRONTEND_CORE_EXPORT DeleteAllFilesByPattern( + const QString& path, const QString& filename_pattern); + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/utils/GpgUtils.cpp b/src/core/utils/GpgUtils.cpp new file mode 100644 index 00000000..db3513eb --- /dev/null +++ b/src/core/utils/GpgUtils.cpp @@ -0,0 +1,167 @@ +/** + * 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 "GpgUtils.h" + +namespace GpgFrontend { + +inline auto Trim(QString& s) -> QString { return s.trimmed(); } + +auto GetGpgmeErrorString(size_t buffer_size, gpgme_error_t err) -> QString { + std::vector<char> buffer(buffer_size); + + gpgme_error_t const ret = gpgme_strerror_r(err, buffer.data(), buffer.size()); + if (ret == ERANGE && buffer_size < 1024) { + return GetGpgmeErrorString(buffer_size * 2, err); + } + + return {buffer.data()}; +} + +auto GetGpgmeErrorString(gpgme_error_t err) -> QString { + return GetGpgmeErrorString(64, err); +} + +auto CheckGpgError(GpgError err) -> GpgError { + auto err_code = gpg_err_code(err); + if (err_code != GPG_ERR_NO_ERROR) { + GF_CORE_LOG_ERROR( + "gpg operation failed [error code: {}], source: {} description: {}", + err_code, gpgme_strsource(err), GetGpgmeErrorString(err)); + } + return err_code; +} + +auto CheckGpgError2ErrCode(GpgError err, GpgError predict) -> GpgErrorCode { + auto err_code = gpg_err_code(err); + if (err_code != gpg_err_code(predict)) { + if (err_code == GPG_ERR_NO_ERROR) { + GF_CORE_LOG_WARN("[Warning {}] Source: {} description: {} predict: {}", + gpg_err_code(err), gpgme_strsource(err), + GetGpgmeErrorString(err), GetGpgmeErrorString(predict)); + } else { + GF_CORE_LOG_ERROR("[Error {}] Source: {} description: {} predict: {}", + gpg_err_code(err), gpgme_strsource(err), + GetGpgmeErrorString(err), GetGpgmeErrorString(predict)); + } + } + return err_code; +} + +auto DescribeGpgErrCode(GpgError err) -> GpgErrorDesc { + return {gpgme_strsource(err), GetGpgmeErrorString(err)}; +} + +auto CheckGpgError(GpgError err, const QString& /*comment*/) -> GpgError { + if (gpg_err_code(err) != GPG_ERR_NO_ERROR) { + GF_CORE_LOG_WARN("[Error {}] Source: {} description: {}", gpg_err_code(err), + gpgme_strsource(err), GetGpgmeErrorString(err)); + } + return err; +} + +auto TextIsSigned(QString text) -> int { + auto trim_text = Trim(text); + if (trim_text.startsWith(PGP_SIGNED_BEGIN) && + trim_text.endsWith(PGP_SIGNED_END)) { + return 2; + } + if (text.contains(PGP_SIGNED_BEGIN) && text.contains(PGP_SIGNED_END)) { + return 1; + } + return 0; +} + +auto SetExtensionOfOutputFile(const QString& path, GpgOperation opera, + bool ascii) -> QString { + QString new_extension; + QString current_extension = QFileInfo(path).suffix(); + + if (ascii) { + switch (opera) { + case kENCRYPT: + case kSIGN: + case kENCRYPT_SIGN: + new_extension = current_extension + ".asc"; + break; + default: + break; + } + } else { + switch (opera) { + case kENCRYPT: + case kENCRYPT_SIGN: + new_extension = current_extension + ".gpg"; + break; + case kSIGN: + new_extension = current_extension + ".sig"; + break; + default: + break; + } + } + + if (!new_extension.isEmpty()) { + return QFileInfo(path).path() + "/" + QFileInfo(path).completeBaseName() + + "." + new_extension; + } + + return path; +} + +auto SetExtensionOfOutputFileForArchive(const QString& path, GpgOperation opera, + bool ascii) -> QString { + QString extension; + + if (ascii) { + switch (opera) { + case kENCRYPT: + case kENCRYPT_SIGN: + extension = ".tar.asc"; + return path + extension; + break; + default: + break; + } + } else { + switch (opera) { + case kENCRYPT: + case kENCRYPT_SIGN: + extension = ".tar.gpg"; + return path + extension; + break; + default: + break; + } + } + + auto file_info = QFileInfo(path); + return file_info.absolutePath() + "/" + file_info.baseName(); +} + +} // namespace GpgFrontend diff --git a/src/core/utils/GpgUtils.h b/src/core/utils/GpgUtils.h new file mode 100644 index 00000000..e6a466dc --- /dev/null +++ b/src/core/utils/GpgUtils.h @@ -0,0 +1,108 @@ +/** + * 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/result_analyse/GpgResultAnalyse.h" +#include "core/typedef/CoreTypedef.h" +#include "core/typedef/GpgTypedef.h" + +namespace GpgFrontend { + +// Error Info Printer + +/** + * @brief + * + * @param err + * @return GpgError + */ +auto GPGFRONTEND_CORE_EXPORT CheckGpgError(GpgError err) -> GpgError; + +/** + * @brief + * + * @param gpgmeError + * @param comment + * @return GpgError + */ +auto GPGFRONTEND_CORE_EXPORT CheckGpgError(GpgError gpgmeError, + const QString& comment) -> GpgError; + +/** + * @brief + * + * @param err + * @param predict + * @return gpg_err_code_t + */ +auto GPGFRONTEND_CORE_EXPORT CheckGpgError2ErrCode( + gpgme_error_t err, gpgme_error_t predict = GPG_ERR_NO_ERROR) + -> gpg_err_code_t; + +/** + * @brief + * + * @param err + * @return GpgErrorDesc + */ +auto GPGFRONTEND_CORE_EXPORT DescribeGpgErrCode(GpgError err) -> GpgErrorDesc; + +// Check + +/** + * @brief + * + * @param text + * @return int + */ +auto GPGFRONTEND_CORE_EXPORT TextIsSigned(BypeArrayRef text) -> int; + +/** + * @brief + * + * @param opera + * @param ascii + * @return QString + */ +auto GPGFRONTEND_CORE_EXPORT SetExtensionOfOutputFile(const QString& path, + GpgOperation opera, + bool ascii) -> QString; + +/** + * @brief + * + * @param path + * @param opera + * @param ascii + * @return QString + */ +auto GPGFRONTEND_CORE_EXPORT SetExtensionOfOutputFileForArchive( + const QString& path, GpgOperation opera, bool ascii) -> QString; + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/utils/IOUtils.cpp b/src/core/utils/IOUtils.cpp new file mode 100644 index 00000000..1541d726 --- /dev/null +++ b/src/core/utils/IOUtils.cpp @@ -0,0 +1,178 @@ +/** + * 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 "IOUtils.h" + +#include "core/GpgModel.h" +#include "core/utils/FilesystemUtils.h" + +namespace GpgFrontend { + +auto GetFileChecksum(const QString& file_name, + QCryptographicHash::Algorithm hashAlgorithm) + -> QByteArray { + QFile f(file_name); + if (f.open(QFile::ReadOnly)) { + QCryptographicHash hash(hashAlgorithm); + if (hash.addData(&f)) { + return hash.result(); + } + } + return {}; +} + +auto ReadFile(const QString& file_name, QByteArray& data) -> bool { + QFile file(file_name); + if (!file.open(QIODevice::ReadOnly)) { + GF_CORE_LOG_ERROR("failed to open file: {}", file_name); + return false; + } + data = file.readAll(); + file.close(); + return true; +} + +auto WriteFile(const QString& file_name, const QByteArray& data) -> bool { + QFile file(file_name); + if (!file.open(QIODevice::WriteOnly)) { + GF_CORE_LOG_ERROR("failed to open file for writing: {}", file_name); + return false; + } + file.write(data); + file.close(); + return true; +} + +auto ReadFileGFBuffer(const QString& file_name) -> std::tuple<bool, GFBuffer> { + QByteArray byte_data; + const bool res = ReadFile(file_name, byte_data); + + return {res, GFBuffer(byte_data)}; +} + +auto WriteFileGFBuffer(const QString& file_name, GFBuffer data) -> bool { + return WriteFile(file_name, data.ConvertToQByteArray()); +} + +auto CalculateHash(const QString& file_path) -> QString { + // Returns empty QByteArray() on failure. + QFileInfo const info(file_path); + QString buffer; + QTextStream ss(&buffer); + + if (info.isFile() && info.isReadable()) { + ss << "# " << QObject::tr("File Hash Information") << Qt::endl; + ss << "- " << QObject::tr("Filename") << QObject::tr(": ") + << info.fileName() << Qt::endl; + + // read all data + ss << "- " << QObject::tr("File Size (bytes)") << QObject::tr(": ") + << QString::number(info.size()) << Qt::endl; + + ss << "- " << QObject::tr("File Size") << QObject::tr(": ") + << GetHumanFriendlyFileSize(info.size()) << Qt::endl; + + // md5 + ss << "- " + << "MD5" << QObject::tr(": ") + << GetFileChecksum(file_path, QCryptographicHash::Md5).toHex() + << Qt::endl; + + // sha1 + ss << "- " + << "SHA1" << QObject::tr(": ") + << GetFileChecksum(file_path, QCryptographicHash::Sha1).toHex() + << Qt::endl; + + // sha1 + ss << "- " + << "SHA256" << QObject::tr(": ") + << GetFileChecksum(file_path, QCryptographicHash::Sha256).toHex() + << Qt::endl; + + ss << Qt::endl; + + } else { + ss << "# " << QObject::tr("Error: cannot read target file") << Qt::endl; + ss << "- " << QObject::tr("Filename") << QObject::tr(": ") + << info.fileName() << Qt::endl; + } + + return ss.readAll(); +} + +auto GetTempFilePath() -> QString { + QString const temp_dir = QDir::tempPath(); + QString const filename = QUuid::createUuid().toString() + ".data"; + return temp_dir + "/" + filename; +} + +auto CreateTempFileAndWriteData(const QString& data) -> QString { + auto temp_file = GetTempFilePath(); + WriteFile(temp_file, data.toUtf8()); + return temp_file; +} + +auto CreateTempFileAndWriteData(const GFBuffer& data) -> QString { + auto temp_file = GetTempFilePath(); + WriteFile(temp_file, data.ConvertToQByteArray()); + return temp_file; +} + +auto TargetFilePreCheck(const QString& path, bool read) + -> std::tuple<bool, QString> { + QFileInfo const file_info(path); + + if (read) { + if (!file_info.exists()) { + return {false, QObject::tr("target path doesn't exists")}; + } + } else { + QFileInfo const path_info(file_info.absolutePath()); + if (!path_info.isWritable()) { + return {false, QObject::tr("do NOT have permission to write path")}; + } + } + + if (read ? !file_info.isReadable() : false) { + return {false, QObject::tr("do NOT have permission to read/write file")}; + } + + return {true, QObject::tr("Success")}; +} + +auto GetFullExtension(const QString& path) -> QString { + QString const filename = QFileInfo(path).fileName(); + + auto const dot_index = filename.indexOf('.'); + if (dot_index == -1) return {}; + + return filename.mid(dot_index); +} + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/utils/IOUtils.h b/src/core/utils/IOUtils.h new file mode 100644 index 00000000..2c48f38c --- /dev/null +++ b/src/core/utils/IOUtils.h @@ -0,0 +1,139 @@ +/** + * 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/model/GFBuffer.h" + +namespace GpgFrontend { + +/** + * @brief + * + * @param file_name + * @return GFBuffer + */ +auto GPGFRONTEND_CORE_EXPORT ReadFileGFBuffer(const QString &file_name) + -> std::tuple<bool, GFBuffer>; + +/** + * @brief + * + * @param file_name + * @param data + * @return true + * @return false + */ +auto GPGFRONTEND_CORE_EXPORT WriteFileGFBuffer(const QString &file_name, + GFBuffer data) -> bool; + +/** + * @brief read file content + * + * @param file_name file name + * @param data data read from file + * @return true if success + * @return false if failed + */ +auto GPGFRONTEND_CORE_EXPORT ReadFile(const QString &file_name, + QByteArray &data) -> bool; + +/** + * @brief write file content + * + * @param file_name file name + * @param data data to write to file + * @return true if success + * @return false if failed + */ +auto GPGFRONTEND_CORE_EXPORT WriteFile(const QString &file_name, + const QByteArray &data) -> bool; + +/** + * calculate the hash of a file + * @param file_path + * @return + */ +auto GPGFRONTEND_CORE_EXPORT CalculateHash(const QString &file_path) -> QString; + +/** + * @brief + * + * @param path + * @param out_buffer + * @return true + * @return false + */ +auto GPGFRONTEND_CORE_EXPORT WriteBufferToFile(const QString &path, + const QString &out_buffer) + -> bool; + +/** + * @brief + * + * @return QString + */ +auto GPGFRONTEND_CORE_EXPORT GetTempFilePath() -> QString; + +/** + * @brief + * + * @param data + * @return QString + */ +auto GPGFRONTEND_CORE_EXPORT CreateTempFileAndWriteData(const QString &data) + -> QString; + +/** + * @brief + * + * @param data + * @return QString + */ +auto GPGFRONTEND_CORE_EXPORT CreateTempFileAndWriteData(const GFBuffer &data) + -> QString; + +/** + * @brief + * + * @param path + * @param read + * @return std::tuple<bool, QString> + */ +auto GPGFRONTEND_CORE_EXPORT TargetFilePreCheck(const QString &path, bool read) + -> std::tuple<bool, QString>; + +/** + * @brief + * + * @param path + * @return QString + */ +auto GPGFRONTEND_CORE_EXPORT GetFullExtension(QString path) -> QString; + +} // namespace GpgFrontend diff --git a/src/core/function/CharsetOperator.h b/src/core/utils/LocalizedUtils.cpp index 41ce62f4..6c020ed7 100644 --- a/src/core/function/CharsetOperator.h +++ b/src/core/utils/LocalizedUtils.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,28 +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_CHARSETDETECTOR_H -#define GPGFRONTEND_CHARSETDETECTOR_H +#include "LocalizedUtils.h" -#include "core/GpgFrontendCore.h" +#include "core/utils/LogUtils.h" namespace GpgFrontend { -class GPGFRONTEND_CORE_EXPORT CharsetOperator { - public: - using CharsetInfo = std::tuple<std::string, std::string, int>; - - static CharsetInfo Detect(const std::string &buffer); - - static bool Convert2Utf8(const std::string &buffer, std::string &out_buffer, - std::string from_charset_name); -}; +auto GetFormatedDateByTimestamp(time_t timestamp) -> QString { + return QLocale().toString(QDateTime::fromSecsSinceEpoch(timestamp)); +} } // namespace GpgFrontend - -#endif // GPGFRONTEND_CHARSETDETECTOR_H diff --git a/src/core/utils/LocalizedUtils.h b/src/core/utils/LocalizedUtils.h new file mode 100644 index 00000000..d7aaf0c8 --- /dev/null +++ b/src/core/utils/LocalizedUtils.h @@ -0,0 +1,35 @@ +/** + * 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 + +namespace GpgFrontend { + +auto GPGFRONTEND_CORE_EXPORT GetFormatedDateByTimestamp(time_t) -> QString; + +}
\ No newline at end of file diff --git a/src/core/utils/LogUtils.cpp b/src/core/utils/LogUtils.cpp new file mode 100644 index 00000000..fbf0c8d3 --- /dev/null +++ b/src/core/utils/LogUtils.cpp @@ -0,0 +1,59 @@ +/** + * 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 "LogUtils.h" + +#include "core/function/LoggerManager.h" + +namespace GpgFrontend { + +auto GetDefaultLogger() -> std::shared_ptr<spdlog::logger> { + return LoggerManager::GetDefaultLogger(); +} + +auto GetCoreLogger() -> std::shared_ptr<spdlog::logger> { + return LoggerManager::GetInstance().GetLogger("core"); +} + +auto GetLogger(const QString& id) -> std::shared_ptr<spdlog::logger> { + return LoggerManager::GetInstance().GetLogger(id); +} + +void SetDefaultLogLevel(spdlog::level::level_enum level) { + return LoggerManager::SetDefaultLogLevel(level); +} + +void RegisterAsyncLogger(const QString& id, spdlog::level::level_enum level) { + LoggerManager::GetInstance().RegisterAsyncLogger(id, level); +} + +void RegisterSyncLogger(const QString& id, spdlog::level::level_enum level) { + LoggerManager::GetInstance().RegisterSyncLogger(id, level); +} + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/utils/LogUtils.h b/src/core/utils/LogUtils.h new file mode 100644 index 00000000..a1a5685a --- /dev/null +++ b/src/core/utils/LogUtils.h @@ -0,0 +1,112 @@ +/** + * 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 + +namespace GpgFrontend { + +/** + * @brief + * + * @return std::shared_ptr<spdlog::logger> + */ +auto GPGFRONTEND_CORE_EXPORT GetDefaultLogger() + -> std::shared_ptr<spdlog::logger>; + +/** + * @brief + * + * @return std::shared_ptr<spdlog::logger> + */ +auto GPGFRONTEND_CORE_EXPORT GetCoreLogger() -> std::shared_ptr<spdlog::logger>; + +/** + * @brief + * + * @return std::shared_ptr<spdlog::logger> + */ +auto GPGFRONTEND_CORE_EXPORT GetLogger(const QString &) + -> std::shared_ptr<spdlog::logger>; + +/** + * @brief Set the Default Log Level object + * + * @return auto + */ +void GPGFRONTEND_CORE_EXPORT SetDefaultLogLevel(spdlog::level::level_enum); + +/** + * @brief + * + * @return auto + */ +void GPGFRONTEND_CORE_EXPORT RegisterAsyncLogger(const QString &, + spdlog::level::level_enum); + +/** + * @brief + * + * @return auto + */ +void GPGFRONTEND_CORE_EXPORT RegisterSyncLogger(const QString &, + spdlog::level::level_enum); + +} // namespace GpgFrontend + +#define GF_DEFAULT_LOG_TRACE(...) \ + SPDLOG_LOGGER_TRACE(GpgFrontend::GetDefaultLogger(), __VA_ARGS__) +#define GF_DEFAULT_LOG_DEBUG(...) \ + SPDLOG_LOGGER_DEBUG(GpgFrontend::GetDefaultLogger(), __VA_ARGS__) +#define GF_DEFAULT_LOG_INFO(...) \ + SPDLOG_LOGGER_INFO(GpgFrontend::GetDefaultLogger(), __VA_ARGS__) +#define GF_DEFAULT_LOG_WARN(...) \ + SPDLOG_LOGGER_WARN(GpgFrontend::GetDefaultLogger(), __VA_ARGS__) +#define GF_DEFAULT_LOG_ERROR(...) \ + SPDLOG_LOGGER_ERROR(GpgFrontend::GetDefaultLogger(), __VA_ARGS__) + +#define GF_CORE_LOG_TRACE(...) \ + SPDLOG_LOGGER_TRACE(GpgFrontend::GetCoreLogger(), __VA_ARGS__) +#define GF_CORE_LOG_DEBUG(...) \ + SPDLOG_LOGGER_DEBUG(GpgFrontend::GetCoreLogger(), __VA_ARGS__) +#define GF_CORE_LOG_INFO(...) \ + SPDLOG_LOGGER_INFO(GpgFrontend::GetCoreLogger(), __VA_ARGS__) +#define GF_CORE_LOG_WARN(...) \ + SPDLOG_LOGGER_WARN(GpgFrontend::GetCoreLogger(), __VA_ARGS__) +#define GF_CORE_LOG_ERROR(...) \ + SPDLOG_LOGGER_ERROR(GpgFrontend::GetCoreLogger(), __VA_ARGS__) + +#define GF_LOG_TRACE(ID, ...) \ + SPDLOG_LOGGER_TRACE(GpgFrontend::GetLogger(ID), __VA_ARGS__) +#define GF_LOG_DEBUG(ID, ...) \ + SPDLOG_LOGGER_DEBUG(GpgFrontend::GetLogger(ID), __VA_ARGS__) +#define GF_LOG_INFO(ID, ...) \ + SPDLOG_LOGGER_INFO(GpgFrontend::GetLogger(ID), __VA_ARGS__) +#define GF_LOG_WARN(ID, ...) \ + SPDLOG_LOGGER_WARN(GpgFrontend::GetLogger(ID), __VA_ARGS__) +#define GF_LOG_ERROR(ID, ...) \ + SPDLOG_LOGGER_ERROR(GpgFrontend::GetLogger(ID), __VA_ARGS__) diff --git a/src/core/utils/MemoryUtils.cpp b/src/core/utils/MemoryUtils.cpp new file mode 100644 index 00000000..f002fd87 --- /dev/null +++ b/src/core/utils/MemoryUtils.cpp @@ -0,0 +1,42 @@ +/** + * 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 "MemoryUtils.h" + +namespace GpgFrontend { + +auto SecureMalloc(std::size_t size) -> void * { + return SecureMemoryAllocator::Allocate(size); +} + +auto SecureRealloc(void *ptr, std::size_t size) -> void * { + return SecureMemoryAllocator::Reallocate(ptr, size); +} + +void SecureFree(void *ptr) { SecureMemoryAllocator::Deallocate(ptr); } +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/utils/MemoryUtils.h b/src/core/utils/MemoryUtils.h new file mode 100644 index 00000000..76c75fc6 --- /dev/null +++ b/src/core/utils/MemoryUtils.h @@ -0,0 +1,179 @@ +/** + * 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/GpgFrontendCoreExport.h" +#include "core/function/SecureMemoryAllocator.h" + +/* To avoid that a compiler optimizes certain memset calls away, these + macros may be used instead. */ +#define wipememory2(_ptr, _set, _len) \ + do { \ + volatile char *_vptr = (volatile char *)(_ptr); \ + size_t _vlen = (_len); \ + while (_vlen) { \ + *_vptr = (_set); \ + _vptr++; \ + _vlen--; \ + } \ + } while (0) +#define wipememory(_ptr, _len) wipememory2(_ptr, 0, _len) +#define wipe(_ptr, _len) wipememory2(_ptr, 0, _len) + +#define xtoi_1(p) \ + (*(p) <= '9' ? (*(p) - '0') \ + : *(p) <= 'F' ? (*(p) - 'A' + 10) \ + : (*(p) - 'a' + 10)) +#define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p) + 1)) + +namespace GpgFrontend { + +template <typename T> +class PointerConverter { + public: + explicit PointerConverter(void *ptr) : ptr_(ptr) {} + + auto AsType() const -> T * { return static_cast<T *>(ptr_); } + + private: + void *ptr_; +}; + +/** + * @brief + * + * @return void* + */ +auto GPGFRONTEND_CORE_EXPORT SecureMalloc(std::size_t) -> void *; + +/** + * @brief + * + * @return void* + */ +auto GPGFRONTEND_CORE_EXPORT SecureRealloc(void *, std::size_t) -> void *; + +/** + * @brief + * + * @tparam T + * @return T* + */ +template <typename T> +auto SecureMallocAsType(std::size_t size) -> T * { + return PointerConverter<T>(SecureMemoryAllocator::Allocate(size)).AsType(); +} + +/** + * @brief + * + * @return void* + */ +template <typename T> +auto SecureReallocAsType(T *ptr, std::size_t size) -> T * { + return PointerConverter<T>(SecureMemoryAllocator::Reallocate(ptr, size)) + .AsType(); +} + +/** + * @brief + * + */ +void GPGFRONTEND_CORE_EXPORT SecureFree(void *); + +template <typename T, typename... Args> +static auto SecureCreateObject(Args &&...args) -> T * { + void *mem = SecureMemoryAllocator::Allocate(sizeof(T)); + if (!mem) return nullptr; + + try { + return new (mem) T(std::forward<Args>(args)...); + } catch (...) { + SecureMemoryAllocator::Deallocate(mem); + throw; + } +} + +template <typename T> +static void SecureDestroyObject(T *obj) { + if (!obj) return; + obj->~T(); + SecureMemoryAllocator::Deallocate(obj); +} + +template <typename T, typename... Args> +static auto SecureCreateUniqueObject(Args &&...args) + -> std::unique_ptr<T, SecureObjectDeleter<T>> { + void *mem = SecureMemoryAllocator::Allocate(sizeof(T)); + if (!mem) throw std::bad_alloc(); + + try { + return std::unique_ptr<T, SecureObjectDeleter<T>>( + new (mem) T(std::forward<Args>(args)...)); + } catch (...) { + SecureMemoryAllocator::Deallocate(mem); + throw; + } +} + +template <typename T, typename... Args> +auto SecureCreateSharedObject(Args &&...args) -> std::shared_ptr<T> { + void *mem = SecureMemoryAllocator::Allocate(sizeof(T)); + if (!mem) throw std::bad_alloc(); + + try { + T *obj = new (mem) T(std::forward<Args>(args)...); + return std::shared_ptr<T>(obj, [](T *ptr) { + ptr->~T(); + SecureMemoryAllocator::Deallocate(ptr); + }); + } catch (...) { + SecureMemoryAllocator::Deallocate(mem); + throw; + } +} + +template <typename T, typename... Args> +auto SecureCreateQSharedObject(Args &&...args) -> QSharedPointer<T> { + void *mem = SecureMemoryAllocator::Allocate(sizeof(T)); + if (!mem) throw std::bad_alloc(); + + try { + T *obj = new (mem) T(std::forward<Args>(args)...); + return QSharedPointer<T>(obj, [](T *ptr) { + ptr->~T(); + SecureMemoryAllocator::Deallocate(ptr); + }); + } catch (...) { + SecureMemoryAllocator::Deallocate(mem); + throw; + } +} + +}; // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/function/aes/aes_ssl.h b/src/core/utils/aes/aes_ssl.h index e75b68dd..5c3ac935 100644 --- a/src/core/function/aes/aes_ssl.h +++ b/src/core/utils/aes/aes_ssl.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,14 +20,13 @@ * 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_AES_SSL_H -#define GPGFRONTEND_AES_SSL_H +#pragma once #include <openssl/aes.h> #include <openssl/evp.h> @@ -70,5 +69,3 @@ uint8_t *aes_256_cbc_encrypt(EVP_CIPHER_CTX *e, uint8_t *plaintext, int *len); uint8_t *aes_256_cbc_decrypt(EVP_CIPHER_CTX *e, uint8_t *ciphertext, int *len); } // namespace GpgFrontend::RawAPI - -#endif // GPGFRONTEND_AES_SSL_H diff --git a/src/core/function/aes/aes_ssl_cbc.cpp b/src/core/utils/aes/aes_ssl_cbc.cpp index 3aa80ef5..3aa80ef5 100644 --- a/src/core/function/aes/aes_ssl_cbc.cpp +++ b/src/core/utils/aes/aes_ssl_cbc.cpp |