diff options
Diffstat (limited to 'src/core/function')
60 files changed, 5477 insertions, 3396 deletions
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/CharsetOperator.h b/src/core/function/SecureMemoryAllocator.h index 41ce62f4..e9f1c1c3 100644 --- a/src/core/function/CharsetOperator.h +++ b/src/core/function/SecureMemoryAllocator.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,28 +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_CHARSETDETECTOR_H -#define GPGFRONTEND_CHARSETDETECTOR_H +#pragma once -#include "core/GpgFrontendCore.h" +#include <cstdint> +#include <memory> + +#include "core/utils/LogUtils.h" namespace GpgFrontend { -class GPGFRONTEND_CORE_EXPORT CharsetOperator { +class GPGFRONTEND_CORE_EXPORT SecureMemoryAllocator { public: - using CharsetInfo = std::tuple<std::string, std::string, int>; + static auto Allocate(std::size_t) -> void *; + + static auto Reallocate(void *, std::size_t) -> void *; - static CharsetInfo Detect(const std::string &buffer); + static void Deallocate(void *); +}; - static bool Convert2Utf8(const std::string &buffer, std::string &out_buffer, - std::string from_charset_name); +template <typename T> +struct SecureObjectDeleter { + void operator()(T *ptr) { + if (ptr) { + ptr->~T(); + SecureMemoryAllocator::Deallocate(ptr); + } + } }; -} // namespace GpgFrontend -#endif // GPGFRONTEND_CHARSETDETECTOR_H +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/aes/aes_ssl_cbc.cpp b/src/core/function/aes/aes_ssl_cbc.cpp deleted file mode 100644 index 3aa80ef5..00000000 --- a/src/core/function/aes/aes_ssl_cbc.cpp +++ /dev/null @@ -1,99 +0,0 @@ -/** - * AES encryption/decryption demo program using OpenSSL EVP apis - * gcc -Wall openssl_aes.c -lcrypto - * this is public domain code. - * Saju Pillai ([email protected]) - **/ - -#include "aes_ssl.h" - -namespace GpgFrontend::RawAPI { - -/** - * @brief Create a 256 bit key and IV using the supplied key_data. salt can be - * added for taste. Fills in the encryption and decryption ctx objects and - * returns 0 on success - * - * @param key_data - * @param key_data_len - * @param salt - * @param e_ctx - * @param d_ctx - * @return int - */ -int aes_256_cbc_init(uint8_t *key_data, int key_data_len, uint8_t *salt, - EVP_CIPHER_CTX *e_ctx, EVP_CIPHER_CTX *d_ctx) { - int i, nrounds = 5; - uint8_t key[32], iv[32]; - - /* - * Gen key & IV for AES 256 CBC mode. A SHA1 digest is used to hash the - * supplied key material. nrounds is the number of times the we hash the - * material. More rounds are more secure but slower. - */ - i = EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha1(), salt, key_data, - key_data_len, nrounds, key, iv); - if (i != 32) { - printf("Key size is %d bits - should be 256 bits\n", i); - return -1; - } - - EVP_CIPHER_CTX_init(e_ctx); - EVP_EncryptInit_ex(e_ctx, EVP_aes_256_cbc(), NULL, key, iv); - EVP_CIPHER_CTX_init(d_ctx); - EVP_DecryptInit_ex(d_ctx, EVP_aes_256_cbc(), NULL, key, iv); - - return 0; -} - -/** - * @brief Encrypt *len bytes of data All data going in & out is considered - * binary (uint8_t[]) - * - * @param e - * @param plaintext - * @param len - * @return uint8_t* - */ -uint8_t *aes_256_cbc_encrypt(EVP_CIPHER_CTX *e, uint8_t *plaintext, int *len) { - /* max ciphertext len for a n bytes of plaintext is n + AES_BLOCK_SIZE -1 - * bytes */ - int c_len = *len + AES_BLOCK_SIZE, f_len = 0; - auto *ciphertext = static_cast<uint8_t *>(malloc(c_len)); - - /* allows reusing of 'e' for multiple encryption cycles */ - EVP_EncryptInit_ex(e, nullptr, nullptr, nullptr, nullptr); - - /* update ciphertext, c_len is filled with the length of ciphertext generated, - *len is the size of plaintext in bytes */ - EVP_EncryptUpdate(e, ciphertext, &c_len, plaintext, *len); - - /* update ciphertext with the final remaining bytes */ - EVP_EncryptFinal_ex(e, ciphertext + c_len, &f_len); - - *len = c_len + f_len; - return ciphertext; -} - -/** - * @brief Decrypt *len bytes of ciphertext - * - * @param e - * @param ciphertext - * @param len - * @return uint8_t* - */ -uint8_t *aes_256_cbc_decrypt(EVP_CIPHER_CTX *e, uint8_t *ciphertext, int *len) { - /* plaintext will always be equal to or lesser than length of ciphertext*/ - int p_len = *len, f_len = 0; - auto *plaintext = static_cast<uint8_t *>(malloc(p_len)); - - EVP_DecryptInit_ex(e, nullptr, nullptr, nullptr, nullptr); - EVP_DecryptUpdate(e, plaintext, &p_len, ciphertext, *len); - EVP_DecryptFinal_ex(e, plaintext + p_len, &f_len); - - *len = p_len + f_len; - return plaintext; -} - -} // namespace GpgFrontend::RawAPI
\ No newline at end of file diff --git a/src/core/function/aes/aes_ssl.h b/src/core/function/basic/ChannelObject.cpp index e75b68dd..18449ddb 100644 --- a/src/core/function/aes/aes_ssl.h +++ b/src/core/function/basic/ChannelObject.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,55 +20,40 @@ * 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 +#include "ChannelObject.h" -#include <openssl/aes.h> -#include <openssl/evp.h> +#include <iostream> -#include "GpgFrontend.h" +namespace GpgFrontend { -namespace GpgFrontend::RawAPI { +ChannelObject::ChannelObject() noexcept = default; -/** - * @brief - * - * @param key_data - * @param key_data_len - * @param salt - * @param e_ctx - * @param d_ctx - * @return int - */ -int aes_256_cbc_init(uint8_t *key_data, int key_data_len, uint8_t *salt, - EVP_CIPHER_CTX *e_ctx, EVP_CIPHER_CTX *d_ctx); +ChannelObject::ChannelObject(int channel, QString type) + : channel_(channel), type_(std::move(type)) {} -/** - * @brief - * - * @param e - * @param plaintext - * @param len - * @return uint8_t* - */ -uint8_t *aes_256_cbc_encrypt(EVP_CIPHER_CTX *e, uint8_t *plaintext, int *len); +#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 -/** - * @brief - * - * @param e - * @param ciphertext - * @param len - * @return uint8_t* - */ -uint8_t *aes_256_cbc_decrypt(EVP_CIPHER_CTX *e, uint8_t *ciphertext, int *len); +void ChannelObject::SetChannel(int channel) { this->channel_ = channel; } + +auto ChannelObject::GetChannel() const -> int { return channel_; } -} // namespace GpgFrontend::RawAPI +auto ChannelObject::GetDefaultChannel() -> int { + return kGpgFrontendDefaultChannel; +} -#endif // GPGFRONTEND_AES_SSL_H +} // 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 |