diff options
author | saturneric <[email protected]> | 2023-12-28 06:32:49 +0000 |
---|---|---|
committer | saturneric <[email protected]> | 2023-12-28 06:32:49 +0000 |
commit | 300e55bf5bddc393de050c2ca9a0356fce9a8a9d (patch) | |
tree | 8332e6b50158718ad98c954302951668a57712a8 | |
parent | feat: avoid reading entire file to memory (diff) | |
download | GpgFrontend-300e55bf5bddc393de050c2ca9a0356fce9a8a9d.tar.gz GpgFrontend-300e55bf5bddc393de050c2ca9a0356fce9a8a9d.zip |
feat: add simple archiving functions for encrypt and decrypt
-rw-r--r-- | src/core/function/ArchiveFileOperator.cpp | 310 | ||||
-rw-r--r-- | src/core/function/ArchiveFileOperator.h | 12 | ||||
-rw-r--r-- | src/core/function/gpg/GpgFileOpera.cpp | 91 | ||||
-rw-r--r-- | src/core/function/gpg/GpgFileOpera.h | 24 | ||||
-rw-r--r-- | src/core/thread/TaskRunner.cpp | 8 | ||||
-rw-r--r-- | src/core/typedef/CoreTypedef.h | 7 | ||||
-rw-r--r-- | src/core/typedef/GpgTypedef.h | 10 | ||||
-rw-r--r-- | src/core/utils/AsyncUtils.cpp | 21 | ||||
-rw-r--r-- | src/core/utils/AsyncUtils.h | 20 | ||||
-rw-r--r-- | src/core/utils/GpgUtils.cpp | 63 | ||||
-rw-r--r-- | src/core/utils/GpgUtils.h | 24 | ||||
-rw-r--r-- | src/core/utils/IOUtils.cpp | 38 | ||||
-rw-r--r-- | src/core/utils/IOUtils.h | 20 | ||||
-rw-r--r-- | src/ui/function/ArchiveDirectory.cpp | 85 | ||||
-rw-r--r-- | src/ui/function/ArchiveDirectory.h | 53 | ||||
-rw-r--r-- | src/ui/main_window/MainWindow.h | 21 | ||||
-rw-r--r-- | src/ui/main_window/MainWindowFileSlotFunction.cpp | 435 | ||||
-rw-r--r-- | src/ui/main_window/MainWindowSlotFunction.cpp | 11 | ||||
-rw-r--r-- | src/ui/main_window/MainWindowUI.cpp | 43 |
19 files changed, 816 insertions, 480 deletions
diff --git a/src/core/function/ArchiveFileOperator.cpp b/src/core/function/ArchiveFileOperator.cpp index 18920e75..c8cd99f4 100644 --- a/src/core/function/ArchiveFileOperator.cpp +++ b/src/core/function/ArchiveFileOperator.cpp @@ -31,6 +31,12 @@ #include <archive.h> #include <archive_entry.h> +#include <fstream> + +#include "core/utils/AsyncUtils.h" + +namespace GpgFrontend { + struct ArchiveStruct { struct archive *archive; struct archive_entry *entry; @@ -39,7 +45,7 @@ struct ArchiveStruct { std::string name; }; -auto copy_data(struct archive *ar, struct archive *aw) -> int { +auto CopyData(struct archive *ar, struct archive *aw) -> int { int r; const void *buff; size_t size; @@ -62,216 +68,132 @@ auto copy_data(struct archive *ar, struct archive *aw) -> int { } } -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; - - 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"); - } - - 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 - ReadFile(QString::fromStdWString(archive_entry_sourcepath_w(entry)), - buff); -#else - 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); - - QDir::setCurrent(current_base_path_backup); +void ArchiveFileOperator::NewArchive2Fd( + const std::filesystem::path &target_directory, int fd, + const OperationCallback &cb) { + RunIOOperaAsync( + [=](const DataObjectPtr &data_object) -> GFError { + struct archive *archive; + struct archive_entry *entry; + std::array<char, 8192> buff{}; + + archive = archive_write_new(); + archive_write_add_filter_none(archive); + archive_write_set_format_pax_restricted(archive); + archive_write_open_fd(archive, fd); + + for (const auto &file : + std::filesystem::recursive_directory_iterator(target_directory)) { + entry = archive_entry_new(); + + auto file_path = file.path().string(); + archive_entry_set_pathname(entry, file_path.c_str()); + archive_entry_set_filetype(entry, AE_IFREG); + archive_entry_set_perm(entry, 0644); + + std::ifstream target_file(file_path, std::ifstream::binary); + if (!target_file) { + SPDLOG_ERROR("cannot open file: {}, abort...", file_path); + archive_entry_free(entry); + continue; + } + + target_file.seekg(0, std::ios::end); + auto file_size = target_file.tellg(); + target_file.seekg(0, std::ios::beg); + archive_entry_set_size(entry, file_size); + + archive_write_header(archive, entry); + + while (!target_file.eof()) { + target_file.read(buff.data(), buff.size()); + std::streamsize const bytes_read = target_file.gcount(); + archive_write_data(archive, buff.data(), bytes_read); + } + + archive_entry_free(entry); + } + + archive_write_close(archive); + archive_write_free(archive); + close(fd); + return 0; + }, + cb, "archive_write_new"); } -void GpgFrontend::ArchiveFileOperator::ExtractArchive( - const std::filesystem::path &archive_path, - const std::filesystem::path &base_path) { - SPDLOG_DEBUG("ExtractArchive: {}", archive_path.u8string()); +void ArchiveFileOperator::ExtractArchiveFromFd( + int fd, const std::filesystem::path &target_path, + const OperationCallback &cb) { + SPDLOG_DEBUG("extract archive from fd start, cuurent thread: {}", + QThread::currentThread()->currentThreadId()); + RunIOOperaAsync( + [=](const DataObjectPtr &data_object) -> GFError { + SPDLOG_DEBUG("extract archive from fd processing, cuurent thread: {}", + QThread::currentThread()->currentThreadId()); + struct archive *archive; + struct archive *ext; + struct archive_entry *entry; + + archive = archive_read_new(); + ext = archive_write_disk_new(); + archive_write_disk_set_options(ext, 0); - auto current_base_path_backup = QDir::currentPath(); - QDir::setCurrent(base_path.u8string().c_str()); - - struct archive *a; - struct archive *ext; - struct archive_entry *entry; - - 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); + archive_read_support_filter_bzip2(archive); #endif #ifndef NO_GZIP_EXTRACT - archive_read_support_filter_gzip(a); + archive_read_support_filter_gzip(archive); #endif #ifndef NO_COMPRESS_EXTRACT - archive_read_support_filter_compress(a); + archive_read_support_filter_compress(archive); #endif #ifndef NO_TAR_EXTRACT - archive_read_support_format_tar(a); + archive_read_support_format_tar(archive); #endif #ifndef NO_CPIO_EXTRACT - archive_read_support_format_cpio(a); + archive_read_support_format_cpio(archive); #endif #ifndef NO_LOOKUP - archive_write_disk_set_standard_lookup(ext); + archive_write_disk_set_standard_lookup(ext); #endif - 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) { -#else - if (archive_read_open_filename(a, archive_path.u8string().c_str(), 10240) != - ARCHIVE_OK) { -#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); - - QDir::setCurrent(current_base_path_backup); + archive_read_open_fd(archive, fd, 8192); + SPDLOG_ERROR("archive_read_open_fd() failed: {}", + archive_error_string(archive)); + + while (archive_read_next_header(archive, &entry) == ARCHIVE_OK) { + SPDLOG_DEBUG("add file: {}, size: {}, bytes: {}, file type: {}", + archive_entry_pathname_utf8(entry), + archive_entry_size(entry), + archive_entry_filetype(entry)); + + auto file_path = + std::filesystem::path(archive_entry_pathname_utf8(entry)); + auto target_file_path = target_path / file_path; + archive_entry_set_pathname(entry, file_path.c_str()); + + auto r = archive_write_header(ext, entry); + if (r != ARCHIVE_OK) { + SPDLOG_ERROR("archive_write_header() failed: {}", + archive_error_string(ext)); + } + + r = CopyData(archive, ext); + if (r != ARCHIVE_OK) { + SPDLOG_ERROR("copy_data() failed: {}", archive_error_string(ext)); + } + } + + archive_read_free(archive); + archive_write_free(ext); + close(fd); + return 0; + }, + cb, "archive_read_new"); } -void GpgFrontend::ArchiveFileOperator::ListArchive( +void ArchiveFileOperator::ListArchive( const std::filesystem::path &archive_path) { struct archive *a; struct archive_entry *entry; @@ -291,3 +213,5 @@ void GpgFrontend::ArchiveFileOperator::ListArchive( 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 7cbe644c..86a3070d 100644 --- a/src/core/function/ArchiveFileOperator.h +++ b/src/core/function/ArchiveFileOperator.h @@ -29,6 +29,7 @@ #pragma once #include "core/GpgFrontendCore.h" +#include "core/typedef/CoreTypedef.h" #include "core/utils/IOUtils.h" namespace GpgFrontend { @@ -50,10 +51,8 @@ class GPGFRONTEND_CORE_EXPORT ArchiveFileOperator { * @param compress * @param files */ - static void CreateArchive(const std::filesystem::path &base_path, - const std::filesystem::path &archive_path, - int compress, - const std::vector<std::filesystem::path> &files); + static void NewArchive2Fd(const std::filesystem::path &target_directory, + int fd, const OperationCallback &cb); /** * @brief @@ -61,7 +60,8 @@ class GPGFRONTEND_CORE_EXPORT ArchiveFileOperator { * @param archive_path * @param base_path */ - static void ExtractArchive(const std::filesystem::path &archive_path, - const std::filesystem::path &base_path); + static void ExtractArchiveFromFd(int fd, + const std::filesystem::path &target_path, + const OperationCallback &cb); }; } // namespace GpgFrontend diff --git a/src/core/function/gpg/GpgFileOpera.cpp b/src/core/function/gpg/GpgFileOpera.cpp index 7c247b95..929c02ea 100644 --- a/src/core/function/gpg/GpgFileOpera.cpp +++ b/src/core/function/gpg/GpgFileOpera.cpp @@ -27,8 +27,9 @@ */ #include "GpgFileOpera.h" -#include <utility> +#include <unistd.h> +#include "core/function/ArchiveFileOperator.h" #include "core/function/gpg/GpgBasicOperator.h" #include "core/model/GFBuffer.h" #include "core/model/GpgData.h" @@ -43,20 +44,6 @@ namespace GpgFrontend { -auto PathPreCheck(const std::filesystem::path& path, bool read) - -> std::tuple<bool, std::string> { - QFileInfo const file_info(path); - QFileInfo const path_info(file_info.absolutePath()); - - if (!path_info.exists()) { - return {false, _("")}; - } - if (read ? !file_info.isReadable() : !path_info.isWritable()) { - return {false, _("")}; - } - return {true, _("")}; -} - GpgFileOpera::GpgFileOpera(int channel) : SingletonFunctionObject<GpgFileOpera>(channel) {} @@ -85,6 +72,44 @@ void GpgFileOpera::EncryptFile(std::vector<GpgKey> keys, cb, "gpgme_op_encrypt", "2.1.0"); } +void GpgFileOpera::EncryptDirectory(std::vector<GpgKey> keys, + const std::filesystem::path& in_path, + bool ascii, + const std::filesystem::path& out_path, + const GpgOperationCallback& cb) { + RunGpgOperaAsync( + [=](const DataObjectPtr& data_object) -> GpgError { + std::array<int, 2> pipe_fds; + if (pipe(pipe_fds.data()) != 0) { + SPDLOG_ERROR( + "cannot create pipe for directory archive and encryt process"); + return GPG_ERR_EPIPE; + } + + ArchiveFileOperator::NewArchive2Fd( + in_path, pipe_fds[1], [](GFError err, const DataObjectPtr&) { + SPDLOG_DEBUG("new archive 2 fd operation, err: {}", err); + }); + + 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(pipe_fds[0]); + 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"); +} + void GpgFileOpera::DecryptFile(const std::filesystem::path& in_path, const std::filesystem::path& out_path, const GpgOperationCallback& cb) { @@ -103,6 +128,42 @@ void GpgFileOpera::DecryptFile(const std::filesystem::path& in_path, cb, "gpgme_op_decrypt", "2.1.0"); } +void GpgFileOpera::DecryptArchive(const std::filesystem::path& in_path, + const std::filesystem::path& out_path, + const GpgOperationCallback& cb) { + SPDLOG_DEBUG("decrypt archive start, cuurent thread: {}", + QThread::currentThread()->currentThreadId()); + RunGpgOperaAsync( + [=](const DataObjectPtr& data_object) -> GpgError { + std::array<int, 2> pipe_fds; + if (pipe(pipe_fds.data()) != 0) { + SPDLOG_ERROR( + "cannot create pipe for directory archive and encryt process"); + return GPG_ERR_EPIPE; + } + + SPDLOG_DEBUG("decrypt archive processing, cuurent thread: {}", + QThread::currentThread()->currentThreadId()); + ArchiveFileOperator::ExtractArchiveFromFd( + pipe_fds[0], out_path, [](GFError err, const DataObjectPtr&) { + SPDLOG_DEBUG("extract archive from fd operation, err: {}", err); + }); + + GpgData data_in(in_path, true); + GpgData data_out(pipe_fds[1]); + + SPDLOG_DEBUG("start to decrypt archive: {}", in_path.string()); + auto err = CheckGpgError( + gpgme_op_decrypt(ctx_.DefaultContext(), data_in, data_out)); + SPDLOG_DEBUG("decryption of archive done: {}", in_path.string()); + + data_object->Swap( + {GpgDecryptResult(gpgme_op_decrypt_result(ctx_.DefaultContext()))}); + return err; + }, + cb, "gpgme_op_decrypt", "2.1.0"); +} + void GpgFileOpera::SignFile(KeyArgsList keys, const std::filesystem::path& in_path, bool ascii, const std::filesystem::path& out_path, diff --git a/src/core/function/gpg/GpgFileOpera.h b/src/core/function/gpg/GpgFileOpera.h index 73649d47..f0880dc1 100644 --- a/src/core/function/gpg/GpgFileOpera.h +++ b/src/core/function/gpg/GpgFileOpera.h @@ -66,6 +66,19 @@ class GPGFRONTEND_CORE_EXPORT GpgFileOpera const GpgOperationCallback& cb); /** + * @brief + * + * @param keys + * @param in_path + * @param ascii + * @param out_path + * @param cb + */ + void EncryptDirectory(KeyArgsList keys, const std::filesystem::path& in_path, + bool ascii, const std::filesystem::path& out_path, + const GpgOperationCallback& cb); + + /** * @brief Encrypted file symmetrically (with password) * * @param in_path @@ -91,6 +104,17 @@ class GPGFRONTEND_CORE_EXPORT GpgFileOpera const GpgOperationCallback& cb); /** + * @brief + * + * @param in_path + * @param out_path + * @param cb + */ + void DecryptArchive(const std::filesystem::path& in_path, + const std::filesystem::path& out_path, + const GpgOperationCallback& cb); + + /** * @brief Sign file with private key * * @param keys diff --git a/src/core/thread/TaskRunner.cpp b/src/core/thread/TaskRunner.cpp index a4a97b38..6d5edd93 100644 --- a/src/core/thread/TaskRunner.cpp +++ b/src/core/thread/TaskRunner.cpp @@ -39,10 +39,7 @@ namespace GpgFrontend::Thread { class TaskRunner::Impl : public QThread { public: - Impl() { - SPDLOG_TRACE("task runner created, thread id: {}", - QThread::currentThread()->currentThreadId()); - } + Impl() : QThread(nullptr) {} void PostTask(Task* task) { if (task == nullptr) { @@ -53,7 +50,8 @@ class TaskRunner::Impl : public QThread { task->setParent(nullptr); task->moveToThread(this); - SPDLOG_TRACE("runner starts task: {}", task->GetFullID()); + SPDLOG_TRACE("runner starts task: {} at thread: {}", task->GetFullID(), + this->currentThreadId()); task->SafelyRun(); } diff --git a/src/core/typedef/CoreTypedef.h b/src/core/typedef/CoreTypedef.h index ccb63bc7..41ff7b43 100644 --- a/src/core/typedef/CoreTypedef.h +++ b/src/core/typedef/CoreTypedef.h @@ -28,8 +28,11 @@ #pragma once +#include "core/model/DataObject.h" + namespace GpgFrontend { +using GFError = uint32_t; using ByteArray = std::string; ///< using ByteArrayPtr = std::shared_ptr<ByteArray>; ///< using StdBypeArrayPtr = std::shared_ptr<ByteArray>; ///< @@ -39,4 +42,8 @@ using BypeArrayConstRef = const ByteArray&; ///< using StringArgsPtr = std::unique_ptr<std::vector<std::string>>; ///< using StringArgsRef = std::vector<std::string>&; ///< /// + /// + +using OperaRunnable = std::function<GFError(DataObjectPtr)>; +using OperationCallback = std::function<void(GFError, DataObjectPtr)>; } // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/typedef/GpgTypedef.h b/src/core/typedef/GpgTypedef.h index ca901a34..7ef02827 100644 --- a/src/core/typedef/GpgTypedef.h +++ b/src/core/typedef/GpgTypedef.h @@ -31,6 +31,7 @@ #include <tuple> #include "core/model/DataObject.h" + namespace GpgFrontend { class GpgKey; ///< forward declaration @@ -63,4 +64,13 @@ using GpgSignMode = gpgme_sig_mode_t; using GpgOperaRunnable = std::function<GpgError(DataObjectPtr)>; using GpgOperationCallback = std::function<void(GpgError, DataObjectPtr)>; using GpgOperationFuture = std::future<std::tuple<GpgError, DataObjectPtr>>; + +enum GpgOperation { + kENCRYPT, + kDECRYPT, + kSIGN, + kVERIFY, + kENCRYPT_SIGN, + kDECRYPT_VERIFY +}; } // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/utils/AsyncUtils.cpp b/src/core/utils/AsyncUtils.cpp index 545c9ce3..4de7fa1e 100644 --- a/src/core/utils/AsyncUtils.cpp +++ b/src/core/utils/AsyncUtils.cpp @@ -67,4 +67,25 @@ void RunGpgOperaAsync(GpgOperaRunnable runnable, GpgOperationCallback callback, .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_GPG) ->PostTask(task); } + +void RunIOOperaAsync(OperaRunnable runnable, OperationCallback callback, + const std::string& operation) { + auto* task = new Thread::Task( + [=](const DataObjectPtr& data_object) -> int { + auto custom_data_object = TransferParams(); + GpgError err = runnable(custom_data_object); + + data_object->Swap({err, custom_data_object}); + return 0; + }, + operation, TransferParams(), + [=](int, const DataObjectPtr& data_object) { + callback(ExtractParams<GFError>(data_object, 0), + ExtractParams<DataObjectPtr>(data_object, 1)); + }); + + Thread::TaskRunnerGetter::GetInstance() + .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_IO) + ->PostTask(task); +} } // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/utils/AsyncUtils.h b/src/core/utils/AsyncUtils.h index bda15328..6d79d9c1 100644 --- a/src/core/utils/AsyncUtils.h +++ b/src/core/utils/AsyncUtils.h @@ -29,11 +29,31 @@ #pragma once #include "core/GpgFrontendCore.h" +#include "core/typedef/CoreTypedef.h" #include "core/typedef/GpgTypedef.h" namespace GpgFrontend { +/** + * @brief + * + * @param runnable + * @param callback + * @param operation + * @param minial_version + */ void GPGFRONTEND_CORE_EXPORT RunGpgOperaAsync( GpgOperaRunnable runnable, GpgOperationCallback callback, const std::string& operation, const std::string& minial_version); + +/** + * @brief + * + * @param runnable + * @param callback + * @param operation + */ +void GPGFRONTEND_CORE_EXPORT RunIOOperaAsync(OperaRunnable runnable, + OperationCallback callback, + const std::string& operation); } // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/utils/GpgUtils.cpp b/src/core/utils/GpgUtils.cpp index 886dc0fc..20a96e12 100644 --- a/src/core/utils/GpgUtils.cpp +++ b/src/core/utils/GpgUtils.cpp @@ -121,4 +121,67 @@ auto TextIsSigned(BypeArrayRef text) -> int { } return 0; } + +auto SetExtensionOfOutputFile(std::filesystem::path path, GpgOperation opera, + bool ascii) -> std::filesystem::path { + std::string extension; + + if (ascii) { + switch (opera) { + case kENCRYPT: + case kSIGN: + case kENCRYPT_SIGN: + extension += ".asc"; + break; + default: + break; + } + } else { + switch (opera) { + case kENCRYPT: + case kENCRYPT_SIGN: + extension += ".gpg"; + break; + case kSIGN: + extension = ".sig"; + break; + default: + break; + } + } + return path.replace_extension(extension); +} + +auto SetExtensionOfOutputFileForArchive(std::filesystem::path path, + GpgOperation opera, bool ascii) + -> std::filesystem::path { + std::string extension; + + if (ascii) { + switch (opera) { + case kENCRYPT: + case kENCRYPT_SIGN: + extension += ".tar.asc"; + return path.replace_extension(extension); + case kDECRYPT: + case kDECRYPT_VERIFY: + return path.parent_path(); + default: + break; + } + } else { + switch (opera) { + case kENCRYPT: + case kENCRYPT_SIGN: + extension += ".tar.gpg"; + return path.replace_extension(extension); + case kDECRYPT: + case kDECRYPT_VERIFY: + return path.parent_path(); + default: + break; + } + } +} + } // namespace GpgFrontend diff --git a/src/core/utils/GpgUtils.h b/src/core/utils/GpgUtils.h index 71fa712a..2165d614 100644 --- a/src/core/utils/GpgUtils.h +++ b/src/core/utils/GpgUtils.h @@ -84,4 +84,28 @@ auto GPGFRONTEND_CORE_EXPORT DescribeGpgErrCode(GpgError err) -> GpgErrorDesc; */ auto GPGFRONTEND_CORE_EXPORT TextIsSigned(BypeArrayRef text) -> int; +/** + * @brief + * + * @param opera + * @param ascii + * @return std::filesystem::path + */ +auto GPGFRONTEND_CORE_EXPORT SetExtensionOfOutputFile(std::filesystem::path, + GpgOperation opera, + bool ascii) + -> std::filesystem::path; + +/** + * @brief + * + * @param path + * @param opera + * @param ascii + * @return std::filesystem::path + */ +auto GPGFRONTEND_CORE_EXPORT SetExtensionOfOutputFileForArchive( + std::filesystem::path path, GpgOperation opera, bool ascii) + -> std::filesystem::path; + } // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/utils/IOUtils.cpp b/src/core/utils/IOUtils.cpp index d19b5581..23c37e7f 100644 --- a/src/core/utils/IOUtils.cpp +++ b/src/core/utils/IOUtils.cpp @@ -73,8 +73,8 @@ auto ReadFileStd(const std::filesystem::path& file_name, std::string& data) return res; } -auto GPGFRONTEND_CORE_EXPORT ReadFileGFBuffer( - const std::filesystem::path& file_name) -> std::tuple<bool, GFBuffer> { +auto ReadFileGFBuffer(const std::filesystem::path& file_name) + -> std::tuple<bool, GFBuffer> { QByteArray byte_data; #ifdef WINDOWS const bool res = ReadFile( @@ -93,8 +93,8 @@ auto WriteFileStd(const std::filesystem::path& file_name, QByteArray::fromStdString(data)); } -auto GPGFRONTEND_CORE_EXPORT WriteFileGFBuffer( - const std::filesystem::path& file_name, GFBuffer data) -> bool { +auto WriteFileGFBuffer(const std::filesystem::path& file_name, GFBuffer data) + -> bool { return WriteFile( QString::fromStdString(file_name.u8string()).toUtf8(), QByteArray::fromRawData(reinterpret_cast<const char*>(data.Data()), @@ -197,4 +197,34 @@ auto CreateTempFileAndWriteData(const std::string& data) file_stream.close(); return temp_file.string(); } + +auto TargetFilePreCheck(const std::filesystem::path& path, bool read) + -> std::tuple<bool, std::string> { + QFileInfo const file_info(path); + + if (read) { + if (!file_info.exists()) { + return {false, _("target path doesn't exists")}; + } + } else { + QFileInfo const path_info(file_info.absolutePath()); + if (!path_info.isWritable()) { + return {false, _("do NOT have permission to write path")}; + } + } + + if (read ? !file_info.isReadable() : false) { + return {false, _("do NOT have permission to read/write file")}; + } + + return {true, _("")}; +} + +auto GetFullExtension(std::filesystem::path path) -> std::string { + const auto filename = path.filename().string(); + std::string extension(std::find(filename.begin(), filename.end(), '.'), + filename.end()); + return extension; +} + } // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/utils/IOUtils.h b/src/core/utils/IOUtils.h index b27f21fb..40e6923d 100644 --- a/src/core/utils/IOUtils.h +++ b/src/core/utils/IOUtils.h @@ -157,4 +157,24 @@ auto GPGFRONTEND_CORE_EXPORT GetTempFilePath() -> std::filesystem::path; auto GPGFRONTEND_CORE_EXPORT CreateTempFileAndWriteData(const std::string &data) -> std::filesystem::path; +/** + * @brief + * + * @param path + * @param read + * @return std::tuple<bool, std::string> + */ +auto GPGFRONTEND_CORE_EXPORT +TargetFilePreCheck(const std::filesystem::path &path, bool read) + -> std::tuple<bool, std::string>; + +/** + * @brief + * + * @param path + * @return std::string + */ +auto GPGFRONTEND_CORE_EXPORT GetFullExtension(std::filesystem::path path) + -> std::string; + } // namespace GpgFrontend diff --git a/src/ui/function/ArchiveDirectory.cpp b/src/ui/function/ArchiveDirectory.cpp new file mode 100644 index 00000000..9cbfc41e --- /dev/null +++ b/src/ui/function/ArchiveDirectory.cpp @@ -0,0 +1,85 @@ +/** + * 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 "ArchiveDirectory.h" + +#include "core/function/ArchiveFileOperator.h" + +namespace GpgFrontend::UI { + +auto PathPreCheck(QWidget* parent, const std::filesystem::path& path) -> bool { + QFileInfo const file_info(path); + QFileInfo const path_info(file_info.absolutePath()); + + if (!path_info.exists()) { + QMessageBox::critical( + parent, _("Error"), + QString(_("The path %1 does not exist.")).arg(path.c_str())); + return false; + } + + if (!path_info.isDir()) { + QMessageBox::critical( + parent, _("Error"), + QString(_("The path %1 is not a directory.")).arg(path.c_str())); + return false; + } + + if (!file_info.isReadable()) { + QMessageBox::critical(parent, _("Error"), + _("No permission to read this file.")); + return false; + } + return true; +} + +ArchiveDirectory::ArchiveDirectory(QWidget* parent) : QWidget(parent) {} + +auto ArchiveDirectory::Exec(const std::filesystem::path& target_directory) + -> std::tuple<bool, GFBuffer> { + if (!PathPreCheck(this, target_directory)) { + return {false, {}}; + } + + try { + auto base_path = target_directory.parent_path(); + auto target_path = target_directory; + target_path = target_path.replace_extension(""); + + SPDLOG_DEBUG("archive directory, base path: {}, target path: {}", + base_path.string(), target_path.string()); + + // ArchiveFileOperator::CreateArchive(base_path, target_path, 0, ); + + } catch (...) { + SPDLOG_ERROR("archive caught exception error"); + return {false, {}}; + } +} + +} // namespace GpgFrontend::UI
\ No newline at end of file diff --git a/src/ui/function/ArchiveDirectory.h b/src/ui/function/ArchiveDirectory.h new file mode 100644 index 00000000..8b21c7e1 --- /dev/null +++ b/src/ui/function/ArchiveDirectory.h @@ -0,0 +1,53 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +#include "core/model/GFBuffer.h" +#include "ui/GpgFrontendUI.h" + +namespace GpgFrontend::UI { +class ArchiveDirectory : public QWidget { + Q_OBJECT + public: + /** + * @brief Construct a new Raise Pinentry object + * + * @param parent + */ + explicit ArchiveDirectory(QWidget* parent); + + /** + * @brief + * + * @return int + */ + auto Exec(const std::filesystem::path& target_directory) + -> std::tuple<bool, GFBuffer>; +}; +} // namespace GpgFrontend::UI
\ No newline at end of file diff --git a/src/ui/main_window/MainWindow.h b/src/ui/main_window/MainWindow.h index 81975579..eb21937e 100644 --- a/src/ui/main_window/MainWindow.h +++ b/src/ui/main_window/MainWindow.h @@ -119,12 +119,25 @@ class MainWindow : public GeneralMainWindow { /** * @details Open dialog for encrypting file. */ - void SlotFileEncrypt(); + void SlotFileEncrypt(std::filesystem::path); + + /** + * @brief + * + */ + void SlotDirectoryEncrypt(std::filesystem::path); /** * @details Open dialog for decrypting file. */ - void SlotFileDecrypt(); + void SlotFileDecrypt(std::filesystem::path path); + + /** + * @brief + * + * @param path + */ + void SlotArchiveDecrypt(std::filesystem::path path); /** * @details Open dialog for signing file. @@ -163,7 +176,7 @@ class MainWindow : public GeneralMainWindow { * @details encrypt the text of currently active textedit-page * with the currently checked keys */ - void slot_encrypt(); + void SlotEncrypt(); /** * @details encrypt and sign the text of currently active textedit-page @@ -175,7 +188,7 @@ class MainWindow : public GeneralMainWindow { * @details Show a passphrase dialog and decrypt the text of currently active * tab. */ - void slot_decrypt(); + void SlotDecrypt(); /** * @details Sign the text of currently active tab with the checked private diff --git a/src/ui/main_window/MainWindowFileSlotFunction.cpp b/src/ui/main_window/MainWindowFileSlotFunction.cpp index c4d8370a..e3d2957c 100644 --- a/src/ui/main_window/MainWindowFileSlotFunction.cpp +++ b/src/ui/main_window/MainWindowFileSlotFunction.cpp @@ -38,147 +38,31 @@ #include "core/function/result_analyse/GpgSignResultAnalyse.h" #include "core/function/result_analyse/GpgVerifyResultAnalyse.h" #include "core/thread/Task.h" +#include "core/utils/GpgUtils.h" #include "ui/UserInterfaceUtils.h" #include "ui/dialog/SignersPicker.h" namespace GpgFrontend::UI { -auto PathPreCheck(QWidget* parent, const std::filesystem::path& path) -> bool { - QFileInfo const file_info(path); - QFileInfo const path_info(file_info.absolutePath()); - - if (!path_info.exists()) { - QMessageBox::critical( - parent, _("Error"), - QString(_("The path %1 does not exist.")).arg(path.c_str())); - return false; - } - if (!file_info.isReadable()) { - QMessageBox::critical(parent, _("Error"), - _("No permission to read this file.")); - return false; - } - if (!path_info.isWritable()) { - QMessageBox::critical(parent, _("Error"), - _("No permission to create file.")); - return false; - } - return true; -} - -/** - * @brief convert directory into tarball - * - * @param parent parent widget - * @param path the directory to be converted - * @return - */ -auto ProcessTarballIntoDirectory(QWidget* parent, - const std::filesystem::path& path) - -> std::tuple<bool, std::filesystem::path> { - SPDLOG_DEBUG("converting directory into tarball: {}", path.u8string()); - auto selected_dir_path = std::filesystem::path(path); - - if (selected_dir_path.extension() != ".tar") { - QMessageBox::critical(parent, _("Error"), _("The file is not a tarball.")); - return {false, path}; - } - - try { - auto base_path = selected_dir_path.parent_path(); - - auto target_path = selected_dir_path; - target_path.replace_extension(".tar"); - - SPDLOG_DEBUG("base path: {} target archive path: {]", base_path.u8string(), - target_path.u8string()); - - bool if_error = false; - process_operation(parent, _("Extracting Tarball"), - [&](DataObjectPtr) -> int { - try { - GpgFrontend::ArchiveFileOperator::ExtractArchive( - target_path, base_path); - } catch (const std::runtime_error& e) { - if_error = true; - } - return 0; - }); - - if (if_error || !exists(target_path)) { - throw std::runtime_error("Decompress Failed"); - } - return {true, target_path.string()}; - } catch (...) { - SPDLOG_ERROR("decompress error"); - return {false, path}; - } -} - -/** - * @brief convert tarball into directory - * - * @param parent parent widget - * @param path the tarball to be converted - */ -auto ProcessDirectoryIntoTarball(QWidget* parent, std::filesystem::path path) - -> std::tuple<bool, std::filesystem::path> { - try { - auto base_path = path.parent_path(); - auto target_path = path; - target_path = target_path.replace_extension(""); - - SPDLOG_DEBUG("base path: {} target archive path: {} selected_dir_path: {}", - base_path.u8string(), target_path.u8string(), path.u8string()); - - bool if_error = false; - process_operation(parent, _("Making Tarball"), [&](DataObjectPtr) -> int { - try { - // GpgFrontend::ArchiveFileOperator::CreateArchive(base_path, - // target_path, - // 0, {path}); - } catch (const std::runtime_error& e) { - if_error = true; - } - return 0; - }); - - if (!exists(target_path)) { - return {false, ""}; - } - - return {if_error, target_path.replace_extension(".tar")}; - } catch (...) { - SPDLOG_ERROR("compress caught exception error"); - return {false, ""}; - } -} - -void MainWindow::SlotFileEncrypt() { +void MainWindow::SlotFileEncrypt(std::filesystem::path path) { auto* file_tree_view = edit_->SlotCurPageFileTreeView(); - auto path_qstr = file_tree_view->GetSelected(); - - auto path = ConvertPathByOS(path_qstr); - if (!PathPreCheck(this, path)) { - SPDLOG_ERROR("path pre check failed"); + auto check_result = TargetFilePreCheck(path, true); + if (!std::get<0>(check_result)) { + QMessageBox::critical( + this, _("Error"), + QString(_("Cannot read from file: %1")).arg(path.filename().c_str())); return; } // check selected keys auto key_ids = m_key_list_->GetChecked(); + bool const non_ascii_when_export = GlobalSettingStation::GetInstance().LookupSettings( "general.non_ascii_when_export", true); + auto out_path = + SetExtensionOfOutputFile(path, kENCRYPT, !non_ascii_when_export); - // get file info - QFileInfo const file_info(path); - const auto* extension = ".asc"; - if (non_ascii_when_export || file_info.isDir()) { - extension = ".gpg"; - } - - auto out_path = path; - out_path = out_path.replace_extension(path.extension().string() + extension); if (QFile::exists(out_path)) { auto out_file_name = boost::format(_("The target file %1% already exists, " "do you need to overwrite it?")) % @@ -190,6 +74,14 @@ void MainWindow::SlotFileEncrypt() { if (ret == QMessageBox::Cancel) return; } + check_result = TargetFilePreCheck(out_path, false); + if (!std::get<0>(check_result)) { + QMessageBox::critical(this, _("Error"), + QString(_("Cannot write to file: %1")) + .arg(out_path.filename().c_str())); + return; + } + if (key_ids->empty()) { // Symmetric Encrypt auto ret = QMessageBox::information( @@ -199,19 +91,6 @@ void MainWindow::SlotFileEncrypt() { QMessageBox::Ok | QMessageBox::Cancel); if (ret == QMessageBox::Cancel) return; - if (file_info.isDir()) { - // stop if the process making tarball failed - const auto [success, target_path] = - ProcessDirectoryIntoTarball(this, path); - if (!success) { - QMessageBox::critical(this, _("Error"), - _("Unable to convert the folder into tarball.")); - return; - } - // reset target - path = target_path; - } - CommonUtils::WaitForOpera( this, _("Symmetrically Encrypting"), [=](const OperaWaitingHd& op_hd) { GpgFileOpera::GetInstance().EncryptFileSymmetric( @@ -231,16 +110,6 @@ void MainWindow::SlotFileEncrypt() { process_result_analyse(edit_, info_board_, result_analyse); file_tree_view->update(); - - // remove xxx.tar and only left xxx.tar.gpg - if (file_info.isDir()) { - auto selected_dir_path = path; - auto target_path = - selected_dir_path.replace_extension(".tar"); - if (exists(target_path)) { - std::filesystem::remove(target_path); - } - } }); }); @@ -281,32 +150,101 @@ void MainWindow::SlotFileEncrypt() { process_result_analyse(edit_, info_board_, result_analyse); file_tree_view->update(); + }); + }); +} - // remove xxx.tar and only left xxx.tar.gpg - if (file_info.isDir()) { - auto selected_dir_path = path; - auto target_path = selected_dir_path.replace_extension(".tar"); - if (exists(target_path)) { - std::filesystem::remove(target_path); - } +void MainWindow::SlotDirectoryEncrypt(std::filesystem::path path) { + auto* file_tree_view = edit_->SlotCurPageFileTreeView(); + auto check_result = TargetFilePreCheck(path, true); + if (!std::get<0>(check_result)) { + QMessageBox::critical( + this, _("Error"), + QString(_("Cannot read from file: %1")).arg(path.filename().c_str())); + return; + } + + // check selected keys + auto key_ids = m_key_list_->GetChecked(); + bool const non_ascii_when_export = + GlobalSettingStation::GetInstance().LookupSettings( + "general.non_ascii_when_export", true); + auto out_path = SetExtensionOfOutputFileForArchive(path, kENCRYPT, + !non_ascii_when_export); + + if (QFile::exists(out_path)) { + auto out_file_name = boost::format(_("The target file %1% already exists, " + "do you need to overwrite it?")) % + out_path.filename(); + auto ret = + QMessageBox::warning(this, _("Warning"), out_file_name.str().c_str(), + QMessageBox::Ok | QMessageBox::Cancel); + + if (ret == QMessageBox::Cancel) return; + } + + check_result = TargetFilePreCheck(out_path, false); + if (!std::get<0>(check_result)) { + QMessageBox::critical(this, _("Error"), + QString(_("Cannot write to file: %1")) + .arg(out_path.filename().c_str())); + return; + } + + if (key_ids->empty()) { + // TODO + return; + } + + auto p_keys = GpgKeyGetter::GetInstance().GetKeys(key_ids); + + // check key abilities + for (const auto& key : *p_keys) { + bool const key_can_encrypt = key.IsHasActualEncryptionCapability(); + + if (!key_can_encrypt) { + QMessageBox::critical( + nullptr, _("Invalid KeyPair"), + QString(_("The selected keypair cannot be used for encryption.")) + + "<br/><br/>" + _("For example the Following Key:") + " <br/>" + + QString::fromStdString(key.GetUIDs()->front().GetUID())); + return; + } + } + + CommonUtils::WaitForOpera( + this, _("Archiving & Encrypting"), [=](const OperaWaitingHd& op_hd) { + GpgFileOpera::GetInstance().EncryptDirectory( + {p_keys->begin(), p_keys->end()}, path, !non_ascii_when_export, + out_path, [=](GpgError err, const DataObjectPtr& data_obj) { + // stop waiting + op_hd(); + + if (data_obj == nullptr || !data_obj->Check<GpgEncryptResult>()) { + throw std::runtime_error("data object doesn't pass checking"); } + + auto result = ExtractParams<GpgEncryptResult>(data_obj, 0); + auto result_analyse = GpgEncryptResultAnalyse(err, result); + result_analyse.Analyse(); + + process_result_analyse(edit_, info_board_, result_analyse); + file_tree_view->update(); }); }); } -void MainWindow::SlotFileDecrypt() { +void MainWindow::SlotFileDecrypt(std::filesystem::path path) { auto* file_tree_view = edit_->SlotCurPageFileTreeView(); - auto path_qstr = file_tree_view->GetSelected(); - auto path = ConvertPathByOS(path_qstr); - if (!PathPreCheck(this, path)) return; - - auto out_path = path; - if (out_path.extension() == ".asc" || out_path.extension() == ".gpg") { - out_path = out_path.parent_path() / out_path.stem(); - } else { - out_path += ".out"; + auto check_result = TargetFilePreCheck(path, true); + if (!std::get<0>(check_result)) { + QMessageBox::critical( + this, _("Error"), + QString(_("Cannot read from file: %1")).arg(path.filename().c_str())); + return; } + auto out_path = SetExtensionOfOutputFile(path, kDECRYPT, true); if (exists(out_path)) { auto ret = QMessageBox::warning( this, _("Warning"), @@ -316,6 +254,14 @@ void MainWindow::SlotFileDecrypt() { if (ret == QMessageBox::Cancel) return; } + check_result = TargetFilePreCheck(out_path, false); + if (!std::get<0>(check_result)) { + QMessageBox::critical(this, _("Error"), + QString(_("Cannot write to file: %1")) + .arg(out_path.filename().c_str())); + return; + } + CommonUtils::WaitForOpera( this, _("Decrypting"), [=](const OperaWaitingHd& op_hd) { GpgFileOpera::GetInstance().DecryptFile( @@ -334,30 +280,56 @@ void MainWindow::SlotFileDecrypt() { process_result_analyse(edit_, info_board_, result_analyse); file_tree_view->update(); + }); + }); +} - // extract the tarball - if (out_path.extension() == ".tar" && exists(out_path)) { - bool const ret = - QMessageBox::information( - this, _("Decrypting"), - _("Do you want to extract and delete the decrypted " - "tarball?"), - QMessageBox::Ok | QMessageBox::Cancel) != 0; - if (ret) { - auto archieve_result = - ProcessTarballIntoDirectory(this, out_path); - if (std::get<0>(archieve_result)) { - QMessageBox::information( - this, _("Decrypting"), - _("Extracting tarball succeeded.")); - // remove tarball - std::filesystem::remove(out_path); - } else { - QMessageBox::critical(this, _("Decrypting"), - _("Extracting tarball failed.")); - } - } +void MainWindow::SlotArchiveDecrypt(std::filesystem::path path) { + auto* file_tree_view = edit_->SlotCurPageFileTreeView(); + auto check_result = TargetFilePreCheck(path, true); + if (!std::get<0>(check_result)) { + QMessageBox::critical( + this, _("Error"), + QString(_("Cannot read from file: %1")).arg(path.filename().c_str())); + return; + } + + auto out_path = SetExtensionOfOutputFileForArchive(path, kDECRYPT, true); + if (exists(out_path)) { + auto ret = QMessageBox::warning( + this, _("Warning"), + _("The target file already exists, do you need to overwrite it?"), + QMessageBox::Ok | QMessageBox::Cancel); + + if (ret == QMessageBox::Cancel) return; + } + + check_result = TargetFilePreCheck(out_path, false); + if (!std::get<0>(check_result)) { + QMessageBox::critical(this, _("Error"), + QString(_("Cannot write to file: %1")) + .arg(out_path.filename().c_str())); + return; + } + + CommonUtils::WaitForOpera( + this, _("Decrypting & Extrating"), [=](const OperaWaitingHd& op_hd) { + GpgFileOpera::GetInstance().DecryptArchive( + path, out_path, [=](GpgError err, const DataObjectPtr& data_obj) { + // stop waiting + op_hd(); + + if (data_obj == nullptr || !data_obj->Check<GpgDecryptResult>()) { + throw std::runtime_error("data object doesn't pass checking"); } + + auto result = ExtractParams<GpgDecryptResult>(data_obj, 0); + + auto result_analyse = GpgDecryptResultAnalyse(err, result); + result_analyse.Analyse(); + + process_result_analyse(edit_, info_board_, result_analyse); + file_tree_view->update(); }); }); } @@ -366,7 +338,13 @@ void MainWindow::SlotFileSign() { auto* file_tree_view = edit_->SlotCurPageFileTreeView(); auto path_qstr = file_tree_view->GetSelected(); auto path = ConvertPathByOS(path_qstr); - if (!PathPreCheck(this, path)) return; + auto check_result = TargetFilePreCheck(path, true); + if (!std::get<0>(check_result)) { + QMessageBox::critical( + this, _("Error"), + QString(_("Cannot read from file: %1")).arg(path.filename().c_str())); + return; + } auto key_ids = m_key_list_->GetChecked(); auto keys = GpgKeyGetter::GetInstance().GetKeys(key_ids); @@ -393,14 +371,9 @@ void MainWindow::SlotFileSign() { bool const non_ascii_when_export = GlobalSettingStation::GetInstance().LookupSettings( "general.non_ascii_when_export", true); + auto sig_file_path = + SetExtensionOfOutputFile(path, kSIGN, !non_ascii_when_export); - const auto* extension = ".asc"; - if (non_ascii_when_export) { - extension = ".sig"; - } - - auto sig_file_path = path; - sig_file_path += extension; if (exists(sig_file_path)) { auto ret = QMessageBox::warning( this, _("Warning"), @@ -438,7 +411,13 @@ void MainWindow::SlotFileVerify() { auto* file_tree_view = edit_->SlotCurPageFileTreeView(); auto path_qstr = file_tree_view->GetSelected(); auto path = ConvertPathByOS(path_qstr); - if (!PathPreCheck(this, path)) return; + auto check_result = TargetFilePreCheck(path, true); + if (!std::get<0>(check_result)) { + QMessageBox::critical( + this, _("Error"), + QString(_("Cannot read from file: %1")).arg(path.filename().c_str())); + return; + } std::filesystem::path sign_file_path = path; std::filesystem::path data_file_path; @@ -509,7 +488,13 @@ void MainWindow::SlotFileEncryptSign() { auto* file_tree_view = edit_->SlotCurPageFileTreeView(); auto path_qstr = file_tree_view->GetSelected(); auto path = ConvertPathByOS(path_qstr); - if (!PathPreCheck(this, path)) return; + auto check_result = TargetFilePreCheck(path, true); + if (!std::get<0>(check_result)) { + QMessageBox::critical( + this, _("Error"), + QString(_("Cannot read from file: %1")).arg(path.filename().c_str())); + return; + } // check selected keys auto key_ids = m_key_list_->GetChecked(); @@ -573,19 +558,6 @@ void MainWindow::SlotFileEncryptSign() { auto signer_key_ids = signers_picker->GetCheckedSigners(); auto p_signer_keys = GpgKeyGetter::GetInstance().GetKeys(signer_key_ids); - // convert directory into tarball - if (file_info.isDir()) { - // stop if the process making tarball failed - const auto [success, target_path] = ProcessDirectoryIntoTarball(this, path); - if (!success) { - QMessageBox::critical(this, _("Error"), - _("Unable to convert the folder into tarball.")); - return; - } - // reset target - path = target_path; - } - CommonUtils::WaitForOpera( this, _("Encrypting and Signing"), [=](const OperaWaitingHd& op_hd) { GpgFileOpera::GetInstance().EncryptSignFile( @@ -615,15 +587,6 @@ void MainWindow::SlotFileEncryptSign() { sign_result_analyse); file_tree_view->update(); - - // remove xxx.tar and only left xxx.tar.gpg - if (file_info.isDir()) { - auto selected_dir_path = path; - auto target_path = selected_dir_path.replace_extension(".tar"); - if (exists(target_path)) { - std::filesystem::remove(target_path); - } - } }); }); } @@ -632,7 +595,13 @@ void MainWindow::SlotFileDecryptVerify() { auto* file_tree_view = edit_->SlotCurPageFileTreeView(); auto path_qstr = file_tree_view->GetSelected(); auto path = ConvertPathByOS(path_qstr); - if (!PathPreCheck(this, path)) return; + auto check_result = TargetFilePreCheck(path, true); + if (!std::get<0>(check_result)) { + QMessageBox::critical( + this, _("Error"), + QString(_("Cannot read from file: %1")).arg(path.filename().c_str())); + return; + } std::filesystem::path out_path = path; if (path.extension() == ".asc" || path.extension() == ".gpg") { @@ -685,30 +654,6 @@ void MainWindow::SlotFileDecryptVerify() { show_verify_details(this, info_board_, err, verify_result); } file_tree_view->update(); - - // extract the tarball - if (out_path.extension() == ".tar" && exists(out_path)) { - bool const ret = - QMessageBox::information( - this, _("Decrypting"), - _("Do you want to extract and delete the decrypted " - "tarball?"), - QMessageBox::Ok | QMessageBox::Cancel) != 0; - if (ret) { - auto archieve_result = - ProcessTarballIntoDirectory(this, out_path); - if (std::get<0>(archieve_result)) { - QMessageBox::information( - this, _("Decrypting"), - _("Extracting tarball succeeded.")); - // remove tarball - std::filesystem::remove(out_path); - } else { - QMessageBox::critical(this, _("Decrypting"), - _("Extracting tarball failed.")); - } - } - } }); }); } diff --git a/src/ui/main_window/MainWindowSlotFunction.cpp b/src/ui/main_window/MainWindowSlotFunction.cpp index 191e80cb..444fe54a 100644 --- a/src/ui/main_window/MainWindowSlotFunction.cpp +++ b/src/ui/main_window/MainWindowSlotFunction.cpp @@ -59,9 +59,9 @@ namespace GpgFrontend::UI { /** * Encrypt Entry(Text & File) */ -void MainWindow::slot_encrypt() { - if (edit_->TabCount() == 0 || edit_->SlotCurPageTextEdit() == nullptr) { - if (edit_->SlotCurPageFileTreeView() != nullptr) this->SlotFileEncrypt(); +void MainWindow::SlotEncrypt() { + if (edit_->SlotCurPageTextEdit() == nullptr) { + // ignore return; } @@ -209,9 +209,8 @@ void MainWindow::slot_sign() { }); } -void MainWindow::slot_decrypt() { - if (edit_->TabCount() == 0 || edit_->SlotCurPageTextEdit() == nullptr) { - if (edit_->SlotCurPageFileTreeView() != nullptr) this->SlotFileDecrypt(); +void MainWindow::SlotDecrypt() { + if (edit_->SlotCurPageTextEdit() == nullptr) { return; } diff --git a/src/ui/main_window/MainWindowUI.cpp b/src/ui/main_window/MainWindowUI.cpp index 9c4e5ceb..0bc00aae 100644 --- a/src/ui/main_window/MainWindowUI.cpp +++ b/src/ui/main_window/MainWindowUI.cpp @@ -32,6 +32,7 @@ #include "core/function/GlobalSettingStation.h" #include "core/function/gpg/GpgAdvancedOperator.h" #include "core/module/ModuleManager.h" +#include "core/utils/IOUtils.h" #include "ui/UserInterfaceUtils.h" #include "ui/dialog/gnupg/GnuPGControllerDialog.h" #include "ui/dialog/help/AboutDialog.h" @@ -183,7 +184,23 @@ void MainWindow::create_actions() { #else #endif encrypt_act_->setToolTip(_("Encrypt Message")); - connect(encrypt_act_, &QAction::triggered, this, &MainWindow::slot_encrypt); + connect(encrypt_act_, &QAction::triggered, this, [this]() { + if (edit_->SlotCurPageFileTreeView() != nullptr) { + const auto* file_tree_view = edit_->SlotCurPageFileTreeView(); + const auto path_qstr = file_tree_view->GetSelected(); + const auto path = ConvertPathByOS(path_qstr); + + const auto file_info = QFileInfo(path); + if (file_info.isFile()) { + this->SlotFileEncrypt(path); + } else if (file_info.isDir()) { + this->SlotDirectoryEncrypt(path); + } + } + if (edit_->SlotCurPageTextEdit() != nullptr) { + this->SlotEncrypt(); + } + }); encrypt_sign_act_ = new QAction(_("Encrypt Sign"), this); encrypt_sign_act_->setIcon(QIcon(":encrypted_signed.png")); @@ -205,7 +222,29 @@ void MainWindow::create_actions() { encrypt_act_->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_E)); #endif decrypt_act_->setToolTip(_("Decrypt Message")); - connect(decrypt_act_, &QAction::triggered, this, &MainWindow::slot_decrypt); + connect(decrypt_act_, &QAction::triggered, this, [this]() { + if (edit_->SlotCurPageFileTreeView() != nullptr) { + const auto* file_tree_view = edit_->SlotCurPageFileTreeView(); + const auto path_qstr = file_tree_view->GetSelected(); + const auto path = ConvertPathByOS(path_qstr); + + const auto file_info = QFileInfo(path); + if (file_info.isFile()) { + const std::string filename = path.filename().string(); + const std::string extension( + std::find(filename.begin(), filename.end(), '.'), filename.end()); + + if (extension == ".tar.gpg" || extension == ".tar.asc") { + this->SlotArchiveDecrypt(path); + } else { + this->SlotFileDecrypt(path); + } + } + } + if (edit_->SlotCurPageTextEdit() != nullptr) { + this->SlotDecrypt(); + } + }); decrypt_verify_act_ = new QAction(_("Decrypt Verify"), this); decrypt_verify_act_->setIcon(QIcon(":decrypted_verified.png")); |