aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsaturneric <[email protected]>2023-12-28 06:32:49 +0000
committersaturneric <[email protected]>2023-12-28 06:32:49 +0000
commit300e55bf5bddc393de050c2ca9a0356fce9a8a9d (patch)
tree8332e6b50158718ad98c954302951668a57712a8
parentfeat: avoid reading entire file to memory (diff)
downloadGpgFrontend-300e55bf5bddc393de050c2ca9a0356fce9a8a9d.tar.gz
GpgFrontend-300e55bf5bddc393de050c2ca9a0356fce9a8a9d.zip
feat: add simple archiving functions for encrypt and decrypt
-rw-r--r--src/core/function/ArchiveFileOperator.cpp310
-rw-r--r--src/core/function/ArchiveFileOperator.h12
-rw-r--r--src/core/function/gpg/GpgFileOpera.cpp91
-rw-r--r--src/core/function/gpg/GpgFileOpera.h24
-rw-r--r--src/core/thread/TaskRunner.cpp8
-rw-r--r--src/core/typedef/CoreTypedef.h7
-rw-r--r--src/core/typedef/GpgTypedef.h10
-rw-r--r--src/core/utils/AsyncUtils.cpp21
-rw-r--r--src/core/utils/AsyncUtils.h20
-rw-r--r--src/core/utils/GpgUtils.cpp63
-rw-r--r--src/core/utils/GpgUtils.h24
-rw-r--r--src/core/utils/IOUtils.cpp38
-rw-r--r--src/core/utils/IOUtils.h20
-rw-r--r--src/ui/function/ArchiveDirectory.cpp85
-rw-r--r--src/ui/function/ArchiveDirectory.h53
-rw-r--r--src/ui/main_window/MainWindow.h21
-rw-r--r--src/ui/main_window/MainWindowFileSlotFunction.cpp435
-rw-r--r--src/ui/main_window/MainWindowSlotFunction.cpp11
-rw-r--r--src/ui/main_window/MainWindowUI.cpp43
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"));